二.指针和数组
二者区别:
指针就是指针,不是数组
数组就是数组,也不是指针
如何求大小:
指针的大小:4/8个字节,指针是存放地址的,地址的存放需要多大空间,指针变量的大小就是多少
数组的大小:取决数组的元素个数和每个元素的类型
我们看一个例子:
#include <stdio.h> int main() { int arr[10] = {1,2,3,4,5,6,7,8,9,0}; printf("%p\n", arr); printf("%p\n", &arr[0]); return 0; }
可见数组名和数组首元素的地址是一样的。
结论:数组名表示的是数组首元素的地址。(2种情况除外:sizeof(数组名)+&数组名)
那么这样写代码是可行的:
int arr [ 10 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 };
int * p = arr ; //p 存放的是数组首元素的地址
既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。
☑️☑️☑️重点:
#include <stdio.h> int main() { int arr[] = { 1,2,3,4,5,6,7,8,9,0 }; int* p = arr; //指针存放数组首元素的地址 int sz = sizeof(arr) / sizeof(arr[0]); int i = 0; for (i = 0; i < sz; i++) { printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p + i); } return 0; }
运行结果:
💾画图笔记:
循环部分的代码也可以写成:
for (i = 0; i < sz; i++) { printf("%d ", i[arr]); //i[arr] -- *(i+arr) //arr[i] -- *(arr+i) }
💥注意的点:
三者等价:*(arr+i)-->*(p+i)-->arr[i]
不管是写成i[arr]还是arr[i],编译器都会转换成*(arr+i)或者*(i+arr)
所以 p+i 其实计算的是数组 arr 下标为i的地址。
那我们就可以直接通过指针来访问数组。
如下:
1.指针和数组间的联系:
#include<stdio.h> int main() { int arr[10] = { 0 }; int* p = arr; int i = 0; //存放 for (i = 0; i < 10; i++) { *p = i + 1; p++; } //打印 p = arr; for (i = 0; i < 10; i++) { printf("%d ", *(p + i)); } return 0; }
存放的另一种写法:
for(i=0;i<10;i++)
{
*(p+i)=i+1;
}
图解:
上述图解和代码证明了:
1.指针可以指向数组元素的
2.因为指针可以运算,所以借助于指针可以访问数组
2.用指针访问二维数组
int main() { int arr[3][5]; return 0; }
等价的写法: 🚗
arr[i][j] --> (*(arr+i))[j] -->*(*(arr+i)+j)
三.二级指针✅
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
答:二级指针
#include<stdio.h> int main() { int a = 10;//a是要在内存中申请4个字节的空间的 //一级指针 int* pa = &a;//0x0012ff40,pa是变量,用来存放地址,也得向内存申请,申请4/8 //二级指针 int** ppa = &pa;//0x0012ff48 //三级指针 int*** pppa = &ppa; printf("%d\n", **ppa); return 0; }
✅✅注意:最右边的*间隔分开只是为了更好解释它是一个什么样的指针,空格加不加无所谓的
一级指针:
int* pa = &a; --> *表明pa是指针,而int表明pa指向的对象a的类型是int
二级指针:是用来存放一级指针变量的地址
int* * ppa = &pa --> *告诉我们ppa是指针,而int*表明ppa指向的对象pa的类型是int*
如此类推....
可以打开内存监视窗口看一下情况,各个变量的地址和生成的对应指针存放的地址是一样的
画图:
🅿️对于二级指针的运算有:
- *ppa 通过对ppa中的地址进行解引用,这样找到的是 pa ,*ppa 其实访问的就是 pa .
int b = 20;
*ppa = &b;//等价于pa = &b;
- **ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a .
**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;
还有一点:其实在开发的过程中三级指针很少用。
四.指针数组
指针数组是指针还是数组? 答案:是数组。是存放指针的数组。
数组我们已经知道整形数组,字符数组。
int arr1[5];
char arr2 [ 6 ];
🚩1.存放整型指针的数组
#include<stdio.h> int main() { int* p; int a = 10; int b = 20; int c = 30; //指针数组--存放指针的数组 int* arr[] = { &a,&b,&c };// int i = 0; for (i = 0; i < 3; i++) { printf("%d ", *(arr[i])); } char* arr2[5]; float* arr3[5]; return 0; }
执行:
▶️关于这里的知识点总结:
除此之外还有:
char* arr2[5];//存放字符指针数组
float* arr3[5];//存放浮点型指针的数组
...等等数组
2.二级指针数组的应用
int main() { char* arr[5];//{char* char* char* char* char*} char** p = arr;//&arr[0] - char** return 0; }
arr表示首元素的地址也就是&arr[0],我本以为它的类型在监视中是char**,结果是char*[5] -- 上图可知。
反思得:
其实首元素的地址:&arr[0]类型确实是char**,监视的时候是表示的是一个数组,监视的是数组类型而不是数组首元素地址的类型
原因:
监视窗口有自己的规则,这个不必深究
⁉️通过整型指针存放三个一维数组
#include<stdio.h> int main() { // int arr1[] = { 1,2,3,4,5 };//数组arr1内部的元素是连续的,但是arr1,arr2,arr3三者不一定连续 int arr2[] = { 2,3,4,5,6 }; int arr3[] = { 3,4,5,6,7 }; int* ptr[] = { arr1,arr2,arr3}; int i = 0; for (i = 0; i < 3; i++) { int j = 0; for (j = 0; j < 5; j++) { printf("%d ", ptr[i][j]); } printf("\n"); } return 0; }
注意:数组arr1的内部元素是连续的,但是arr1,arr2,arr3三者不一定连续
执行结果:
本章完。欢迎大佬补充