目录
目录
1:数组和指针
定义:
指针变量就是指针变量,指针变量的大小根据不同的编译环境,要么是8个字节,要么是4个字节,指针变量的作用是专门用来存放地址。
数组就是数组,不是指针,数组的作用是在内存中开辟一段连续的空间,可以用来存放一个或者多个相同性质数据。
联系:
数组名其实是数组元素的地址,数组名<----地址----> 指针 ,所以是可以通过指针来进行访问数组。
1.1:数组名的理解
从编译器中可以得出结论,数组名、数组首元素地址以及数组自身的地址均指向同一个地址,那么这3种有什么区别呢?
但是有两个例外:
1:sizeof(数组名):这里的数组名不是数组首元素的地址,数组表示整个数组,sizeof计算出来的结果是整个数组的大小,单位是字节。
2:&数组名,这里的数组名表示整个数组,通过 & 取地址操作符取出的是整个数组的地址。
我们将上列代码每个地址都+1
为什么会出现这种+1 情况不一致?参考数组指针部分知识。
1.2:使用指针访问数组
1.3:数组传参本质
2:二级指针
3:指针数组
参考整型数组、字符数组等含义,那么指针数组的本质就是数组,只不过里面存放的数据均是指针。
类比:整型数组:存放整型的数组
字符数组:存放字符的数组
指针数组:存放指针的数组
int main() {
int arr1[] = {1,2,3,4,5};
int arr2[] = { 6,3,1,9,10 };
int arr3[] = {24,55,23,11,33};
int* parr[] = { arr1,arr2,arr3 };// parr 是一个指针数组,里面存放的都是指针
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
printf("%d ", parr[i][j]);
}
printf("\n");
}
return 0;
}
4:数组指针
首先,数组指针是指针,接下来类比:
整型指针:(指向角度)指向整型变量的指针,(存储角度)这个指针存放着整型变量的地址。
字符指针:(指向角度)指向字符变量的指针,(存储角度)这个指针存放着字符变量的地址。
数组指针:(指向角度)指向数组的指针,(存储角度)存放的是数组地址的指针变量。
int *p1[10]; ---- > 指针数组 ,因为 [ ]号 优先级 大于 * ,所以 变量p 先跟[ ]结合 -----> p[10],这是一个数组,数组里存放着10个指针或者说地址。
int (*p2)[10]:数组指针,因为 () 号优先级最大,所以括号内的 * 跟 p2 先结合 ----> *p2 , 这是一个指针,然后这个指针指向一个 数组
数组指针剖析:
int (*p1)[100]= & arr;
| | |
| | p1指针指向数组内数据个数
| |
| | p1 是数组指针变量名
|
| p1指向数组内数据类型
#回顾 1.1 里数组名理解中 &arr + 1 这个案列,这个实际上就是数组指针进行+1 操作,然后会跳过整个数组。
数组指针的使用场景:一般在操作二维数组的时候用数组指针比较方便。
二维数组可以看做每个元素都是一个一维数组的数组,所以二维数组内每个元素都是一维数组,对于二维数组来说,首元素其实就是第一行地址。
5:字符指针
常用的字符初始化有两种方式,一种是创建字符数组,还有一种是创建字符指针。
延伸一下,分析接下来这个代码里的区别与联系:
int main() {
char str1[] = "subaru wrx sti";
char str2[] = "subaru wrx sti";
const char* str3 = "22b";
const char* str4 = "22b";
if (str1 == str2) {
printf("str1==str2\n");
}
else {
printf("str1!=str2\n");
}
if (str3 == str4) {
printf("str3==str4\n");
}
else {
printf("str3!=str4\n");
}
return 0;
}
6:函数指针
函数实际上也是有地址的,正如同数组一样,我们也可以通过 & 取地址操作符得到函数的地址。
但是函数地址 跟数组 地址在是否加 & 操作符上还是略有不同。
数组 | 函数 |
数组名:表示数组首元素的地址 | 函数名:函数地址 |
&数组名:表示整个数组的地址 | &函数名:函数地址 |
函数指针的声明形式:
int (*pf)(int x,int y);
| | |
| | |
| | pf 指向 函数的参数 和 个数
| 函数指针变量名,注意一定要用()引起来
| pf这个函数指针指向的函数返回值类型
简易对比一下: