指针第四章、指针例题

o本章我们将用例题来加深对指针的理解,尤其是对首字母地址的理解。在开始之前,需要了解sizeof和strlen

一、sizeof和strlen

sizeof是一个单目操作符,不关心里面储存的内容, 表示变量所占内存空间的大小,单位是字节,如果操作数是类型的话计算的是使用类型创建的变量所占内存空间的大小。其中第二个侧面证明了sizeof不是函数,因为函数的调用需要括号来完成,sizeof后面没有括号仍然能完成调用

但是strlen是C语言的库函数,功能是求字符串的长度。其中strlen的函数原型是这样的:

size_t strlen ( const char * str);

统计的是从首字符str开始后向后,\0之前的字符串中字符的个数。 只针对字符串

由上文可见 arr2的sizeof和strlen不相同,因为双引号会被认为是字符串并且最后一位是\0省略不写,所以sizeof(arr2)=4,加上了省略的字符,但是strlen(arr2)不加\0只计算前面的,结果是3。如果在字符中加入\0,例如arr3,结果又会发生相应的变化,strlen只计算\0前面的,但是sizeof会全部计算在内,sizeof中\0被视为一个字符,所以结果+1.

其次需要注意的是strlen(arr1),arr1的写法意为字符串内容是“ a b c”,没有\0,所以指针在内存空间找到首字符的位置后会继续向后找,哪怕超出范围也要到\0为止,所以是随机值。

strlen和sizeof的区别:

sizeof:

1、sizeof是操作符

2、sizeof计算的是操作数所占内存的大小,单位是字节

3、不关注内存中存放什么数据

4、sizeof内部有表达式,表达式不参与计算

strlen:

1、strlen是库函数,需要包含头文件“string.h

2、strlen求字符串长度,统计\0之前的长度

3、关心内存中是否含有\0,如果没有\0就继续向后寻找,可能会越界

二、题目解析 

1、一维数组

 1.1解析:

(1)、sizeof计算数组的长度,int类型一个占四个字节,四个数据就是16个字节。数组名是数                   组首元素的地址,但是sizeof(数组名)和&(数组名)两个例外,均表示整个数组

(2)、sizeof(数组名)表示整个数组,但是括号里还有+0,所以数组名不表示整个数组,表示                首元素地址,类型是int*,a+0还是首元素地址(a向后走0个元素),指针的大小就是4或8

 (3)、a表示首元素的地址,*a就是首元素(解引用),大小4个字节(*a)等价于a[0]等价于*             (a+0)

(4)、跳过一个整形,第二个元素的地址,4\8

(5)、a[1]表示第二个元素,大小四个字节

(6)、&a表示整个数组的地址,数组的地址也是地址,是地址,大小就是4或者8个字节

(7)、 &a表示整个数组的地址,* &a是对数组的地址解引用,所以是整个数组,结果是16

(8)、&a是数组的地址,&a+1跨过整个数组,不访问后面的空间,但是仍然是后面的地址所以             是4/8;

(9)、首元素地址,大小为4/8字节

(10)、第二个元素的地址,大小为4/8字节

2、字符数组

代码1:

(1)、表示整个数组的大小,6个元素,结果是6

(2)、arr表示首元素的地址,+0还是表示首元素的地址,4/8

(3)、*arr对首元素的地址解引用,也就是表示首元素的占据字节的大小,结果是1;

(4)、arr[1]表示第二个元素,字符串类型占据字节为1

(5)、&arr表示整个数组的地址,4/8;

(6)、&arr+1表示跳过整个数组之后下一个数组的地址,4/8;

(7)、&arr[0]+1跳过首元素,表示第二个元素地址,4/8;

代码2:

(1)、strlen(arr)表示首元素地址,但是arr内部没有\0,所以strlen会在指向最后一个元素之后     继续向后统计,直到遇到\0,因此数值为随机值,也可能会越界访问

(2)、strlen(arr+0)与(1)相同;

(3)、arr表示首元素地址,*arr对首元素地址解引用表示首元素,首元素是字符'a',相当于把a传了过去,a的assci是97,strlen把97当成地址,但是在计算机当中97这个地址不允许被访问,所以走到这里程序就崩了

