函数,函数,指针,数组,函数指针,指针数组,函数指针数组,指向函数指针的数组的指针以及数组指针这些概念你全都懂了吗?不全懂?
那就赶紧上船吧!
二、干货 1、函数,指针,数组
这一部分相信各位的学校也已经讲的非常清楚了,函数,指针,数组这一块的内容本身并不难。只要注意几个事项就行了,
1、函数的声明,调用,以及实现。函数的类型就是返回值的类型,
2、指针注意当需要的是里面变量的时候时候需要解引用,当需要的是地址的时候直接使用指针变量或者是对所指的变量取地址。弄清楚什么时候应该使用 & 和 * 就基本不会出现太大的错误。
3、数组要注意下标不要越界访问,然后就是一维数组作为参数传参时只需要写数组名。
2、字符数组当一个指针去指向一个字符串的时候,实际上是内存开辟出一段空间去存储了这个字符串,然后定义一个指针变量去指向这个字符串的首字符。
注意:此时的字符串是常量字符串,常量字符串是不能通过指针解引用去改变的。
char* ps = "hello world!"
printf("%sn",*ps);
printf("%c",*ps);
打印结果是
hello world!
h
当你去试图通过*ps='s',这时编译器就会提醒你错误。
3、指针数组arr = {指针};
顾名思义,整形指针就是存放整形数据的指针,整型数组就是存放整形数据的数组,所以,指针数组就是存放指针的数组。那么怎么定义一个指针数组呢?
我们只需要类比整型数组的定义就行
整型数组
int a[5] = {1,2,3,4,5};
int b[5] = {2,3,4,5,6};
指针数组
int* arr[3] = {a,b,NULL};
其实指针数组在内存中的数据的储存就像是一个二维数组,但是并不是二维数组,因为二维数组每一行的数据在内存中的储存是挨着,而指针数组中每个指针的地址是随机的。
4、数组指针根据我们对于指针数组的理解,指针数组是一个存放指针的数组,那么,数组指针就是指向整个数组的指针。
我们都知道数组的数组名是一个地址,可以定义一个指针变量去接受这个地址
int arr[3]={1,2,3};
int (*pa)[3] = &arr; //这个(*pa)如果不加(),pa会优先与[3]结合。
int (*pa) [3] 从左到右分别是
1、指向数组中的元素类型int。2、指针变量pa。3、指向数组元素个数[3]。
所以当我们指向一个指针数组时就如下所示
int*arr[3]={a,b,NULL};
int* (*pa)[3]=&arr ;
我们都知道数组名其实就是数组的首地址,但是我们要搞清楚这个概念,数组指针指向的是数组的地址,是整个数组的地址,而不是首地址。
int arr[3]={1,2,3};
int*pa=arr;
int(*pb)[3]=&arr;
pa=pa+1;
pb=pb+1;
这里我们对两个指针变量进行+1,pa指针移动了4个字节(一个整型数据);pb指针移动了12个字节(arr数组的长度)。
当然说到这里了。就有必要说一下数组名和数组首地址的关系
数组名一般情况下就是数组的首地址但有以下两个例外
5、函数指针1、sizeof(数组名);这里的数组名是整个数组。计算整个数组长度
2、&数组名;这里的数组名也是整个数组。取出整个数组地址
指向函数的指针
数组名是数组的首地址,函数名是这个函数的地址,如下
#define _CRT_SECURE_NO_WARNINGS 1 #includeint Add(int x, int y) { return x + y; } int main() { printf("%pn", Add); printf("%p", &Add); return 0; }
打印的结果是,如下
所以说我们定义一个指针变量pf其接受Add的地址,那么pf与*pf也是一样的也就是说
Add(3,4)
pf(3,4)
*pf(3,4)
得出的结果相同
但是函数指针该怎么定义呢?
类比数组指针就会发现并不难
int (*pf)(int ,int )=&Add
从左到右分别是1、函数返回类型int。2、指针变量pf。3、函数参数类型int,int
因为我们上面也说到了pf(3,4)其实就是直接调用函数Add了,所以我们要用(*pf)防止pf与后面的()结合。
注意易错
6、函数指针数组int (*pf)(int ,int )=&Add 与 int (*pf)(int ,int )=Add 相同
而 int (*pa)[3]=&arr与int (*pa)[3]=arr不相同,而且后者是一个错误写法。
既然函数指针是一个指针,前面也学习了指针数组中这个概念,那么我们就可以把函数指针去放到一个数组中。
#define _CRT_SECURE_NO_WARNINGS 1 #includeint Sub(int x, int y) { return x - y; } int Add(int x, int y) { return x + y; } int main() { int a = 3, b = 4; int(*pfarr[2])(int, int) = { Add,Sub };//定义函数指针数组 printf("%d", (pfarr)[0](a, b));//调用函数 return 0; }
我们可以这样使用,跟上面函数指针和指针数组的概念差不多,但是这里一个函数指针数组只能存放相同返回类型,以及相同参数类型的函数。
此时的打印结果无疑是3+4=7;也就是调用了Add函数。
7、指向函数指针数组的指针《禁止套娃》
这个其实并不会太多见,但是学会了它一是可以装个*,二是可以有效地提高你对这一块知识的理解。所以还是要好好看看。
三、总结我们就借用前面代码段的函数指针数组pfarr[2]
int(*(*p2)[2])(int ,int)=&pfarr;
下面是这篇文章中提到的指针或者数组的定义方法
1、字符指针
int x = 'a';
int pa = &x;
2、指针数组
int a[3] = { 1,2,3 };
int b[3] = { 2,2,3 };
int* arr[3] = { a,b,NULL };
3、数组指针
int arr[3] = { 1,2,3 };
int(*pa)[3] = &arr;
4、函数指针
int (*pf)(int, int) = &Add;
5、函数指针数组
int(*pfarr[2])(int, int) = { Add,Sub };
6、指向函数指针数组的指针
int(*(*p2)[2])(int, int) = &pfarr;
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)