目录
1. sizeof和strlen的对比
1.1 sizeof
我们在做指针习题前,再次认识下sizeof()和strlen,很多人分不清,其实这两区别特别大,sizeof 计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。
sizeof 只关注占用内存空间的大小,不在乎内存中存放什么数据。
1.2 strlen
strlen 是C语言库函数,功能是求字符串长度。函数原型如下:
统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。
strlen 函数会一直向后找 \0 字符,直到找到为止,所以可能存在越界查找。
1.3 sizeof和strlen的对比
2. 数组和指针笔试题解析
2.1 一维数组
这里面元素都是int类型,一个元素大小4个字节
我们先看第一个,sizeof(a)代表什么意思那,a是数组名在sizeof里只有一个数组名,此时a代表整个元素,一个元素大小是4,则整个元素的大小就是16个字节
sizeof(a+0)此时不仅仅是数组名一个单独在sizeof里,所以这里的a代表数组首元素的地址,那首元素地址加0还是首元素地址,所以此时sizeof里是个地址,大小为4或8个字节
sizeof(*a)此时不仅仅是数组名一个单独在sizeof里,所以这里的a代表数组首元素的地址,那首元素地址解引用,所以此时sizeof里是第一个元素的大小,大小为4个字节
sizeof(a+1)此时不仅仅是数组名一个单独在sizeof里,所以这里的a代表数组首元素的地址,那首元素地址加1,所以此时sizeof里是第2个元素的地址,大小为4或8个字节
sizeof(a[1])此时不仅仅是数组名一个单独在sizeof里,所以这里的a代表数组首元素的地址,那首元素地址后面跟个数组括号,里面有个1,所以此时sizeof里是第2个元素的大小,大小为4个字节
sizeof(&a)此时不仅仅是数组名一个单独在sizeof里,但是别忘了还有一个结论,&后跟数组名代表取整个数组的地址,那整个数组的地址也是地址呀,所以此时sizeof里是地址大小,大小为4或8个字节
sizeof(*&a)&后跟数组名代表取整个数组的地址,但前面那个*解引用号把地址又解引用了,相当于此时此刻只有一个数组名在sizeof里,那此刻数组名就代表整个数组的大小,所以大小为16个字节
sizeof(&a+1)&后跟数组名代表取整个数组的地址,所以这里取整个数组的地址,那&a+1相当于跳了一个数组大小的地址,所以此时sizeof里是地址的大小,大小为4或8个字节
sizeof(&a[0])此时&后跟数组名,但是这里[]优先级比&高,所以a先与后面的【0】成为数组里第一个元素再对它取地址,那&a【0】相当于首元素地址,所以此时sizeof里是地址的大小,大小为4或8个字节
sizeof(&a[0]+1)根据以上推测第一个地址加一相当于第2个地址,既然是地址,那大小为4或8个字节
2.2 字符数组
这里是char类型,一个元素大小1个字节
我们先看第一个,sizeof(arr),arr是数组名在sizeof里只有一个数组名,此时arr代表整个元素,一个元素大小是1,则整个元素的大小就是6个字节
sizeof(arr+0),此时不仅仅是数组名一个单独在sizeof里,所以这里的arr代表数组首元素的地址,那首元素地址加0还是首元素地址,所以此时sizeof里是个地址,大小为4或8个字节
sizeof(*arr),此时不仅仅是数组名一个单独在sizeof里,所以这里的arr代表数组首元素的地址,那解引用就是首元素的大小,所以此时sizeof里是个元素大小,大小为1
sizeof(arr[1]),此时不仅仅是数组名一个单独在sizeof里,所以这里的arr代表数组首元素的地址,那首元素地址后面跟个数组括号,里面有个1,所以此时sizeof里是第2个元素的大小,大小为1个字节
sizeof(&arr),&后跟数组名代表取整个数组的地址,所以此时sizeof里是个地址大小,大小为4或8个字节
sizeof(&arr+1),此&后跟数组名代表取整个数组的地址,加一就是跳过一个数组的大小的地址,所以此时sizeof里是个地址大小,大小为4或8个字节
sizeof(&arr【0】+1),&后跟首元素的地址,加一是第2个元素的地址,所以此时sizeof里是个地址大小,大小为4或8个字节
那如果所有的sizeof换成strlen会是什么样子
strlen(arr)这里的arr代表首元素地址,此时从首元素读取到\0不知道什么时候读取到,所以此时为随机值
strlen(arr+0)这里的arr代表首元素地址,加0依旧是首元素的地址,此时从首元素读取到\0不知道什么时候读取到,所以此时为随机值
strlen(*arr)这里的arr代表首元素地址,解引用是一个字符,字符对应的ASC码值强制转换成地址,是个野指针,所以这里读取错误
strlen(arr【1】)这里的arr代表首元素地址,后面【1】代表第2元素大小,字符对应的ASC码值强制转换成地址,是个野指针,所以读取错误。
strlen(&arr)&后跟数组名代表取整个数组的地址,整个数组的地址也是从首元素开始读取,找到\0结束,所以是随机值。
strlen(&arr+1)跳过一个数组的地址,也是个地址,从这个地址开始读取,到\0结束,所以是个随机值
strlen(&arr【0】+1)跳过一个元素的地址,从这个地址开始读取,到\0结束,所以是个随机值
来看看字符串
sizeof(arr),arr是数组名在sizeof里只有一个数组名,此时arr代表整个元素,一个元素大小是1,但别忘了字符串结束标志还有一个\0,则整个元素的大小就是7个字节
sizeof(arr+0),此时不仅仅是数组名一个单独在sizeof里,所以这里的arr代表数组首元素的地址,那首元素地址加0还是首元素地址,所以此时sizeof里是个地址,大小为4或8个字节
sizeof(*arr),此时不仅仅是数组名一个单独在sizeof里,所以这里的arr代表数组首元素的地址,那解引用就是首元素大小,所以此时sizeof大小为1个字节
sizeof(arr【1】),此时不仅仅是数组名一个单独在sizeof里,所以这里的arr代表数组首元素的地址,那首元素地址后面跟个数组括号,里面有个1,所以此时sizeof里是第2个元素的大小,所以此时sizeof大小为1个字节
sizeof(&arr),此&后跟数组名代表取整个数组的地址,所以此时sizeof里是个地址大小,大小为4或8个字节
sizeof(&arr+1),此&后跟数组名代表取整个数组的地址,加一就是跳过一个数组的大小的地址,所以此时sizeof里是个地址大小,大小为4或8个字节
sizeof(&arr【0】+1),&后跟首元素的地址,加一是第2个元素的地址,所以此时sizeof里是个地址大小,大小为4或8个字节
字符串数组换成strlen是什么情况那
strlen(arr)这里的arr代表首元素地址,此时从首元素读取到\0就停止,所以此时为6
strlen(arr+0)这里的arr代表首元素地址,加0还是首元素地址,此时从首元素读取到\0就停止,所以此时为6
strlen(*arr)这里的arr代表首元素地址,解引用是一个字符,字符对应的ASC码值强制转换成地址,是个野指针,所以这里读取错误
strlen(arr【1】)这里的arr代表首元素地址,后面【1】代表第2元素大小,字符对应的ASC码值强制转换成地址,是个野指针,所以读取错误。
strlen(&arr)&后跟数组名代表取整个数组的地址,整个数组的地址也是从首元素开始读取,找到\0结束,所以是6。
strlen(&arr+1)跳过一个数组的地址,刚好跳过了字符串的\0,也是个地址,从这个地址开始读取,到\0结束,所以是个随机值
strlen(&arr【0】+1)跳过一个元素的地址,相当于从第二个元素开始读取,到\0结束,所以是5
当换成指针变量存放字符会是什么结果那
sizeof(p)p是指针变量,指针变量的大小就是4或8个字节
sizeof(p+1)p指针指向的是第一元素指针,+1指向的是第二元素的地址,此刻还是个地址,大小就是4或8个字节
sizeof(*p)p指针指向的是第一元素指针,解引用的是第一个元素的大小,是char类型,大小为1个字节
sizeof(p[0])此时这里面可以把它看成一个数组,因为p指针是首元素的地址,相当于数组名嘛,此刻就是第一个元素的大小,大小为1个字节
sizeof(&p)此时取地址取的是p指针变量这个空间的地址,不是p指向的首元素的地址,相当于char* *p2=&p二级指针,但此刻存放地址的地址也是地址,大小为4或8个字节
sizeof(&p+1)p指针变量的地址加1还是地址,相当于跳了一个char*指针变量的地址,大小为4或8个字节
sizeof(&p[0]+1)取首元素的地址,再加1,相当于第二个元素的地址,大小为4或8
我们再看看换成strlen
strlen(p),p是首元素的地址,从首元素的地址往后读取到\0结束,长度为6
strlen(p+1),p是首元素的地址,加1是第二个元素地址,从第2个元素的地址往后读取到\0结束,长度为5
strlen(*p),p是首元素的地址,*p是第一个元素的大小,相当于字符对应的ASC码值强制转换为地址,是个野指针,则读取错误
strlen(p【0】),把它看成数组,相当于首元素大小,相当于字符对应的ASC码值强制转换为地址,是个野指针,则读取错误
strlen(&p),p指针变量的地址,相当于把p存放的地址读取到\0结束,但我不知道什么时候结束,所以是随机值
strlen(&p+1),p指针变量的地址,再加一,相当于是从p跳过一个p指针变量的地址,从这个地方把存储的东西读取到\0结束,但我不知道什么时候结束,所以是随机值
strlen(&p【0】+1),相当于首元素地址加一,是从第二个元素地址开始读取,到\0结束,大小为5
2.3 二维数组
哈哈哈接下来继续上强度,二维数组
sizeof(a)a是二维数组的数组名,当数组名单独存在sizeof()里代表的是整个数组的大小,大小为48个字节
sizeof(a【0】【0】)a不是单独存在那就代表是首元素的地址,后面跟一个数组括号里面是0代表第一行数组数组名,再跟一个数组括号里面是个0就代表第一行数组的首元素大小,大小为4个字节
sizeof(a【0】)a不是单独存在那就代表是首元素的地址,后面跟一个数组括号里面是0代表第一行数组数组名,数组名单独存在就代表这是第一行数组大小,大小为16个字节
sizeof(a【0】+1)a不是单独存在那就代表是首元素的地址,后面跟一个数组括号里面是0代表第一行数组数组名,数组名不是单独存在就代表是第一行首元素地址,加1就代表是第二个元素地址,大小为4或8个字节
sizeof(*(a【0】+1))a不是单独存在那就代表是首元素的地址,后面跟一个数组括号里面是0代表第一行数组数组名,数组名不是单独存在就代表是第一行首元素地址,加1就代表是第二个元素地址,再解引用就是第二个元素大小,大小为4字节
sizeof(a+1)a不是单独存在那就代表是首元素的地址,二维数组的首元素地址就是第一行数组的地址,第一行数组的地址加1就是第二行数组的地址,地址大小就为4或8个字节
sizeof(*(a+1))a不是单独存在那就代表是首元素的地址,二维数组的首元素地址就是第一行数组的地址,第一行数组的地址加1就是第二行数组的地址,再解引用,就是第二行数组名,数组名单独存在就代表第二行数组的大小,是16个字节
sizeof(&a[0]+1)a[0]是第一行数组名,取地址就是第一行的地址,再加一就是第二行地址,地址大小为4或8个字节
sizeof(*(&a[0]+1))a[0]是第一行数组名,取地址就是第一行的地址,再加一就是第二行地址,再解引用是第二行数组大小,大小为16个字节
sizeof(*a)a不是单独存在那就代表是首元素的地址,二维数组的首元素地址就是第一行数组的地址,再解引用就是第一行数组名,又因为第一行数组名单独存在,就代表第一行大小,大小为16个字节
sizeof(a【3】)这里肯定有人疑惑,这不是越界了吗,确实越界了,但sizeof里表达式不运算,所以根本不访问指针指向的对象,依旧可以运行,这里就相当于第四行数组名,数组名单独存在,就代表第四行大小,注意,我并不需要去访问它,只需要知道它的类型是int [4],就可以知道它的大小是16个字节
3. 指针运算笔试题解析
3.1 题目1
我们来分析一下,a是首元素地址,加1就是第二个元素的地址,再解引用就是第二个元素,所以第一个答案就是2,ptr是int型指针,&后跟数组名取的是整个数组的地址,加1就是跳了一个数组的地址,注意,此时被强制转换为int*指针,所以再减一,减的是整形大小,相当于现在指向的是第5个元素,再解引用就是第五个元素,所以第二个答案为5
3.2 题目2
分析第一个,p是结构体类型,加1就是跳了一个结构体类型,一个结构体20个字节,跳了一个就是加20,又因为是16进制数,所以大小为0x100014,但让以地址打印所以去掉符号补零,就是100014前面位置全补零,第二个,此时p强制转换为unsigned long类型,此刻注意它不是指针了,注意,它不是指针了!!是个整型,那加一个整型1就是直接加一,结果就是100001高位补零就行,第三个是整型指针类型,加1就是跳过4个字节,那结果就是100004高位补零就行。
3.3 题目3
此刻首先一定要注意里面是小括号(),不是大括号{},是逗号表达式,返回值是最右边的值,那数组里就三个数,1,3,5,a[0]是第一行数组名,代表第一行首元素地址,用指针p表示,那p[0]就是第一行首元素,结果就是1
OK,指针这块就完全结束了,喜欢的各位可以点赞,对指针还是不懂的朋友可以从我的第一篇指针博客再回顾一下。