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

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

 #include <stdio.h>

 int main(void){
char ac[] = {,,,,,,,,,};
char *p = ac;
printf("p =%p\n",p); //输出p的值
printf("p+1=%p\n",p+); return ;
}

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

 #include <stdio.h>

 int main(void){
char ac[] = {,,,,,,,,,};
char *p = ac;
printf("p =%p\n",p); //输出p的值
printf("p+1=%p\n",p+); int ai[] = {,,,,,,,,,};
int *q = ai;
printf("q =%p\n",q); //输出p的值
printf("q+1=%p\n",q+); return ;
}

  综合上述两个例子,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。

  我们在学指针和数组时说过,你拿到指针可以像数组一样操作,也可以拿到数组像指针一样操作,以上述例子为例,*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类型,也就是告诉我们中间差了几个数组单元。

 *p++运算

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

 #include <stdio.h>

 int main(void){
char ac[] = {,,,,,,,,,,-};
char *p = ac;
int i;
for(i=;i<sizeof(ac)/sizeof(ac[]);i++){
printf("%d\n",ac[i]);
} while (*p!=-){
printf("%d\n",*p++);
}
return ;
}

指针比较运算

  指针比较运算包括<,<=,==,>,>=,!=等等。指针的比较其实就是地址大小的比较,如果一个指针指向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*:

指针有什么用那?

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

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

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

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

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

听翁恺老师mooc笔记(6)--指针运算的更多相关文章

  1. 听翁恺老师mooc笔记(5)--指针与数组

    如果我们通过函数的参数将一个数组传递到参数中去,那么在函数里接收到的是什么东西呢?我们知道如果传递一个普通变量,那么参数接收到的是值,如果传递一个指针变量,参数接收到的也是值,只不过这时的值是地址.那 ...

  2. 听翁恺老师mooc笔记(4)--指针的应用场景

    指针应用场景一:交换两个变量的值 在学习函数时,交换两个数的值,做一个swap函数,传递值进去,也可以将两个值交换过来,没问题,可是离开swap就没有用了,为什么?因为传进去的是两个值. #inclu ...

  3. 听翁恺老师mooc笔记(3)--指针的定义

    在上一个blog学习了&运算符,使用&取了变量.数组等地址,有什么用那?如果能够将取得的变量的地址传递给函数,能否通过这个地址在函数内访问到外部这个变量?答案是肯定的,scanf(&q ...

  4. 听翁恺老师mooc笔记(16)--程序设计与C语言

    问题1:计算机遍布生活的各个方面,若你需要一个功能可以下载APP,我们需要的大部分功能都可以找到对应的APP,如果没有可以自己写一个软件,但是很少人需要这么做,那么我们为什么学习计算机编程语言? 学习 ...

  5. 听翁恺老师mooc笔记(12)--结构中的结构

    结构数组: 和C语言中的int,double一样,一旦我们做出一个结构类型,就可以定义这个结构类型的变量,也可以定义这个结构类型的数组.比如下面这个例子: struct date dates[100] ...

  6. 听翁恺老师mooc笔记(11)--结构和函数

    结构作为函数参数: 声明了一个结构就有了一种自定义的数据类型,这个数据类型和int.float.double一样,int等基本类型可以作为函数的参数,那么这种个自定义的结构类型也应该可以作为函数参数, ...

  7. 听翁恺老师mooc笔记(10)--结构

    定义结构: 在程序里,如果想要表达一个数据就需要一个变量,而每个变量又都需要一个类型,之前学过C语言中有int.double.float.char等这些基础类型,还有指针.数组等.如果你要表达的数据比 ...

  8. 听翁恺老师mooc笔记(8)--字符串2

    字符串的赋值 字符串的输入与输出 对C语言的基础类型,比如int.double等类型,scanf.printf有专门的格式转换,而对字符串,scanf.printf使用%s格式字符进行输入与输出.当使 ...

  9. 听翁恺老师mooc笔记(7)--字符串1

    C语言中字符串的定义 如果定义一个字符数组word,并使用大括号对其初始化,如下图所示: 但是这个不是C语言的字符串,只是字符数组,不是字符串,因为不能使用字符串的方式进行计算.那么C语言的字符串长什 ...

随机推荐

  1. vue常用的网址

    http://cn.vuejs.org/v2/guide/routing.html#官方路由 https://unpkg.com/vue-router@2.3.1/dist/vue-router.js

  2. T470p VS 2017 上运行 VS 2015 + Qt 5.6.2 + GLSL 400

    vs 2017 的qt设置可以按照这篇文章 注意,必须使用qt的安装程序进行安装,否则会出现意想不到的问题(不要简单地把qt的文件拷贝过来..血的教训) 显卡的问题 好不容易编译通过了,一运行报了一个 ...

  3. SonarQube和Maven的集成

    1.1. SonarQube简介 SonarQube是一款免费用于代码质量管理的开源平台,用于管理源代码的质量,可以从七个维度检测代码质量通过插件形式,可以支持包括java,C#,C/C++,PL/S ...

  4. 使用myeclipse出现中文乱码的情况以及解决办法

    一:在jsp页面使用中文在浏览器中显示的时候出现乱码,解决问题的办法: 1)直接在<mete>标签中修改charset属性为"utf-8"或者为"gb2312 ...

  5. Struts2【OGNL、valueStack】就是这么简单

    什么是OGNL表达式? OGNL是Object Graphic Navigation Language 是操作对象属性的开源表达式. Struts2框架使用OGNL作为默认的表达式语言. 为什么我们学 ...

  6. [MyBatis]DAO层只写接口,不用写实现类

    团队开发一个项目,由老大架了一个框架,遇到了DAO层不用写接口了,我也是用了2次才记住这个事的,因为自己一直都是习惯于写DAO层的实现类,所以,习惯性的还是写了个实现类.于是遇到错误了. 找不到那个方 ...

  7. 【Luogu1337】平衡点(模拟退火)

    [Luogu1337]平衡点(模拟退火) 题面 洛谷 题解 和BZOJ3680吊打XXX是一样的.. 但是数据很强呀.. 疯狂调参 各种WA... 很无奈呀.... #include<iostr ...

  8. 关于一道面试题【字符串 '1 + (5 - 2) * 3',怎么算出结果为10,'eval'除外】

    最近徘徊在找工作和继续留任的纠结之中,在朋友的怂恿下去参加了一次面试,最后一道题目是: 写一个函数,输入一个字符串的运算式,返回计算之后的结果.例如这样的: '1 + (5 - 2) * 3',计算出 ...

  9. 利用CDLinux里面的水滴破解路由器密码的教程

    工具: 1.CDLinux系统镜像(网上有很多,这里我提供一个我使用的:http://yunpan.cn/cFgIifL8s6zUF 访问密码 a0ef) 2.U盘一个,不需要很大.(可以使用虚拟机安 ...

  10. python爬微信公众号前10篇历史文章(4)-正则表达式RegularExpressionPattern

    正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串.将匹配的子串替换或者从某个串中取出符合某个条件的子串等. Pytho ...