前言
我本人也在慢慢学习C语言,看的是C Primer Plus这本书,为了激励自己学习下去,所以会慢慢发分享一些学习心得,也当是记录一下吧,以后也好回顾回顾,本人很菜,高手们不要嘲笑,有问题欢迎指点或者交流,当然,我也可能不会......
正文
指针也许是C语言中逻辑性比较强的概念之一,针对这种概念,没啥特别好的办法,只能靠实践的例子去理解。
相关知识简介
指针
指向一个地址的变量。比如
p = &test;
这上面的p就是一个指针变量。
使用指针时如何怎么定义?
int* p = &test;
数组
比如:
int a[3] = {0};
char b[3] = {'a','b','c'};
其中a和b分别是int型数组和char型数组的数组名。
那么为啥要把数组和指针放一起来讲呢?
因为,细节上看,指针和数组‘名’是等价的,注意是数组名,不是数组整体!
指针代表的是指向一个地址的变量,而数组名在一维的情况下就是代表这个数组中首元素的地址
这么想,数组名不就是指向数组首元素地址的指针吗。
可以试试这样写代码得到的结果
int arr[3]={0};
scanf("%d",arr);
printf("%d",*arr);
取址符
我们在使用scanf输入时,结尾往往会带着一个&...,为了告诉电脑,我们把输入的结果放在啥地址,这个&就是取址符号。
当然,如果你填入的本来就是地址,那就不需要取址啦,比如上面的那个arr
取值符
我们在定义指针时,很多人会好奇,这个*是干啥的,所以很多初学者会以为这就是指针哈,其实不然,指针就是指针,它必定是个变量的载体,比如abcdefg......,而*是个符号就是取址符,也叫解引用。取值就是从地址中取得其中的数值或者字符等等,还是看上面最后printf函数,我们输出不是用arr[0],而是使用的*arr。这么一看是不是有点明白了。
指针运算的优先级
上例子!
#include <stdio.h>
void main()
{
int a[2] = {100,200};
int b[2] = {300,400};
int *p1,*p2,*p3;
p1 = p2 = a;
p3 = b;
printf("*p1 = %d, *p2 = %d, *p3 = %d",*p1,*p2,*p3);
putchar('\n');
printf("*p1++ = %d, *++p2 = %d, (*p3)++ = %d",*p1++,*++p2,(*p3)++);
putchar('\n');
printf("*p1 = %d, *p2 = %d, *p3 = %d",*p1,*p2,*p3);
return 0;
}
结果是
通过这个例子,我们可以看出,*p1++代表的完成p1地址取值任务后,p1的地址会加一个单位,这个单位的大小取决于你指向的目标是啥类型,我这里指向整型,所以是4个字节。
而*++p2和上面就是反过来了,地址先自增,在取值。
加上括号后又会改变运算的优先级了,先取值,在取得值的基础上自增1。
从第三次输出我们更加清晰的看出了优先级的关系。
指针表示&数组表示
我们之前也谈到,数组和指针在一些细节上是一样的,那么我们是不是可以把数组用指针表示或者把指针用数组表示呢。答案是可以的
int a[2] = {100,200};
int *p1;
p1 = a;
//求a的首元素
printf("%d",a[0]);
putchar('\n');
printf("%d",*p1);
putchar('\n');
printf("%d",p1[0]);
putchar('\n');
//求a的第二个元素
printf("%d",a[1]);
putchar('\n');
printf("%d",*(p1 + 1));
putchar('\n');
printf("%d",p1[1]);
putchar('\n');
大家可以运行一下试试,求了数组中的两个元素,都用了三种求法,你会发现,三种表示的值是一样的哈。
第一种是常见的数组取值,就不解释了;
第二种就是用数组名指向首元素的地址的原理进行取值,值得研究的是求第二个元素,我们之前也说过,p1 + 1代表地址加一个单位,这里是整形,所以是4个字节,地址从首元素到了第二个元素,再取值,得到了数组中第二个元素的值。
第三种,更好的体现了指针和数组的关系,既然我们把p1指向了数组首地址了,a也是数组首地址,那么p1和a又有什么区别呢,好像没区别了,那么a能进行的操作,我p1为啥不行呢?
好好体会一下哈。是不是挺有意思的!
指针与字符串
字符串与指针也是一对小伙伴,他俩经常一起出现
比如:
char *mesg = "you are a genius!";
我也觉得很奇怪,为啥还能这么操作,按理来说右边不应该是个地址吗........
后来,我不断的调试,查看存放地址,我得出一个猜想......
后面的字符串在计算机内肯定是存放在固定的地址的,我们这么写,只是把mesg指向了这个地址的首部。
所以,原理上,mesg还是指向了地址。
所以很多人就好奇了,我写个二维数组去放字符串和这样写有啥区别呢?
答案是:节省内存!
因为,这个字符串本身就占一些地址,如果我们再写一个数组,那有需要划出一部分内存,然后把字符串的内容复制进去,这无疑是浪费了内存。
然而,我使用指针去指向这个字符串地址,无疑是减少了内存的使用了。
指针和多维数组 & 指向指针的指针
指针不仅和一维数组有关系,和多维数组也是有关系的。
int b[2][2] = { {300,400},
{500,600}
};
int **p3;
p3 = b;
//求b的2行1列的元素
printf("%d",b[1][0]);
putchar('\n');
printf("%d",*(p3 + 1)) ;
putchar('\n');
b是一个二维数组,所以我们这里需要定义的p3是一个指向指针的指针。
这里b的数组名不在是简单指向第一个元素了,而是指向了,二维数组中的第一维,也就是300和400这一维,那么p3 + 1,就从第一维指向了第二维,再取值,就取得了第二维第一个元素的地址。
但是这种指向指针的指针办法来求多维数组有点缺陷,就是求第二列的元素值不太方便,我还没找到方法,大家有好的方法可以指点指点我呀。
那么我是用哪种方法求第二列的元素呢?
第一种方法最简单,不用设置指针,直接*(*b + 1);
第二种方式是,可以采用数组指针的办法,下面开始讲!
数组指针与指针数组
我们需要先搞明白,这两个东西究竟是指针,还是数组,虽然前面我们谈过指针和数组再某些细节上是一样的,但是既然设计出来了,我们从客观上还是要加以区别的。
结论是:
数组指针==>指针
指针数组==>数组
数组指针是个指向数组的指针,而指针数组是一个包含了很多指针元素的数组!
我们这里主要来看看数组指针!
int b[2][2] = { {300,400},
{500,600}
};
int (*p4)[2] = b;
这个p4就是数组指针,指向了b数组,我们使用数组指针时候需要注意的是指向的数组每个维度里面的变量数目必须是要和自己本身设计[.]相符合,否则是会出错的。
这种情况下,p4和b基本可以说是等价了,b能干的事情,p4也是可以做的!
指针数组本人暂时用的不是很多,常见的就是在数组里面输入字符串,其他的还没见过呢.....以后碰到实际应用了,有机会再谈谈!
总结
数组和指针可以说是C中比较难的一部分了,尤其高维数组使用指针很容易出错,只有勤加练习,多多回顾,处理起来才能游刃有余!
以上就是我对数组和指针一些看法,有叙述错误或者不到位的地方欢迎大家批评指正,有问题大家也可以提出,我看到都会回复的。
以上的例子出自C Primer Plus这本书,这书写的蛮不错的,大家自学的话有兴趣可以看看!