听翁恺老师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:
#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)--指针运算的更多相关文章
- 听翁恺老师mooc笔记(5)--指针与数组
如果我们通过函数的参数将一个数组传递到参数中去,那么在函数里接收到的是什么东西呢?我们知道如果传递一个普通变量,那么参数接收到的是值,如果传递一个指针变量,参数接收到的也是值,只不过这时的值是地址.那 ...
- 听翁恺老师mooc笔记(4)--指针的应用场景
指针应用场景一:交换两个变量的值 在学习函数时,交换两个数的值,做一个swap函数,传递值进去,也可以将两个值交换过来,没问题,可是离开swap就没有用了,为什么?因为传进去的是两个值. #inclu ...
- 听翁恺老师mooc笔记(3)--指针的定义
在上一个blog学习了&运算符,使用&取了变量.数组等地址,有什么用那?如果能够将取得的变量的地址传递给函数,能否通过这个地址在函数内访问到外部这个变量?答案是肯定的,scanf(&q ...
- 听翁恺老师mooc笔记(16)--程序设计与C语言
问题1:计算机遍布生活的各个方面,若你需要一个功能可以下载APP,我们需要的大部分功能都可以找到对应的APP,如果没有可以自己写一个软件,但是很少人需要这么做,那么我们为什么学习计算机编程语言? 学习 ...
- 听翁恺老师mooc笔记(12)--结构中的结构
结构数组: 和C语言中的int,double一样,一旦我们做出一个结构类型,就可以定义这个结构类型的变量,也可以定义这个结构类型的数组.比如下面这个例子: struct date dates[100] ...
- 听翁恺老师mooc笔记(11)--结构和函数
结构作为函数参数: 声明了一个结构就有了一种自定义的数据类型,这个数据类型和int.float.double一样,int等基本类型可以作为函数的参数,那么这种个自定义的结构类型也应该可以作为函数参数, ...
- 听翁恺老师mooc笔记(10)--结构
定义结构: 在程序里,如果想要表达一个数据就需要一个变量,而每个变量又都需要一个类型,之前学过C语言中有int.double.float.char等这些基础类型,还有指针.数组等.如果你要表达的数据比 ...
- 听翁恺老师mooc笔记(8)--字符串2
字符串的赋值 字符串的输入与输出 对C语言的基础类型,比如int.double等类型,scanf.printf有专门的格式转换,而对字符串,scanf.printf使用%s格式字符进行输入与输出.当使 ...
- 听翁恺老师mooc笔记(7)--字符串1
C语言中字符串的定义 如果定义一个字符数组word,并使用大括号对其初始化,如下图所示: 但是这个不是C语言的字符串,只是字符数组,不是字符串,因为不能使用字符串的方式进行计算.那么C语言的字符串长什 ...
随机推荐
- 决策树系列(三)——ID3
预备知识:决策树 初识ID3 回顾决策树的基本知识,其构建过程主要有下述三个重要的问题: (1)数据是怎么分裂的 (2)如何选择分类的属性 (3)什么时候停止分裂 从上述三个问题出发,以实际的例子对I ...
- Java sax、dom、pull解析xml
-------------------------------------SAX解析xml---------------------------------- >Sax定义 SAX是一个解析速度 ...
- 【BZOJ3130】费用流(最大流,二分)
[BZOJ3130]费用流(最大流,二分) 题面 Description Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识. 最大流问题:给定一张有向图表示运输网络,一个源点S和一 ...
- eclipse 启动报内存溢出的问题out of memory!
这个问题困扰了我一个月,今天终于解决了,在网上尝试了好多方法都不行.启动的时候就报错,这里可能是jdk的内存太小了,需要加大jdk的内存. 加上这个就好了 -server -Xms512m -Xmx5 ...
- Spring入门看这一篇就够了
前言 前面已经学习了Struts2和Hibernate框架了.接下来学习的是Spring框架...本博文主要是引入Spring框架... Spring介绍 Spring诞生: 创建Spring的目的就 ...
- data数据不一致的问题
经常会遇到that.data能打印出来(能访问到),而that.data.xxx不能打印(为空)的情况.特别是在调用了云方法,然后setData的时候,为什么会出现这样的情况不明. 解决方法,将需要用 ...
- 弹框modal, 获取id与绑定id
var span2 = '<span class="replaceBlue cursor" data-target="#myModalMember" da ...
- 毫秒级检测!你见过带GPU的树莓派吗?
树莓派3B+英特尔神经计算棒进行高速目标检测 转载请注明作者梦里茶 代码: 训练数据预处理: https://gist.github.com/ahangchen/ae1b7562c1f93fdad1d ...
- Django 2.0 学习(04):Django数据库
数据库设置/配置 打开mysite/settings.py,我们会发现Django是用的是默认的数据库SQLite,如下图所示: Django也是支持其它数据库的,比如PostgreSQL.MySQL ...
- python 检测nginx状态,若无法访问发邮件通知
应用场景:用来检测网站可用性,访问失败,则发邮件通知 #!/usr/bin/env python import urllib2,time,smtplib,string,logging from con ...