C 对指针数组、数组指针 和 函数指针、函数指针数组、指向函数指针数组的指针的理解
程序员文章站
2024-01-01 17:28:58
...
0.指针和数组的定义与声明(说明指针和数组是不一样的)
①
//text.c
char arr[] = "abcdef"; //在text.c文件中定义数组
//main.c
ertern char *arr; // 调用其他源文件中的参数时要用ertern
int main()
{
printf("%s\n", arr);
return 0;
}
执行后程序崩溃;text.c中的arr[]占用了7个字节,main.c中的arr是个指针,所以只占了四
个字节,而指针中存放的是地址,所以就会误把字符''abcd''当做一个地址,去找这个地址所代
表的空间,然后输出这块空间上的字符串,但由于字符''abcd''所对应的ASCII转换成的地址无
法去访问,所以最后程序访问出错,直接崩掉
若想让输出的结果为正确的,则需要把paintf中的arr改为(char *)&arr,取出arr中的地址,
但因为arr原本就是char *类型的,再加上个&,就变成了char **类型,所以需要强制转换为
char *类型,也就是拿到了a的地址,然后在打印,结果就会是abcdef
②
//text.c
char *p = "abcdef";//在text.c文件中定义指针
//main.c
ertern p[];
int main()
{
printf("%s\n", p);
return 0;
}
执行结果为随机值;text.c中的p存放的是字符串"abcdef"中'a'的地址,占4个字节,
main.c中的p[](未指定大小,所以最多为4个字节)则误把text.c中的这个地址当做字符串,
把没地址分成四份存起来,在printf中的p是首元素地址,也就是前1/4元素的值被转换成字符
形式输出来
若想输出为正确的值,则需要把printf中的p改成(char *)*(int *)p,因为p中存放的是a的
地址的首地址,先把p强制转化为int *形式(取出p中的4个字节)再解引用,得到八位十六进制
数,即为a的地址,因为要打印出字符串,所以要再强制转化为char *类型
或
把p改成*(char **)p,先把p当做是char *类型的,然后对char *类型的p取地址,就是
char **类型,再解引用,因为char **类型解引用取出的是四个字符,正好取到p中a的地址,
所以打印时刚好打出字符串"abcdef"
声明与定义指向的是同一块空间,但因为在链接是只查找参数名,所以链接时不会出现问题
1.指针数组
指针数组强调的是数组,所以它是一个数组,用来存放指针
例如:
①
int* arr[10] 存放整形指针的数组,数组包含10个元素;
②
char* arr[10] 存放字符形指针的数组,数组包含10个元素;
③
char** arr[10] 存放字符型二级指针的数组,数组包含10个元素。
2.数组指针
与上面相反,数组指针强调指针,所以他是个指针,指向一个数组
例如:
①
int arr[10] = {0};
int (*p) [10] = &arr;(因为[]的优先级比*高,所以要给*p加上(),
否则这个表达式就是前面提到的指针数组)
②
void text(int (*p) [5])
{
...
}
int main()
{
int arr[3][5] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
text(arr);
return 0;
}
因为在main函数中传过去的arr是首元素地址,在二维数组中,首元素地址是第一行的地址,第一行则可以看成一个一维数组,数组中包含5个元素,这个数组的地址就是 int (*p) [5]
3.函数指针
指向函数的指针变量
例:
void text()
{
printf("hello world\n");
}
int main()
{
void (*p)() = text;//这里的text与&text作用相同,都表示函数的地址
(*p)();
p();
return 0;
}
从结果可以看出,(*p)()与p()的调用结果是相同的,因为C语言设计者为了方便初学者的理解
,所以可以写成(*p)()的形式,但要注意如果有*,就一定要(),否则就会出现错误,因这样写
最后会把函数的返回值解引用
4.函数指针数组
是一个数组,里面存放许多指向函数的指针
例如:
①
int (*p[10])(int);
[]的优先级高于*,所以p先和[]结合,说明这是一个数组,去掉名称看类型,这是一个函数指针
,所以是函数指针数组;包含函数返回值类型为int,函数参数类型也为int的10个函数指针
②
转移表:
#include <stdio.h>
void menu()
{
printf("*************************\n");
printf("**** 1.Add 2.Sub ****\n");
printf("**** 3.Mul 4.Div ****\n");
printf("**** 0.exit ****\n");
printf("*************************\n");
}
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
int main()
{
int x = 0;
int y = 0;
int ret = 0;
int input = 0;
int(*p[5])(int, int) = { 0, Add, Sub, Mul, Div };
do
{
menu();
printf("please choose:");
scanf("%d", &input);
if ((input >= 1) && (input <= 4))
{
printf("please input two numbers:");
scanf("%d %d", &x, &y);
printf("%d\n", ret = p[input](x, y));
}
} while (input);
return 0;
}
当参数类型与返回类型相同时才可以使用函数指针数组,函数指针数组可以减少代码的数量,
以上代码若不用函数指针数组,用最基本的switch case语句,需要逐条列出来,代码长度
会大幅增加
5.指向函数指针数组的指针
是一个指向数组的指针,数组中的元素都是函数指针
例如(借用函数指针数组的例子):
void (*a)(int, int) = Add;//指向函数Add的指针a;
void (*count[4])(int, int) = { Add, Sub, Mul, Div };
//count为函数指针数组,里面包含的元素为函数指针a,s,m,d;
void (*(*p)[4])(int, int) = &count;//p为指向函数指针数组count的指针;
推荐阅读
-
指向指针数组的指针数组-4个*指针
-
函数指针,该指针指向的函数的返回值是数组,该数组里放的是函数指针,该函数的返回值是数组。。。无限循环。。。
-
php each 返回数组中当前的键值对并将数组指针向前移动一步实例_php实例
-
函数参数传递、数组指针、二级指针、左值、引用
-
C 函数参数传递一级指针和二级指针的区别
-
【C语言】指针数组 _ 数组指针 _ 函数指针 _ 函数指针数组 _ 指向函数指针数组的指针
-
C语言,函数不可返回指向栈内存的指针
-
C 对指针数组、数组指针 和 函数指针、函数指针数组、指向函数指针数组的指针的理解
-
指针,指向指针的指针,指针数组,数组指针,函数指针,函数指针数组
-
C++指向函数的指针