关于sizeof和strlen的一些题目解析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于sizeof和strlen的一些题目解析相关的知识,希望对你有一定的参考价值。
首先我们要知道sizeof 和strlen的区别是什么
1.sizeof计算的是占用内存空间的大小,单位是字节,不关注内存中到底存放的是什么,
2.sizeof不是函数,是操作符
3.strlen是函数
4.strlen是针对字符串的,求的是字符串的长度你传给strlen的是字符数组的地址strlen从地址处向后计数遇到一个字符加一直到遇到\\0。所以当你传给strlen一个特定的值如a就会造成非法访问,因为strlen将a的ascll值当作了地址
然后便是数组名代表的意义在不同情况下意义是不同的。
大部分情况下数组名代表的是数组首元素的地址,
但是有两个例外首先就是sizeof(数组名),数组名表示的是整个数组,计算的是整个数组的大小。
然后就是&数组名- 数组名表示的是整个数组,取出的是整个数组的地址。
上面的这些话是非常重要的,和下面的题联系非常的密切
我们来看下面的一组打印函数分别会打印什么答案
#include<stdio.h>
int main()
//一维数组
int a[] = 1,2,3,4 ;
printf("%d\\n", sizeof(a));//这里的a是数组名单独放在sizeof内部计算的是整个数组的大小所以是16
printf("%d\\n", sizeof(a + 0));//这里加了0就不是数组名单独放在sizeof内部,这里的数组名代表的是数组首元素的地址。是地址所以大小是4或者是8.
printf("%d\\n", sizeof(*a));//这里也不是数组名单独放在sizeof内部那么a就是数组首元素的地址解应用后代表整型数1大小为4个字节
printf("%d\\n", sizeof(a + 1));//这里也不是数组名单独放在sizeof代表首元素的地址加1就是跳过了一个整型的地址代表2的地址,因为是地址所以是4或者8个字节
printf("%d\\n", sizeof(a[1]));//这个就很简单了直接就是代表数组的第二个数据所以大小是4
printf("%d\\n", sizeof(&a));//这里是取地址a代表取出了整个数组的地址但依旧是地址所以大小就是4或者8个字节
printf("%d\\n", sizeof(*&a));//这里代表的是先将整个数组的地址取出来再解引用得到的是整个数组所以大小是16
printf("%d\\n", sizeof(&a + 1));//这里&a先取出了整个数组的地址这里的地址类型就是数组指针变量,加一跳过了一个数组指针变量的大小但是数组指针变量本质上还是地址所以大小还是4或者8个字节
printf("%d\\n", sizeof(&a[0]));//这里就是将数组首元素的地址取出来,是地址所以大小是4或者8个字节
printf("%d\\n", sizeof(&a[0] + 1));这里和上面的意思一样但是跳过了一个整型指针所以这个应该是2的地址,地址所以大小是4或者8个字节
return 0;
最后我们来运行验证一下如图完美符合
下面我们来看下一组题目
对于这一组题目我们首先就要知道char arr[] = a,b,c,d,e,f ;和char arr[] = "abcdef";的区别
就是第一个数组里只有6个元素不包含\\0而第二个数组里是除了前面6个元素以外还包含了\\0、
还有就是strlen函数是怎么计数的我们来看下面的这个模拟函数
#include<stdio.h>
int my_strlen(const char* arr)
int count = 0;
while (*arr++ != \\0)
count++;
return count;
int main()
char arr[] = "abcdef";
printf("%d", my_strlen(arr));
运行结果
从这里我们就能知道strlen函数需要的是我们传递给这个函数一个地址,strlen再解引用地址判断是不是\\0是就停止计数再返回计数的值不是就++先后一位。
#include<stdio.h>
int main()
char arr[] = a,b,c,d,e,f ;
printf("%d\\n", sizeof(arr));//这里是数组名单独放在了sizeof内部代表的是整个数组所以这里的值是6。char类型数据占一个字节
printf("%d\\n", sizeof(arr + 0));//这里并不是数组名单独放在sizeof内部所以数组名代表的是数组首元素的地址,地址所以大小是4或者8个字节
printf("%d\\n", sizeof(*arr));//这里和上面一样不是数组名单独放置所以代表数组首元素的地址解引用这里就是a,所以这里的大小是1
printf("%d\\n", sizeof(arr[1]));这个就很简单了直接就表示数组第二个元素即b,b是char类型所以大小是1
printf("%d\\n", sizeof(&arr));//这里代表取出了整个数组的地址,地址所以大小是4或者8个字节
printf("%d\\n", sizeof(&arr + 1));//这里先取出了整个数组的地址,这里的地址就是数组指针变量加1就跳过了一个数组指针变量,但仍旧是地址所以大小是4或者8个字节
printf("%d\\n", sizeof(&arr[0] + 1));//这里就是先取出了首元素的地址,这里的地址就是字符指针,在跳过一个字符指针所以这里就表示了一个字符指针变量即地址,这个地址指向的是b因为是地址所以大小是4或者8个字节
printf("%d\\n", strlen(arr));//这里就不是sizeof了所以这里的arr代表的是数组首元素的地址,所以strlen函数通过这个地址不断向后去访问但是我们不知道\\0会存在于这6个元素之后的哪一个地址空间里所以这里的大小是随机值。
printf("%d\\n", strlen(arr + 0));这里不是数组名单独在sizeof内部也不是&数组名所以这里的数组名就代表的是数组首元素的地址加0还是这个地址不变,所以最后的情况和上面代码一样都是随机值因为不知道\\0的位置
printf("%d\\n", strlen(*arr));//首先这里的数组名代表的是数组首元素的地址,然后解引用后得到的就是第一个字符a,strlen函数在接受参数的时候接受的是地址这里的a并不是地址但strlen还是会将a的ascll值作为地址,所以这里的代码是有问题的不能这么写的,所以也得不出任何大小
printf("%d\\n", strlen(arr[1]));//这里的情况和上面的代码情况一样,只不过是把b的asccll值当作了地址而已
printf("%d\\n", strlen(&arr));//这里表示的就是取出来整个数组的地址但是传递给strlen之后它依旧会从数组首元素的地址开始往后所以这里的值依旧是随机值
printf("%d\\n", strlen(&arr + 1));//这里表示的是取出整个数组的大小然后再跳过了一个数组的地址,所以对于strlen函数而言它相当于从数组的末端开始向后读取所以这里的值为随机值2,但与上面的随机值的关系就是随机值-随机值2=6因为这个随机值2相当于是跳过了6个元素从元素末端向后计数的
printf("%d\\n", strlen(&arr[0] + 1));//这里就是取出a的地址加了一个字符指针所以这个表达式地址指向的就是b然后strlen从b开始往后读取。
return 0;
下面就是运行结果
我们会发现基本都满足但是再strlen(*arr)以后的代码都未执行,这是因为在这里就出现了问题我们调试之后运行到这里就会出现下图这个问题就是因为我上面说的那个原因。将a的ascll值当作了地址
而我们再注释掉这两个代码后就能得到下面的运行图
这些随机值也满足我刚刚说的那些规律。
下面我们继续来看下一组题目
#include<stdio.h>
int main()
char arr[] = "abcdef";
printf("%d\\n", sizeof(arr));//这个数组名单独放在了sizeof内部代表的式整个数组所以大小为7
printf("%d\\n", sizeof(arr+0));//这个不是数组名单独放在了sizeof内部代表的就是数组首元素的地址+0依旧是a的电地址,是地址所以大小是4或者8个字节
printf("%d\\n", sizeof(*arr));//不是数组名单独放在了sizeof内部所以代表的是数组首元素的地址,解引用之后就是字符类型的a,所以大小是1
printf("%d\\n", sizeof(arr[1]));这个很简单直接就是代表了字符类型的b所以大小是1
printf("%d\\n", sizeof(&arr));//这个是取地址数组名取出的是整个数组的地址,但依旧是地址所以还是4或者8个字节
printf("%d\\n", sizeof(&arr+1));//这个首先是取出了整个数组的地址然后在跳过了一个数组大小的地址但依旧是地址大小依旧是4或8个字节
printf("%d\\n", sizeof(&arr[0]+1));这个首先是将数组首元素的地址取了出来在加了一个char*大小的空间,也就让这个表达式的地址指向了b但这个表达式表示的依旧是地址所以大小还是4或者8个字节
printf("%d\\n", strlen(arr));//这个并不是数组名单独放在了sizeof内部也不是取地址数组名,所以这个就表示数组首元素的地址,传给了strlen函数因为这个数组最后加了\\0所以这里的值为6
printf("%d\\n", strlen(arr+0));///这个并不是数组名单独放在了sizeof内部也不是取地址数组名,所以这个就表示数组首元素的地址,加了0所以还是一个地址指向了数组首元素所以最后这里的值还是6
printf("%d\\n", strlen(*arr));///这个并不是数组名单独放在了sizeof内部也不是取地址数组名,所以这个就表示数组首元素的地址,解引用之后就代表了a和之前遇到的错误一样所以这个代码是错误的无值
printf("%d\\n", strlen(arr[1]));//与上面的代码表示一样
printf("%d\\n", strlen(&arr));//这个为&arr代表取出了整个数组的地址但传给了strlen之后strlen依旧从第一个元素向后读取,所以这里值依旧为6
printf("%d\\n", strlen(&arr+1));//前面与上面的代码表示一样的意思,但是加了一个1跳过了整个数组之后等于从\\0后面的那个元素开始向后读取,但我们不知道后面的\\0在哪里所以这里的值是随机值
printf("%d\\n", strlen(&arr[0]+1));这个即将首元素的地址取出来再跳过了一个元素的地址即此时指向的是第二个元素,此时的地址也是第二个元素的地址。所以这里的值为5
这里的字符数组和上面的那个数组不同点就在于再f的后面有一个\\0
下面就是我在注释了两个错误代码之后的运行截图
完全符合
我们继续看下一组题
#include<stdio.h>
int main()
char *p = "abcdef";//这里我们并没有创建一个数组而是将一个常量字符串的首元素的地址给到了p变量里面
printf("%d\\n", sizeof(p));//这里就是计算这个字符指针变量p的大小即一个地址的大小所以是4或者8个字节
printf("%d\\n", sizeof(p+1));//这里和上面的类似只不过是将p加了一个字符指针变量的大小让其的地址不再指向a而是指向了b
printf("%d\\n", sizeof(*p));//这里就是解引用了首元素的地址即计算了a的大小a是字符所以大小是1
printf("%d\\n", sizeof(p[0]));//p[0]等价于*(p+0)所以这里还是相当于计算a的大小依旧是1
printf("%d\\n", sizeof(&p));//这里是将p的地址取出来了计算的是一个二级指针变量的大小,但二级指针依旧是地址所以大小依旧是4或者8个字节
printf("%d\\n", sizeof(&p+1));//和上面一样只不过1加了一个二级指针变量的大小但依旧是地址大小依旧是4或者8个字节
printf("%d\\n", sizeof(&p[0]+1));//这里可以理解成&[*(P+0)]+1,就相当于是取出来a的地址再加了一个字符指针即跳过了一个字符的地址所以最后得出的是一个地址指向的是b所以大小是4或者8个字节
printf("%d\\n", strlen(p));//这里就相当于将a的地址传给了strlen,strlen往后读所以最后的值是6
printf("%d\\n", strlen(p+1));//这里就相当于strlen从b开始往后读所以最后的值为5
printf("%d\\n", strlen(*p));//这里的错误和上面用数组的错误是一样的
printf("%d\\n", strlen(p[0]));//和之前的错误是一样的所以不再赘述了
printf("%d\\n", strlen(&p));//这里就相当于将p的地址即一个二级指针变量传给了strlen所以最后这里的值为随机值
printf("%d\\n", strlen(&p+1));//这里依旧是随机值但这俩个随机值之间没有任何关系因为我们不知道p的地址和p+1的地址之间有没有\\0
printf("%d\\n", strlen(&p[0]+1));//这里可以理解为将a的地址取出来再加上了一个字符指针的大小所以最后得出的是一个地址指向的是b,所以这里的值为5
return 0;
再注释了两个错误代码之后的运行结果
完美符合
最后我们来看下一组题(也是比较难的一组题)
首先我们来看下面代码中的这个二维数组我们用画图的方式将这个二维数组在内存中的存在表示出来,
下面就是a[3][4]在内存中的表现形式
然后当我们想要访问这个二维数组其中的一个元素的时候我们一般就是用a[i][j]的方式访问
其中i大于等于0小于等于2。j大于等于0小于等于3。若我们想要访问第0行的数据那么不管是第0行的哪一个数据我们都要使用a[0][j]的形似访问,对于第一行和第二行的数据也是同理,那么我们看一下一维数组,在访问数据时是a[i]的形式其中a单拎出来在大部分情况下就是数组名加方块就可以访问这个一维数组元素,同理那么对于二维数组也是这样数组名加方块也就可以访问二维数组每一个元素,所以a[i]也就可以被称为这一行的数组名。
#include<stdio.h>
int main()
int a[3][4] = 0;
printf("%d\\n",sizeof(a));//这里是a这个二维数组的数组名单独放在了sizeof内部,计算的是整个二维数组的大小,即最后的大小就是48个字节
printf("%d\\n",sizeof(a[0][0]));//这个就是直接访问这个二维数组第0行第0列的数据,计算的是这个数据的大小所以是4个字节
printf("%d\\n",sizeof(a[0]));//这里就相当于是将第0行的数组名单独放在了sizeof内部计算的就是第0行的大小所以是16个字节
printf("%d\\n",sizeof(a[0]+1));//这里并不是数组名单独放在sizeof内部所以这个a[0]代表的是首元素的地址即a[0][0]的地址加1即a[0][1]的地址所以这里最后的值就是4或者8
printf("%d\\n",sizeof(*(a[0]+1)));//这里就直接相当于对a[0][1]的地址解引用得到的就是a[0][1]的值所以最后sizeof计算大小为4
printf("%d\\n",sizeof(a+1));//这里不是二维数组的数组名a单独放在sizeof内部所以这里的a就表示数组首元素的地址,而二维数组的首元素就是第一行所以a就相当于第一行的地址,地址所以最后sizeof求出的值是4或者8
printf("%d\\n",sizeof(*(a+1)));//这里就相当于将数组第一行的地址解引用得到的就是第一行的数据所以最后sizeof求出的大小就是16
printf("%d\\n",sizeof(&a[0]+1));//这里就相当于先将第一行的地址取出来再加了一个1即跳过了一行的地址,所以这个表达式表示的就是第二行的地址所以这里的值就是4或者为8
printf("%d\\n",sizeof(*(&a[0]+1)));//这里就相当于将第二行的地址解引用所以最后求出的值就是第二行数据所占空间大小为16
printf("%d\\n",sizeof(*a));//这里也不是二维数组的数组名单独放在sizeof内部所以就相当于是第1行的地址被解引用所以最后的大小也为16
printf("%d\\n",sizeof(a[3]));//这里求出的值依旧是16原因我会在下面写出
printf("%d\\n", sizeof(*a + 1));//这里我们一步一步的分析首先这并不是二维数组的数组名单独放在了sizeof内部所以这里就相当于是第1行的地址被解引用也就相当于a[0]+1被放在了sizeof内部而这个也不是第一行的数组名单独放在sizeof内部所以这个就相当于是第一行第一个元素的地址加1即第一行第二个元素的地址所以最后的值为4或者8
return 0;
运行结果如图
完美符合
最后一个为16的原因就是对于计算机而言它认为了这就是第四行的地址就相当于是第四行的数组名单独放在了sizeof内部计算的就是整个第四行的地址所以是16。
这里之所以不会出现越界访问的问题原因就是sizeof内部的地址,计算机并没有去访问而是计算机内部自己便推断出来了。
我们来看下面一个代码说明sizeof的这个特点
#include<stdio.h>
int main()
int a = 7;
short s = 4;
printf("%d\\n", sizeof(s = a + 4));
printf("%d\\n", s);
return 0;
然后我们来看运行结果
前面的2是因为s是一个短整型占两个字节的空间而a+4为11,11能够放在短整型里面所以计算机对a+4的值进行了截断,所以最后这个表达式的类型依旧是短整型。
从这里我们也能知道了对于一个变量而言它既有值属性也有类型属性,计算机就是通过了这个类型属性确定了sizeof要输出什么所以也就不会让s的值属性发生改变。
但下面的代码又告诉了我们计算机并没有去执行sizeof内部的赋值语句,而是靠自己的推断便得到了2这个值。总结就是对于计算机而言sizeof内部的表达式并没有执行而是靠计算机自己便可以推断出来。即通过a[3]的类型属性也就能得到16的值,就不会去访问这一行,所以在上面的a[3]才不会发生数组越界的问题。
我们下面来看一个关于一个结构体数据的问题
//,这里告知结构体的大小是20个字节
#include<stdio.h>
struct Test
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
p = (struct Test*)0x100000;
printf("%p\\n", p + 0x1);//我们首先要知道一个整型指针加1跳过的是一个整型指针的大小而这里是一个结构体指针加一所以这里跳过的就是20个字节,打印地址也就是0x100014,这里是16进制所以14也就是20
printf("%p\\n", (unsigned long)p + 0x1);//而这里p的值被强制类型转换为了整型而整型加1自然也就是0x100001
printf("%p\\n", (unsigned int*)p + 0x1);因为在前面就将p强制类型转换为了无符号整型指针所以这里相当于加了一个整型指针的大小也即变成了0x100004
return 0;
运行截图
以上便是我对于这些题的解释,如果您发现了问题请严厉指出。
非常感谢。
以上是关于关于sizeof和strlen的一些题目解析的主要内容,如果未能解决你的问题,请参考以下文章