听翁恺老师mooc笔记(6)--指针运算

指针值加1就是将指针值加上sizeof(指针所指变量的类型)

  1+1=2,那么指针加1是加上了1这个数字吗?试一下,在代码中定义了char数组,char也是整数,数组名是ac,ac中有10个元素,0-9,然后做了一个char *p=ac,定义了*p的一个指针,p指向了ac数组的第一个单元。然后分别输出p和p+1的值,结果是差了1:

 1 #include 
 2 
 3 int main(void){
 4     char ac[] = {0,1,2,3,4,5,6,7,8,9};
 5     char *p = ac;
 6     printf("p  =%p\n",p);   //输出p的值
 7     printf("p+1=%p\n",p+1); 
 8 
 9     return 0;
10 }
View Code

听翁恺老师mooc笔记(6)--指针运算_第1张图片

  再对程序进行修改,将char改成int,然后指针变量p改成q,结果显示q和q+1差了4:

 1 #include 
 2 
 3 int main(void){
 4     char ac[] = {0,1,2,3,4,5,6,7,8,9};
 5     char *p = ac;
 6     printf("p  =%p\n",p);   //输出p的值
 7     printf("p+1=%p\n",p+1); 
 8 
 9     int ai[] = {0,1,2,3,4,5,6,7,8,9};
10     int *q = ai;
11     printf("q  =%p\n",q);   //输出p的值
12     printf("q+1=%p\n",q+1); 
13 
14     return 0;
15 }
View Code

听翁恺老师mooc笔记(6)--指针运算_第2张图片

  综合上述两个例子,char为何是加1,而int是为何是差了4那?因为sizeof(char)=1,sizeof(int)=4,所以我们再对指针加1的时候,实际不是再地址值上加1而是在地址值上加sizeof(指针所指变量的类型),为什么?因为char数组,第一个元素的地址是30,大小是1个字节,那么第二个元素的地址就是31,而int数组中1个元素需要占用4个字节,所以第一个元素(0)的地址是00,那么第二个元素的地址是04,第三个元素的地址差不多就是08,相邻单元的地址差了4个,正好和int类型的大小一致。

  q的值是第一个单元的地址,也就是说q指向了第一个单元,那么q+1=04,就是q+1指向了第二个单元。所以对指针做一个加1的东西意味着将它移到下一个单元去,实际的指针值加上的是sizeof变量类型。同学们可以使用这个程序试一下long long,double,short等,测试下是不是加的sizeof。

听翁恺老师mooc笔记(6)--指针运算_第3张图片

  我们在学指针和数组时说过,你拿到指针可以像数组一样操作,也可以拿到数组像指针一样操作,以上述例子为例,*p就相当于是ac[0],那么*(p+1)就相当于是ac[1],这里也可以做实验输出*p,*(p+1)的值都是多少,是否和a[1]的值一样。所以当p指向一个数组时,p+n实际上就是指向了数组n的第n个元素,所以*(p+n)=a[n]。但是如果指针不是指向数组这种一片连续分配的空间时,就这种运算没有意义。

指针的其他加减运算(1)(2)(3)

  除了指针可以加1,还可以给(1)指针加、减一个整数(+,+=,-,-=),减的意思是往前挪一些,加是往后挪。还可以做(2)递增递减(++,--),在以后的运算中经常看到对指针加加减减的运算。还可以的运算是(3)两个指针可以相加或者向减,对这种运算实验下:(给学生详细介绍程序和结果)结果显示p1-p是5,我们可以理解第5个元素减去第0个元素就是5.而q1-q是6,不应该是6*4=24吗?可以再输出q1的地址和q的地址,使用十六进制计算器进行减法是24。所以,q1-q的差值不是地址相减,而是这两个地址的差除以sizeof类型,也就是告诉我们中间差了几个数组单元。

听翁恺老师mooc笔记(6)--指针运算_第4张图片

 *p++运算

  在指针运算中还比较常见的是*p++的运算,*p++有两个运算符,从优先级上来说,++比*的优先级高,但是++是后缀,所以*p++的意思是先*p,然后p++,相当于*(p++)。这个运算常用于数组类的连续空间操作:

 1 #include 
 2 
 3 int main(void){
 4     char ac[] = {0,1,2,3,4,5,6,7,8,9,-1};
 5     char *p = ac;
 6     int i;
 7     for(i=0;i<sizeof(ac)/sizeof(ac[0]);i++){
 8         printf("%d\n",ac[i]);
 9     }
10 
11     while (*p!=-1){
12         printf("%d\n",*p++);
13     }
14     return 0;
15 }
View Code

指针比较运算

  指针比较运算包括<,<=,==,>,>=,!=等等。指针的比较其实就是地址大小的比较,如果一个指针指向a[0],一个指针指向a[5],很明显a[0]要比a[5]的值要小,数组是顺序递增排列的

0地址

  我们现代的操作系统,包括windows,macs,linux,unix等都是多进程的,基本的管理单元是进程,什么叫进程那?双击一个东西,这个东西运行起来就是一个进程,对于进程来说,操作系统会给他一个虚拟的地址空间,所有的进程都以为自己拥有一个从0开始的地址空间,直到4G(32位机器)。所以任何程序里面都有0地址,不是说这个程序使用了0地址,另外一个程序就不可以使用0地址,所有程序都有虚拟的0地址,那么这个虚拟的0地址的物理地址(真实地址)是多少我们不用管,这是操作系统的事。

  每个程序都有0地址,但是0地址通常是个不能随便碰的地址,一般我们使用0地址做一些特殊的事情,比如说你要返回指针,返回0告知你返回的指针是无效的,或者当你有了一个指针变量之后,可以先给他赋上一个0,0表示指针没有被真正初始化,当你对赋值0的指针操作的话,系统肯定会崩溃(可以实验验证下)。

  C语言事先定义了NULL(全部大写)作为预先定义的符号,表示0地址,有些编译器愿意你用0来表示0地址,有些则不愿意那么就可以使用NULL表示0地址。这件事情牵涉的比较深远,这块只做简单说明。

指针类型转换

  一个指针有各种类型,有char,有int等。同一类型的指针,所有的指针的大小都是一样的,因为都是地址。但是不同类型的指针是不能互相赋值的(可以编码验证)。这主要是为了避免用错指针。

  关于指针的类型转换,可以使用void*:

听翁恺老师mooc笔记(6)--指针运算_第5张图片

指针有什么用那?

  (1)需要传入比较大的数据时,可以使用指针作为参数,比如传递数组。

  (2)传入数组后,可以使用指针对数组做操作。

  (3)当函数返回不止一个结果时,可以使用指针做参数让它带出结果。

  (4)当使用函数修改不止一个变量时,比如swap,传指针进去,让函数修改变量的值

  (5)当动态申请的内存时。。。。

你可能感兴趣的:(听翁恺老师mooc笔记(6)--指针运算)