指针进阶(一)
参考文献:《c技能树》(https://edu.csdn.net/skill/c/c-fa927c0947f3427aafee3415e11694e7?category=115&typeId=18326)
指针数组
概念
指针数组重在数组,意为存放指针的数组,其本质上是一个数组,里面的元素类型为指针
指针数组的的形式
指针数组的形式其实就是数组的形式,数组的元素类型+数组名+数组的元素个数
例如:
int a=0;
int b=0;
int* arr[2]={&a,&b};//这里的int*代表了数组元素的类型是整形指针类型
用法:
用来模拟列数不同的二维数组。我们可以通过将不同元素个数的一维数组放在同个指针数组中人为构造一个列数不同的二维数组。用此方法构建的二维数组和二维数组有着本质上的差异,二维数组在内存上是连续存放的,通过指针数组模拟的二维数组在内存上不是连续的
数组指针
概念
数组指针重在数组,意为指向某个数组的指针,其本质上是一个指针类型
表现形式
数组指针和指针数组很相似,他们的表现形似主要区别于数组名和谁先结合了。数组名和下标引用符相先结合那么它的本质上是数组,数组名和解引用符号现结合那么它本质上是指针。
例如:
int arr[3]={1,2,3};
int (*parr)[3]=&arr;//这里的[3],代表的是该指针指向的数组有3个元素
区分”&数组名“与”数组名“
在学习c语言的时候我时常会将这两个概念搞混淆
先说结论数组名不等于&数组名
通过测试我们发现&arr和arr取得的地址是一样的,那是不是代表着他两就是等价的呢?答案是否定的。arr和&arr所代表的类型是不一样。在表达式中arr代表的永远都是数组的首元素地址,而&arr代表的是得到整数组的地址。很明显,两者的类型是不一样的,数组的地址需要用数组指针来指向,元素的地址需要用该元素的类型的指针来指向。即**arr的类型是int*, &arr的类型是int(*parr)[10] **
此外我们发现arr虽然是指向首元素的”指针“,但其在作为左值时无法被改变。事实上arr根本称不上指针变量,因为在内存中根本没有为其开辟空间所以在&arr地址时其实还是指向的数组的第一个元素。arr可以作为指针常量(int * const arr),即该指针指向的内容可以被改变,但该指针变量无法被改变
从本质上来讲数组名是一种数据结构,然而在表达式或作为参数传递给函数时数组名会退化为指针常数来使用
指针传参
类型要匹配
无论什么 指针在进行传参的时候最重要的就是注意类型匹配,形参是什么类型实参就要是什么类型,反之亦然
函数已经设计好时,怎样传入参数
-
传入一个地址
-
传入一个指针变量
函数指针
概念
函数指针也是指针,是指向函数的指针,函数在内存上开辟空间则可通过地址来访问
如何得到函数的地址?
取地址函数名就能得到函数的地址,此外函数名本身就是函数的地址
例如:
”函数名“与”&函数名“
刚刚已经了解到数组名和&数组名是有本质上的差异性的,那么函数名和&函数名等价吗?答案时肯定的,函数名和&函数名从本质上来讲是一样的
函数名被使用时总是由编译器将它转换为该函数类型的函数指针, 比如 print 的类型就是 void () (int) 所以可以用 print 初始化 funptr. 当使用 & 时只是显示的说明了编译器的转换操作, 所以 print 与 &print 都是 void () (int) 类型.
函数指针的形式
函数返回类型+(*指针变量名)+(函数参数类型)
例如:
void text(int* p)
{
printf("66\n");
}
int main()
{
int a = 0;
int* p = &a;
void (*ps)(int*) = &text;//函数指针
return 0;
}
通过函数指针来调用函数
-
通过解引用来调用函数
对指针变量解引用访问其所指向的函数,任何然后传参调用,在解引用调用函数时一定要将解引用符号和指针变量括在一起,不然指针变量在这里就会优先和后面结合
-
直接通过指针变量来调用函数
直接原因是函数名等价于&函数名,因此可以直接使用
函数指针作为函数的返回类型
函数指针作为函数返回类型时需注意*需要和函数名相结合
例如: