✨✨小新课堂开课了,欢迎欢迎~✨✨
🎈🎈养成好习惯,先赞后看哦~🎈🎈
所属专栏:http://t.csdnimg.cn/Oytke
小新的主页:编程版小新-优快云博客
在深入理解sizeof和strlen之前,我们先对其进行简单的介绍。
在学习操作符的时候,我们学习了 sizeof , sizeof 是用来计算变量所占内存内存空间⼤⼩的,单位是字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的⼤⼩。一定要注意的是sizeof只计算类型所占内存的大小,不关注内存中存放的什么数据。
strlen其实是一个函数,用来计算字符串长度,在使用该函数的时候要包含头文<string.h>,计算的过程中遇到'\0'停止,如果没有'\0'就有可能会出现越界访问。因为这篇文章是用指针来理解strlen,在这里就和大家提一下 strlen的函数原型: size_t strlen ( const char * str );
为了方便大家的理解,给大家准备了表格进行对比:
sizeof | strlen | ||
1.sizeof是操作符 | 1.库函数,使用前要包含头文件 | ||
2.计算内存所占空间的大小 | 2.计算'\0'之前字符的个数 | ||
3.不管内存中存放的什么数据 | 3.如果没有'\0'可能会出现越界访问 |
接下来我们进入正文,这里要补充到到一些知识点,首先是一般数组名代表数组首元素的地址,只有在两种情况下代表的是整个数组的地址:1.sizeof(arr)数组名单独放在sizeof内部 2.&arr这时取出的地址是整个数组的地址。一定要切记这两点,把握好这两点才能避免很多错误。
无论是一维数组还是二维数组在内存中都是连续存放的。
arr[3][4] | ||||
0 | 1 | 2 | 3 | |
0 | 1 | 2 | 3 | 4 |
1 | 5 | 6 | 7 | 8 |
2 | 9 | 10 | 11 | 12 |
这是我们以为的二维数组在内存中的存放方式,实际情况并非如此。
第一行 | 第二行 | 第三行 | |||||||||
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
arr[0] | arr[1] | arr[3] |
这才是二维数组在内存中存放的实际情况。
另外还要补充的是:指针 - 指针 绝对值 得到是指针与指针之间的元素个数;类型加减常数要看是什么类型,比如整型+1跳过4个字节。
下面请看整体的例子:
#include<stdio.h>
int main()
{
int arr[3][4] = { 0 };//arr是数组名,arr[0]是第一行的数组名
printf("%zd\n", sizeof(arr));//arr单独放在sizeof内部,计算的是数组的大小,单位是字节,12*4==48
printf("%zd\n", sizeof(arr[0][0]));//arr没有单独放在sizeof内部,也没有&arr,此时arr[0][0]表示数组
//首元素的地址,是地址就是4/8个字节
printf("%zd\n", sizeof(arr[0]));//arr[0]是第一行的数组名,数组名单独放在sizeof内部,计算第一行数组的大小
//是16个字节
printf("%zd\n", sizeof(arr[0] + 1));//arr[0]没有单独放在sizeof内部,arr[0]表示数组首元素的地址,就是arr[0][0]的地址,+1跳过4个
//字节,就是arr[0][1]的地址,是地址,就是4/8个字节
printf("%zd\n", sizeof(*(arr[0] + 1)));//arr[0]没有单独放在sizeof内部,arr[0]表示数组首元素的地址,+1
//跳过4个字节,就是arr[0][1]的地址,*(解引用)后,就是第一行第二个元素,4个字节
printf("%zd\n", sizeof(arr + 1));//arr没有单独放在sizeof内部,表示数组首元素的地址,是二位数组首元素的地址,
//是第一行的地址,+1,跳过一行,表示第二行的地址,是地址就是4/8个字节
printf("%zd\n", sizeof(*(arr + 1)));//arr+1表示第二行的地址,*后,就是第二行,计算的是第二行的大小,16个字节
printf("%zd\n", sizeof(&arr[0] + 1));//arr[0]是第一行,&arr[0]取出的是第一行的地址,+1是第二行的地址,是
//地址就是4/8个字节
printf("%zd\n", sizeof(*(&arr[0] + 1)));//*后,得到的是第二行,计算第二行的大小,16个字节
printf("%zd\n", sizeof(*arr));//arr没有单独放在sizeof内,是数组首元素的地址,是二维数组首元素的地址,也
//就是第一行的地址,*后,计算第一行的大小,16个字节
printf("%zd\n", sizeof(&arr));//&arr取出的是数组的地址,是地址就是4/8个字节
printf("%zd\n", sizeof(*&arr));//*与&相抵消,sizeof(*&arr)==sizeof(arr),计算的是数组的大小,48个字节
printf("%zd\n", sizeof(arr[3]));//arr[3]无需真实存在,仅仅需要类型的推断就能计算出长度
//arr[3]是第四行的数组名,数组名单独放在sizeof内,计算第四行的大小,16个字节
const char* p = "abcdef";//p是指针变量,里面存放的首元素'a'的地址,知道了'a'的地址就能找到整个字符串
printf("%zd\n", sizeof(p));//4/8
printf("%zd\n", sizeof(p + 1));//+1后,就是'b'的地址,是地址就是4/8个字节
printf("%zd\n", sizeof(*p));//p的类型是conest char *,*后,就是char类型,结果是1个字节
printf("%zd\n", sizeof(p[0]));//p[0]是首元素,是char类型,结果就是1个字节
printf("%zd\n", sizeof(&p));//&p,取出的是p的地址,是地址就是4/8个字节
printf("%zd\n", sizeof(&p + 1));//&p+1,就是跳过指针变量p的地址的后一个地址,是地址,就是4/8个字节
printf("%zd\n", sizeof(&p[0] + 1));//+1后,是第二个元素的地址,是地址就是4/8个字节
return 0;
}
#include<stdio.h>
int main()
{
char arr[] = { 'a','b','c','d','e','f' };//没有'\0'系列
printf("%d\n", strlen(arr));//arr是数组名,是数组首元素的地址,数组中没有'\0',就有可能越界访问,结果是随机的
printf("%d\n", strlen(arr + 0));//arr+0是数组首元素的地址,数组中没有'\0',就有可能越界访问,结果是随机的
printf("%d\n", strlen(*arr));//arr是数组首元素的地址,*后,就是'a','a'的ascii码值是97,就相当于把97当作
//地址传给了strlen,strlen得到的是野指针,代码有问题
printf("%d\n", strlen(arr[1]));//arr[1]是数组中的第二个字符'b','b'的ascii码值是98,就相当于把98当作地址
//传给了strlen,strlen得到的是野指针,代码有问题
printf("%d\n", strlen(&arr));//&arr,取出的是整个数组的地址,起始位置是数组的第一个元素,结果是随机值
printf("%d\n", strlen(&arr + 1));//+1,跳过整个数组,因为没有'\0',结果还是随机值
printf("%d\n", strlen(&arr[0] + 1));//&arr[0],是数组首元素的地址,+1,是第二个元素的地址,结果还是随机值
char arr[] = "abcdef";//存在'\0'系列
printf("%d\n", strlen(arr));//arr是数组名,是数组首元素的地址,结果是6
printf("%d\n", strlen(arr + 0));//arr+0是数组首元素的地址,结果是6
printf("%d\n", strlen(*arr));//arr是数组名,是数组首元素的地址,*后,是数组中的第一个元素,结果是6
printf("%d\n", strlen(arr[1]));//arr[1]是数组中第二个元素的地址,结果是5
printf("%d\n", strlen(&arr));//&arr,取出的是整个数组的地址,起始位置是数组首元素,结果是6
printf("%d\n", strlen(&arr + 1));//+1,跳过整个数组,也就跳过了原本数组中的'\0',结果是随机值
printf("%d\n", strlen(&arr[0] + 1));//+1,跳过一个字节,来到数组的第二个元素,是第二个元素的地址,结果是5
char* p = "abcdef";//有'\0'存在,p是指针变量,里面存放的首元素'a'的地址,知道了'a'的地址就能找到整个字符串
printf("%d\n", strlen(p));//6
printf("%d\n", strlen(p + 1));//5,类比为p[0]+1
printf("%d\n", strlen(*p));//*p->'a'->97->err
printf("%d\n", strlen(p[0]));//6
printf("%d\n", strlen(&p));//&p,取出的是p的地址,就和字符串"abcdef"关系就不大了,从p这个指针变量的
//起始位置开始向后数,结果是随机值
printf("%d\n", strlen(&p + 1));//随机值
printf("%d\n", strlen(&p[0] + 1));//5
return 0;
}
通过以上很多例子,你有没有对sizeof和strlen有更加清晰的认识,后期会更新指针的内容,以及字符函数和字符串函数的知识,希望大家可以一起进步 ,感谢大家的支持~