(4)、同理arr[1]是b,同样被认为传了97给arr导致报错

(5)、与(1)相同,都是把数组地址给strlen,同样为首元素地址,结果是随机值

(6)、&arr+1从f的下一位开始走,结果同样为随机值

(7)、从b的地址开始走,一直向后直到遇到\0,结果为随机值

代码3:

(1)、数组所占字节的大小,但是该数组最后有一个“\0”省略不写,所以要在数量的基础上+1,结果为7

(2)、arr是首元素的地址,arr+0也是首元素的地址,4/8;

(3)、arr首元素表示地址,*arr表示对首元素地址解引用,所以为1;

(4)、 arr[1]第二个元素,大小1个字节

(5)、&arr整个数组的地址,结果为4/8;

(6)、下一个数组的地址,4/8;

(7)、第二个元素的地址,4/8

代码4:

(1)、strlen统计\0之前的字符个数,所以是6

(2)、arr是首元素的地址,arr+0还是首元素地址,所以结果还是6

(3)、arr是首元素地址,*arr对首元素解引用,所以会传a给strlen所以会报错

(4)、与(3)相同arr[1]会把b传给strlen,同样会报错

(5)、&arr是数组的地址,也是从第一个元素向后找,所以正常是6;

(7)、&arr是数组的地址,那么+1就是跨过整个数组,跨过后开始统计,所以是随机值

(8)、&arr[0]是首元素地址,+1从第二个开始统计,所以结果是5

代码5:

(1)、p是指针变量,计算指针变量的大小,所以是4/8

(2)、整个代码是有 "a,b,c,d,e,\0,",其中p指向了a的地址,p+1指向下一个字符的地址,也就是指向了b的地址  

(3)、p的类型是char *,已经是地址,*p是对p的解引用,所以将a传给sizeof,结果是1

(4)、p[0]-->*(p+0)--> *p-->'a',或者把常量字符串想象成数组,把p理解成数组,p[0]理解为数组的首元素

(5)、&p取出的是p的地址,地址的大小是4或者8个字节

(6)、p的类型是char*,那么*p的类型就是char* *, 二级指针,变量类型是char* *,第二个*说明是指针变量,前面的内容char *  说明是指向char*的元素

(7)、p[0]是内容是a,&p[0]是a的地址,a的地址在加一是b的地址,既然是地址的大小结果就是4/8

代码6:

字符串是"a b c d e f \0",p指向a的地址,

(1)、从a开始向后数,长度是6个字符

(2)、从b开始向后数,5个字符

(3)、p是a的地址,*p是对p的解引用,所以是a,strlen(a)无法计算

(4)、p[0],把p想象成数组,p[0]就是首元素a,无法计算

(5)、p是a的地址,&p是p的地址,随机值

(6)、&p是p的地址,&p+1是p的地址+1,同样为随机值

(7)、&p[0]是元素'a'的地址,加一是b的地址,从b的地址向后数,答案是5,字符串在内存空间是连续排列的,所以a地址的后面依次是bcdef \0的地址

3、二维数组 

(1)、数组是int类型的二维数组,一共有12个元素,一个元素4个字节,12个就是48个字节

(2)、a[0][0]是首元素的大小也就是4个字节

(3)、二维数组在本质上就是每一行相连,虽然名称是二维数组,但是实际上是三个一维数组,a[0],a[1],a[2],sizeof(a[0])计算a[0]这个数组的大小,所以一共16个字节

(4)、a[0]没用单独放在sizeof内部,所以是首元素的地址,+1是第二个元素的地址,所以大小是4或者8 

(5)、a[0]+1取的是第二个元素的地址,*(a[0]+1)是对第二个元素解引用,所以是4

(6)、a是第一个元素的地址,也就是二维数组首元素的地址,也就是第一行的地址,+1是第二行的地址,所以大小是4/8

(7)、a表示数组第一行的地址,+1是第二行的地址,*(a+1)是对第二行地址的解引用也就是第二行元素16

