指针值加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. Query 插件为什么要return this.each()

    jQuery.fn.test2= function(){ this.css("background","#ff0");//这里面的this为jquery对象,而 ...

  3. Halcon的应用程序 打开后 弹出没有帮助文件错误提示

    问题: Halcon的应用程序 打开后 弹出没有帮助文件错误提示 解决方法: 建立(C:\ProgramFiles\MVTec\halcon)目录,将halcon安装目录下的help文件夹复制过来即可 ...

  4. 对维数组排序 array_multisort()的应用

    PHP允许在多维数组上执行一些比较复杂的排序--例如,首先对一个嵌套数组使用一个普通的关键字进行排序,然后再根据另一个关键字进行排序.这与使用SQL的ORDER BY语句对多个字段进行排序非常相似.为 ...

  5. Xcode 9.0 新增功能大全

    Xcode是用于为Apple TV,Apple Watch,iPad,iPhone和Mac创建应用程序的完整开发人员工具集.Xcode开发环境采用tvOS SDK,watchOS SDK,iOS SD ...

  6. 【网络流24题】最长k可重线段集(费用流)

    [网络流24题]最长k可重线段集(费用流) 题面 Cogs的数据有问题 Loj 洛谷 题解 这道题和最长k可重区间集没有区别 只不过费用额外计算一下 但是,还是有一点要注意的地方 这里可以是一条垂直的 ...

  7. 推荐一款有趣的APP-种子习惯

    在女朋友的影响下接触到了种子习惯的app,一开始不觉得它有多大魅力,只知道它有契约的功能,有很多人分享自己的习惯,记录生活中的点滴. 毕业回家的寒假,家里比较冷,每天起床都需要莫大的勇气,挣扎半天最终 ...

  8. 面向对象和面向过程,python中的类class,python中程序的入口——main方法,

    1.程序入口,让main显现出来: print(__name__)#__name___是模块中的隐藏字段,当前模块运行的函数名 if __name__ == __main__ __main__() # ...

  9. 关于CoordinatorLayout的用法——复杂交互的克星

    好久没有写博客了,主要还是任务过多哈.在开发的过程当中,也记录了很多东西,但是技术这个事吧,其实,时效性真的事非常强--就比如说,你昨天还津津乐道的一个难点解决方案,你过个几天再回过头去看它,就会有一 ...

  10. Java中的代理模式--静态代理和动态代理本质理解

    代理模式定义:为其他对象提供了一种代理以控制对这个对象的访问. 代理模式的三种角色: Subject抽象主题角色:抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求. Real ...