本文目录:
一、二维数组的理解
(1)二维数组array[i]和array[i] [j]的理解
- 二维数组:本质上是以数组作为数组元素的数组,即"数组的数组"。也称为矩阵,行、列数相等时称为方阵。
- array[i]:表示二维数组第 i 行的一维数组的地址(地址、地址、地址)。
- array[i] [j]:表示二维数组第 i 行第 j 列元素的值。
#include <stdio.h>
int main() {
int array[3][4] = {
{
1,2,3,4},
{
5,6,7,8},
{
9,10,11,12},
};
/* 1.array[i]是每一行的数组(一维)的地址 */
int i,j;
for(i=0;i<3;i++){
printf("%p\n",array[i]);
}
/* 2.array[i][j]是每一行数组(一维)的值 */
for(i=0;i<3;i++){
for(j=0;j<4;j++){
printf("%d ",array[i][j]);
}
putchar('\n');
}
return 0;
}
(2)array[i]+j、*array[i]+j的理解
-
array[i]+j:二维数组第 i 行第 j 列的地址
-
*array[i]+j:二维数组第 i 行第 j 列的地址的值
注意:*array[i]+j和*(array[i]+j)写法不同,表示意思相同
#include <stdio.h>
int main() {
int array[3][4] = {
{
1,2,3,4},
{
5,6,7,8},
{
9,10,11,12},
};
/* 1.array[i]+j:二维数组的i行第j列的地址 */
/* 2.*array[i]+j:二维数组第i行第j列的地址的值(元素的值) */
/* PS:*array[i]+j和*(array[i]+j)意思一样(*和+运算符优先级一样,遵循从右往左计算) */
int i,j;
for(i=0;i<3;i++){
for(j=0;j<4;j++){
printf("%d\t",*array[i]+j);
}
putchar('\n');
}
return 0;
}
(3)二维数组名array的理解
在前面一维数组的认知中,我们知道数组名就是数组的首地址,可以通过数组首地址来操作数组元素。同样地,在二维数组中,二维数组名array也表示二维数组的首地址,只是该地址存放的是每一组一维数组的首地址。也就是说,二维数组名是一个存放其一维数组首地址的地址("地址的地址")。所以array[i]也可以写成*(array+i);array[i]+j可以写成(*(array+i))+j;可以理解成以array为基地址,*(array+i)偏移i得到第i行的首地址,(*(array+i))+j再偏移j得到第i行第j列元素的地址;或许有亿点点绕,亿点点晕,继续体会下面的代码吧
- array:二维数组名,是存放其一维数组首地址的地址(二维数组名虽然在理解上有点类似二级指针,但是二维数组名并不同于二级指针)
#include <stdio.h>
int main() {
int array[3][4] = {
{
1,2,3,4},
{
5,6,7,8},
{
9,10,11,12},
};
int i,j;
for(i=0;i<3;i++){
for(j=0;j<4;j++){
printf("%d\t",*array[i]+j); //写法一
printf("%d\t",*(*(array+i))+j); //写法二(输出结果可以看到,两种写法等价)
}
putchar('\n');
}
return 0;
}
二、指针的各种"形态"
(1)数组指针
-
数组指针:指向数组的指针,也就是指向数组首地址的地址。(其实和上面所说的array差不多)
-
int (*p)[4] = array(array是二维数组名):定义一个指向有4个元素的二维数组首地址的指针变量。
(二维数组实质上同一维数组一样,在内存中的地址空间连续,可以通过指针进行操作)
-
根据用户输入的行、列值输出二维数组中的指定行列元素,要求使用数组指针实现。
#include <stdio.h>
void getInput(int *i,int *j){
printf("请输入行、列值(从1开始):");
scanf_s("%d %d",i,j);
printf("input done\n");
}
int findTargetValue(int (*p)[4],int i,int j){
int targetValue;
// targetValue = p[i][j];
targetValue = *(*(p+i))+j;
return targetValue;
}
int main() {
int array[3][4] = {
{
1,2,3,4},
{
5,6,7,8},
{
9,10,11,12},
};
int i,j;
int targetValue;
getInput(&i,&j);
targetValue = findTargetValue(array,i-1,j-1);
printf("矩阵%d行%d列的数据是:%d",i,j,targetValue);
return 0;
}
(2)函数指针
【2-1】函数指针的理解
- 函数指针:指向函数的指针,存放函数的地址的指针变量。
- 定义:int (*p)(const char *format, …);
- 赋值(初始化,使其指向某个函数—函数名也是地址):p = printf;
- 调用:(*p)(“Hello World”);
#include <stdio.h>
int main() {
int (*p)(const char *format, ...) = printf;
(*p)("Hello World\n");
return 0;
}
【2-2】函数指针的应用
- 应用:根据程序运行过程中的不同情况,调用不同的函数(类似于Java中的接口)+
- 例:有两个整数a和b,由用户输入1,2或3,如输入1程序给出a和b中大者,输入2就给出a和b中小者,输入3则求a和b的和。
#include <stdio.h>
#include <stdlib.h>
int getMax(int data1,int data2){
return data1>data2 ? data1:data2;
}
int getMin(int data1,int data2){
return data1<data2 ? data1:data2;
}
int getSum(int data1,int data2){
return (data1+data2);
}
int getCommandAndHandle(int data1,int data2,int (*p)(int, int)){
int choise = 0;
printf("请输入1-取大值、2-取小值、3-求和:\n");
scanf_s("%d",&choise);
switch (choise) {
case 1:
p = getMax;
break;
case 2:
p = getMin;
break;
case 3:
p = getSum;
break;
default:
printf("error\n");
exit(-1);
}
return (*p)(data2,data1);
}
int main() {
int data1 = 10;
int data2 = 20;
int result;
int (*command)(int, int) = NULL;
result = getCommandAndHandle(data1,data2,command);
printf("%d\n",result);
return 0;
}
-
Linux创建线程函数:int pthread_create(pthread_t *th, const pthread_attr_t *attr, void ( func)(void *), void *arg);
和C++ QT的信号与槽的回调函数底层逻辑——函数指针实现。
三、数组、指针和函数的"傻傻分不清楚"
(1)指针数组
-
指针数组:数组元素全为指针类型变量的数组称为指针数组(①是数组;②数组元素是指针)
-
如何定义:一个有4个整型变量元素的指针数组:int *p[4]
区别前面的数组指针int (*p)[4],可以知道优先级[]比*高
(2)函数指针数组
-
函数指针数组:①是数组;②数组元素是指针;③指针指向函数的地址
-
如何定义:int (*p[4])(int,int)
优先级:() > [] > *;到了这里,优先级对理解记忆这些东西显得十分关键
-
例:传入两个数值,分别输出最大值,最小值以及两数的和(函数指针数组)
#include <stdio.h>
int getMax(int data1,int data2){
return data1>data2 ? data1:data2;
}
int getMin(int data1,int data2){
return data1<data2 ? data1:data2;
}
int getSum(int data1,int data2){
return (data1+data2);
}
void getAllResult(int data1,int data2,int (*p[3])(int,int)){
printf("Max Min Sum\n");
for(int i=0;i<3;i++){
printf("%d ",(*p[i])(data1,data2));
}
}
int main() {
//函数指针
//int (*p)(int,int);
//函数指针数组
int (*p[3])(int,int) = {
getMax, getMin, getSum};
getAllResult(88,99,p);
return 0;
}
(3)指针函数
- 指针函数:返回值是指针类型的函数(①是函数;②函数返回值是指针)
- 定义:int *p(int i,int j)
- 根据用户指定的行号,输出给定二维数组(矩阵)的列的元素。
#include <stdio.h>
int *findTargetSubArray(int (*parray)[4],int target){
return (int *)parray+target;
}
int main() {
int array[3][4] = {
{
11,22,33,44},
{
55,66,77,88},
{
99,110,220,330},
};
int targetNumber;
int *subArray;
puts("输入要查询的行号(0-2)");
scanf_s("%d",&targetNumber);
subArray = findTargetSubArray(array,targetNumber);
for (int i = 0; i < 4; i++) {
printf("%d ",*subArray++);
}
}
(4)各种"妖魔鬼怪"的定义(经典笔试题):
- 建议复制到IDE中,练练手
1.定义一个整型数
2.定义一个指向整型数的指针
3.定义一个指向指针的指针,它指向的指针指向一个整型数
4.定义一个有10个整型数的数组
5.定义一个有10个指针的数组,每个指针指向一个整型数
6.定义一个指向有10个整型数的数组的指针
7.定义一个指向指针的指针,被指向的指针指向一个有10个整型数的数组
8.定义一个指向数组的指针,数组中有10个整型指针
9.定义一个指向函数的指针,该函数只有一个整型参数且返回一个整型数
10.定义一个有10个指针的数组,每个数组指向一个函数,该函数只有一个整型参数且返回一个整型数
11.定义一个函数指针,指向的函数有两个整型参数且返回一个函数指针,返回的函数指针指向有一个整型参数且返回整型数的函数
定义一个整型数 int a;
定义一个指向整型数的指针 int *a;
定义一个指向指针的指针,它指向的指针指向一个整型数 int **a;
定义一个有10个整型数的数组 int a[10];
定义一个有10个指针的数组,每个指针指向一个整型数 int *p[10];
定义一个指向有10个整型数的数组的指针 int (*p)[10];
定义一个指向指针的指针,被指向的指针指向一个有10个整型数的数组 int *(*p)[10];(错) / int (**a)[10];(对)
定义一个指向数组的指针,数组中有10个整型指针 int *((*p1)[10]);(我的答案) / int *(*p2)[10];(参考答案)
定义一个指向函数的指针,该函数只有一个整型参数且返回一个整型数 int (*p)(int);
定义一个有10个指针的数组,每个数组指向一个函数,该函数只有一个整型参数且返回一个整型数 int (*p[10])(int);
定义一个函数指针,指向的函数有两个整型参数且返回一个函数指针,返回的函数指针指向有一个整型参数且返回整型数的函数 int(* (*p)(int,int))(int)
- 关于第8题:第8题属实有些不理解,我还是觉得int *(( *p1)[10]);和 int *( *p2)[10];是一样的。希望有大佬解惑!