(8)、a[0]是第一行,&a[0]是第一行的地址,+1是第二行的地址,所以是4/8

(9)、a[0]是第一行,&a[0]是第一行的地址,+1是第二行的地址,加上*是对第二行的解引用,4个元素,所以一共16个字节

(10)、a是首元素的地址,作为二维数组首元素的地址也就是第一行的地址,所以*a是对第一行地址的解引用,所以是16个字节

(11)、二维数组一共到a[2],但是求a[3],这只是第四行的数组名而已,sizeof不参与计算不访问内部元素,虽然越界,但是不影响计算长度,可以计算类型,int [4]的数组,所以长度是16

4、指针运算笔试题

题目1

 &a指向数字1,&a+1指向5后面的地址,&a的数字类型是int(*)[5],强制类型转换成int *,赋给ptr,ptr指向5后面的地址,a是首元素地址,+1指向2,解引用就是2.。ptr-1指向5的地址,解引用就是5

题目2

 Test是结构体,*p是结构体指针,把0x100000赋给*p,但是0x100000是int类型,强制类型转换成struct Text*变成结构体指针。

p是指针变量16进制的0x1是十进制的1.结构体指针+1跳过结构体,+1相当于加了20

p被强转成unsigned long,不是指针了,无符号指针类型,整形+1就是+1

p被强转成unsigned int,+1相当于+4,变成了00100004

题目3:

这里需要注意的是,a是二维数组,但是(0,1)是逗号表达式,取后面的值,也就是所a里面的变量只有{1,3,5},所以a[0]其实是1. 

题目4:

p是一个数组指针,指向的数组有4个整形元素,然后把a赋给p,a是二维数组。

指针-指针的绝对值是指针之间的元素个数,a[4][2]是第四行第二列的元素。p=a,数组名是首元素的地址,所以a是首元素的地址也就是第一行的地址,也就是把第一行赋给了p,其中a的类型是int (*)[5],p的类型是int (*)[4],但是仍然可以赋给a,p的指针类型决定+1跳四个整形,

 其中a[4][2]在数组中的位置:

p是四行,所以可以把二维数组a等效为:

p[4][2](*(*(p+4)+2))也就是a[3][3],%d相减得到的两个指针之间的元素个数,有符号的整数,需要考虑正负号,所以是-4 

 %p打印地址,不考虑正负号,-4存的补码,由于%p打印地址,而在内存中补码就是地址,所以将-4的补码进行打印

原码:10000000000000000000000000000100

反码:111111111111111111111111111111111011

补码:111111111111111111111111111111111100

题目5:

 &aa+1是跳过整个二维数组得到地址,ptr-1解引用得到10

aa是首元素地址,二维数组首元素地址就是第一行,*(aa+1)得到第二行的数组元素等价于aa[1],aa[1]表示第二行的数组名,数组名又表示首元素的地址,所以是6的地址,ptr2-1表示5的地址,解引用得到5

*(aa+1),等价于aa[1].

题目6:

 a是指针数组,每个元素都是指针,存什么地址呢?存的是work  at   alibaba这三个字符串的地址。a代表了首元素的地址也就是work的地址,赋给pa也就是pa指向了work的地址,pa++指向at的地址,解引用得到地址里面的元素也就是at

(%s打印字符串,从该字符串开始直到\0)

题目7:

题目如图所示:

**++cpp: cpp指向第一个元素,++cpp指向第二个元素,*++cpp得到c+2,*(c+2)得到point

cpp在上面的代码中已经指向第二个元素,继续++指向第三个元素c+1;cpp++表示指向c+1的地址,*(cpp++)表示得到c+1这个元素,所以--*(cpp++)相当于c+1-1得到c,对c解引用得到enter,此时指向e,+3指向e,解引用得到er

cpp[-2]可以等效为 *(cpp-2),这样的值为c+3,*(c+3)结果是first,+3得到st

cpp[-1][-1]等效为*(*(cpp-1)-1),原本cpp指向c+1,*(cpp-1)得到c+2,c+2-1得到c+1,解引用就是new,+1为ew

  • 24
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值