开发者学堂课程【你的第一门 C 语言课:指向指针的指针】学习笔记,与课程紧密联系,让用户快速学习知识
课程地址:https://developer.aliyun.com/learning/course/444/detail/5477
指向指针的指针
内容介绍:
一、指向数组和指向指针的指针
二、数组指针和二维数组
一、 指向数组和指向指针的指针
其实只要懂得了指针的概念,指向指针的指针也可以轻松掌握了。
案例:
#include
int main( )
{
Int num=52
0;
//p 是定义的指向整型变量的指针,p 中存放的是 num 这个整型变量的地址
对 p 进行解引用就是 num 地址存放的值520
int *p = #
//pp 就是指向指针的指针了,存放的 p 的地址,就是指向指针的指针的地址也就是 num 的地址,需要进行两层解引用,相当于对 p 进行一层解引用,读取到 num 的值也就是520。其实 C 语言在定义的时候就已经交代了如何对它进行解引用了。
int **pp = &p;
...
return 0;
}
实践案例:
#include
int main( )
{
//定义三个int变量
Int num=520;
Int *p=#
int **pp = &p;
//定义指针变量 p 的值
//打印出 num 值
printf("num: %d\n", num) ;
//打印出对 p 一层解引用的值
printf("*p: %d\n",*p);
//打印出对p二层解引用的值
printf("**p: %d\n", **pp) ;
//打印地址,进行二重验证
//如果前面三个是一样的,那说明没问题,得到的都是 num 的值。
printf("&p: %p,pp: %p\n"&p,pp) ;
//首先打印 p 指针的地址,打印 pp 存在的值,验证 pp 存在的值是否是 p 的地址。
printf("&num:%p,p: %p,*pp: %p\n", &num, p, *pp);
return 0;
}
运行: gcc test1.c && ./a. out
结果:
num: 520
*p: 520
**p: 520
&p: 0xbfea9384, pp: 0xbfea9384
&num: 0xbfea9388 p: 0xbfea938 8, *pp : 0xbfea9388
结论: pp 中存放的确实是 p 的地址,num 的地址在存放在 pp 进行一层解引用得到 p 的值520,也就是 num 的地址。
虽然指针可以无限的指向下,但是不建议,因为代码不好观察
二、指向数组和指向指针的指针案例:
#incLude
int main( )
{
//定义指针数组存放经典书籍
char *cBooks[ ] = {
”《C程序设计语言》",
“《C专家编程》”,
“《C和指针》”,
“《C陷阱与缺陷》”,
“《C Primer PLus 》“,
”《带你学C带你飞》"
};
//定义鱼 c 工作室编著的
char **byFishC;
//存放另外4本书
char **jiayuLoves[4];
int i;
//赋值第六的元素,对 cBooks 进行取址就取第一个元素的地址,事实上就是一个指向指针的指针。
byFishC = &cBooks[5];
//分别用 jiayuLoves 数组对 cBooks 进行取值,数组中存放的就是指向指针的指针。然后进行赋值。
jiayuLoves[0] = &cBooks [0];
jiayuLoves[1] = &cBooks[1] ;
jiayuLoves[2] = &cBooks[2];
jiayuLoves[3] = &cBooks[3] ;
//打印结果,查看是否一样
printf("FishC出版的图书有: %s\n",*byFishC) ;
printf("小甲鱼喜欢的图书有: \n");
//for循环进行打印*jiayuLoves [i]中所有数据
for(i=0;i<4;i++)
{
printf("%s\n", *jiayuLoves [i]) ;
}
return 0;
}
运行: gcc test2.c && ./a. out
结果:
FishC出版的图书有:《带你学C带你飞》
小甲鱼喜欢的图书有:
《C程序设计语言》
《C专家编程》
《C和指针)
《C陷阱与缺陷》
结论:可以看到有两个好处
- 避免重复分配内存,不会对内存进行浪费
- 只需要进行一处修改
效果:
- 代码的灵活性和安全性都有了显著地提高!
三、数组指针和二维数组
C 语言的指针是非常灵活的,让人越学越就觉得深不可测,同样的代码,用不同的角度去切入就有不同的理解,不同的应用结果,数组指针同样可以访问二维数组
指针和数组有密不可分的关系
实践案例:
#include
int main( )
{
int array[10] = {0, 1, 2, 3,4,5,6,7,8,9};
int *p = array;
int i;
for(i=0;i<10;i++)
{
printf("%d\n", *(p + i));]
}
return 0 ;
}
运行: gcc test3.c && ./a. out
结果:
0
1
2
3
4
5
6
7
8
9
结论: 通过指针对一维数组进行索引是没有问题的
修改代码为二维数组
#include
int main( )
{
//二维数组
int array[3][4] = {
{0,1,2,3},
{4,5,6,7},
{8,9,10,11}};
//二维数组就用指向指针的指针
int (*p)[41] = array ;
int i,j;
//双重循环进行打印输出
for(i=0;i<3;i++)
{
for(j=0;j<4;j++){
//两层解引用
printf("%2d”,*(*(p+i)+j));
}
//换行符
printf("\n");
}
return 0;
}
运行: gcc test3.c && ./a. o
ut
结果报错:
test3. c: In function . ‘main ‘
test3.c:9: warning :initialization Fromincompatible pointer type
Segmentation f ault
运行报错进行修改代码:
#include
int main( )
{
//二维数组
int array[3][4] = {
{0,1,2,3},
{4,5,6,7},
{8,9,10,11}};
//二维数组就用指向指针的指针
//int (*p)[41] = array ;
int i,j;
//双重循环进行打印输出
for(i=0;i<3;i++)
{
for(j=0;j<4;j++){
//两层解引用
printf("%2d”,*(*(array+i)+j));
}
//换行符
printf("\n");
}
return 0;
}
注释代码并把 p 改为 array 进行输出
运行: gcc test3.c && ./a. out
结果:
0 1 2 3
4 5 6 7
8 9 10 11
再次修改代码:
#include
int main( )
{
//二维数组
int array[3][4] = {
{0,1,2,3},
{4,5,6,7},
{8,9,10,11}};
//二维数组就用指向指针的指针
//使用数组指针
int (*p)[4] = array ;
int i,j;
//双重循环进行打印输出
for(i=0;i<3;i++)
{
for(j=0;j<4;j++){
//两层解引用
printf("%2d”,*(*(p+i)+j));
}
//换行符
printf("\n");
}
return 0;
}
运行: gcc test4.c && ./a. out
结果:
0 1 2 3
4 5 6 7
8 9 10 11
结论:
p 仍然指向一个二维数组,把二维数组第一个元素的首地址赋值给 p,p+1就能得到二维数组的第二行的地址,通过 for 循环就能获得二维数组所有的值,所有可以通过数组指针的方式来访问二维数组,利用跨度一样来实现。可以互相解引用