指针值加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. Radar Installation POJ - 1328

    Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. ...

  2. ajax页面跳转(后台返回的是一个url地址,或者自己传进去的是url地址)

    function modifyMerchantInfo(merchant_code) { $.ajax({ url: '/intra/crm/merchant/OrderMgr.htm?method= ...

  3. 第一个bug

    话不多说自己遇到的第一个小程序bug 需要渲染渲染多重元素,这个没什么.but当你要获取这个大样式的id进行各种操作时,你需要每一个子节点都加上data-=""属性这样就很麻烦了, ...

  4. Javascript设计模式(2)-单体模式

    单体模式 1. js最简单的单体模式 对象字面量:把一批有一定关联的方法和属性组织在一起 // 对象字面量 var Singleton = { attr1: true, attr2: 10, meth ...

  5. C#图解教程 第二十五章 其他主题

    其他主题 概述字符串使用 StringBuilder类把字符串解析为数据值关于可空类型的更多内容 为可空类型赋值使用空接合运算符使用可空用户自定义类型 Main 方法文档注释 插入文档注释使用其他XM ...

  6. WebForm 生成并显示二维码

    Generate and display QRCode in WebForm. 项目引用 QRCoder生成并显示 QRCode 项目引用 QRCoder How to use QRCoder Via ...

  7. RSS简介

    1.RSS(Really Simple Syndication)简介 1.定义     对于网站:RSS 是一种使用 XML 向许多其他的网站分发自己网站上的网络内容的方法.     对于用户:RSS ...

  8. ListView添加item的事件监听

    1. 点击事件(OnItemClickListener) onItemClick(AdapterView<?> parent, View view, int position, long ...

  9. MySQL系列-第一章节:MySQL介绍与安装

    1.数据库介绍 1.1.什么是数据库`<Database>` 简单说存放数据的仓库,这个仓库按照一定的数据结构<数据结构是指数据的组织形式或数据之间的联系>来组织.存储的,我们 ...

  10. 一次日语翻译的Chrome插件开发经历

    序言 去年7月刚过了日语N2,想着今年考个N1,为了加深日语文化的了解,还有学习日语,平时免不了经常上日语网站. 但是毕竟水平有限,所以不免遇到不认识的单词,日语单词的一个特点就是很多单词你知道是什么 ...