目录
一、前言
sizeof和strlen的区别:
1、strlen计算字符串的具体长度 (只能是字符串),不包括字符串结束符。返回的是字符个数。
2、strlen的参数是指针类型,所以传过来的参数为指针才对。
size_t strlen ( const char * str );
3、sizeof计算声明后所占的内存数(字节大小),不是实际长度。
4、sizeof是一个取字节运算符, 而strlen是个函数。
5、sizeof的返回值=字符个数*字符所占的字节数,字符实际长度小于定义的长度,此时字符个数就等于定义的长度。若未给出定义的大小,分类讨论,对于字符串数组,字符大小等于实际的字符个数+1;对于整型数组,字符个数为实际的字符个数。字符串每个字符占1个字节,整型数据每个字符占的字节数需根据系统的位数类确定,32位占4个字节,48位占8个字节。
二、基础(前提)知识
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
3. 除此之外所有的数组名都表示首元素的地址。 (二维数组的首元素地址指的是第一行元素地址)
三、题目
(一)一维数组
1、整形数组
整形数组只能求sizeof,strlen只能求字符串的具体长度
#include <stdio.h>
int main() {
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a + 0));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(a[1]));
printf("%d\n", sizeof(&a));
printf("%d\n", sizeof(*&a));
printf("%d\n", sizeof(&a + 1));
printf("%d\n", sizeof(&a[0]));
printf("%d\n", sizeof(&a[0] + 1));
return 0;
}
下面来一行行解释:
printf("%d\n", sizeof(a));
这里是sizeof(数组名)的情况,所以这里的数组名表示整个数组,计算的是整个数组的大小,结果是sizeof(int)*4 = 16。
printf("%d\n", sizeof(a + 0));
这里的数组名不是直接放在sizeof里,而是+0,就是我们说的第三种情况,也就是代表首元素地址,地址分为32位和64位,所以这里的答案是4或者8。
printf("%d\n", sizeof(*a));
此处a表示首元素地址,进行解引用以后就代表了第一个元素也就是1,所以结果是4。
printf("%d\n", sizeof(a + 1));
同第二条,+1代表指向第二个元素地址,也就是2的地址,结果是4或8。
printf("%d\n", sizeof(a[1]));
a[1]代表第二个元素2,所以结果为4。
printf("%d\n", sizeof(&a));
&a就是取出a整个数组的地址,但是它还是一个地址,结果为4或8。
printf("%d\n", sizeof(*&a));
&a取出了整个数组的地址,解引用以后代表的是整个数组,相当于 int (* p ) [4]= &a; 一个数组指针, *p代表整个数组
所以结果是16。
printf("%d\n", sizeof(&a + 1));
&a代表取出整个数组地址,再+1代表直接跨过这个数组到达2的地址位置。结果为4或8。
printf("%d\n", sizeof(&a[0]));
表示取a[0]的地址,结果是4或8。
printf("%d\n", sizeof(&a[0] + 1));
取出a[0]的地址再向后跨过一个整形到达第二个元素的地址,结果是4或8。
结果:(32位地址为4个字节,64位地址为8个字节)
2、字符数组(情形1)
sizeof()
#include <stdio.h>
int main() {
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
return 0;
}
首先明确这里的arr数组里最后是没有\0的。
下面来一行行分析:
printf("%d\n", sizeof(arr));
arr直接放到sizeof里面,数组名表示整个数组,计算的是整个数组的大小,结果为6。
printf("%d\n", sizeof(arr + 0));
arr不是直接放到sizeof里,而是+0,所以这里的数组名就代表了首元素地址,+0表示没有向后移动,所以结果是4或8。
printf("%d\n", sizeof(*arr));
arr是首元素地址,*arr就是把首元素地址解引用,就是‘a’这个元素,所以结果为1。
printf("%d\n", sizeof(arr[1]));
arr[1]代表数组的第二个元素,是'b',所以结果为1。
printf("%d\n", sizeof(&arr));
&arr取出的是整个数组的地址,但它还是一个地址,所以结果为4或8。
printf("%d\n", sizeof(&arr + 1));
&arr取出的是整个数组的地址,+1表示跨过了这个数组到达下一块地址位置,结果为4或8。
printf("%d\n", sizeof(&arr[0] + 1));
&arr[0]代表取出数组第一个元素地址,+1表示向后挪动一个字节到达第二个元素地址,也就是‘b’的地址,结果为4或8。
结果:(32位地址为4个字节,64位地址为8个字节))
strlen()
int main() {
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
return 0;
}
下面来一条条解释:
printf("%d\n", strlen(arr));
这里arr表示的是首元素地址,但是因为此数组最后没有‘\0’字符串结束符,所以strlen数的时候停不下来,所以结果为随机值。
printf("%d\n", strlen(arr + 0));
同上,arr+0代表的还是数组首元素地址,结果为随机值。
printf("%d\n", strlen(*arr));
*arr表示解引用首元素地址,就是‘a’,但是strlen()这个函数的参数接收的是地址,所以此条语句错误。
printf("%d\n", strlen(arr[1]));
同上,这里的a[1]指的是元素‘b’,此条语句错误。
printf("%d\n", strlen(&arr));
&a代表取出a整个数组的地址,但是这个地址是指向首元素的地址的,于是传给strlen就是数组首元素地址,但是数组没有字符结束符,所以结果为随机值。
printf("%d\n", strlen(&arr + 1));
这条的意思前面已经解释过两遍,就是指向arr数组后的地址空间,所以是随机值,但是这个随机值会比上一条的随机值少6,因为arr数组里有六个元素,所以也可以写成 随机值 - 6。
printf("%d\n", strlen(&arr[0] + 1));
取出的是arr数组的第二个元素‘b’,但因为没有字符结束符,结果还是随机值,但这个随机值比上上条随机值少1,所以也可以写成随机值 - 1。
结果:(32位)(把两个错误语句屏蔽以后)
3、字符数组(情形2)
sizeof()
#include <stdio.h>
int main() {
char arr[] = { "abcdef" };
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr + 0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr + 1));
printf("%d\n", sizeof(&arr[0] + 1));
return 0;
}
首先明确这里的arr数组里最后是有\0的。sizeof()会算上最后的‘\0’。
所以这段代码除了第一条
printf("%d\n", sizeof(arr));
的结果会多一个'\0',也就是6 + 1 = 7,以外,其他分析和结果不变。
结果:(32位)
strlen()
#include <stdio.h>
int main() {
char arr[] = { "abcdef" };
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
return 0;
}
下面来一条条分析:
printf("%d\n", strlen(arr));
arr表示数组首元素地址,而数组后面有字符串结束符‘\0’,而strlen计算本身并不包括'\0',所以结果为6。
printf("%d\n", strlen(arr + 0));
arr+0还是表示首元素地址,结果为6。
printf("%d\n", strlen(*arr));
*arr表示首元素,但是strlen得接受地址,所以此条代码错误。
printf("%d\n", strlen(arr[1]));
arr[1]代表数组第二个元素,理由如上条,此条代码错误。
printf("%d\n", strlen(&arr));
&arr表示取出整个数组地址,但是传过去的值是首元素地址,所以结果为6。
printf("%d\n", strlen(&arr + 1));
&arr + 1表示越过arr数组到 arr后面的地址空间,所以是随机值。
printf("%d\n", strlen(&arr[0] + 1));
&arr[0],表示区第一个元素的地址,+1代表往后走一个字节(因为是char类型),取到了第二个元素的地址,所以结果为5。
结果:(32位)(把两条错误代码屏蔽以后)
4、字符数组(情形3)
sizeof()
#include <stdio.h>
int main() {
char* p = "abcedf";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p+1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p + 1));
printf("%d\n", sizeof(&p[0] + 1));
return 0;
}
相当于将上面的arr数组的首元素地址放进指针p里。
下面来一条条分析:
printf("%d\n", sizeof(p));
p是指针,结果是4或8。
printf("%d\n", sizeof(p+1));
p+1还是一个地址,结果为4或8。
printf("%d\n", sizeof(*p));
p是指向数组首元素的指针,*p指的就是‘a’,结果为1。
printf("%d\n", sizeof(p[0]));
p[0]相当于情形2中的arr[0],相当于*(p + 0),指的还是‘a’,结果为1。
printf("%d\n", sizeof(&p));
p本身为指针,&p也还是一个地址,结果为4或8。
printf("%d\n", sizeof(&p + 1));
&p为地址,+1取出的是p后面那块内存空间的地址,结果为4或8。
printf("%d\n", sizeof(&p[0] + 1));
&p[0]取出的是首元素的地址,+1代表第二个元素的地址,结果为4或8。
结果:(32位)
strlen()
#include <stdio.h>
int main() {
char* p = "abcdef";
printf("%d\n", strlen(p));
printf("%d\n", strlen(p + 1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p + 1));
printf("%d\n", strlen(&p[0] + 1));
return 0;
}
下面来一条条分析:
printf("%d", strlen(p));
p是一个指向'a'地址的指针,strlen(p)就相当于把'a'的地址作为参数,结果为6。
printf("%d", strlen(p + 1));
p + 1就是跳过一个char型指向'b'的地址,结果是5。
printf("%d", strlen(*p));
p是指向'a'地址的指针,*p获取的就是'a',但是strlen的参数是指针,所以此条语句错误。
printf("%d", strlen(p[0]));
p[0] 相当于*(p + 0),取出来的就是'a',词条语句错误。
printf("%d", strlen(&p));
已知p是指向'a'地址的指针,此数组里有\0可以让strlen停下来。&p取出来的是p这个指针的地址,可是p里面存放了什么我们并不知道,所以是随机值。
printf("%d", strlen(&p + 1));
&p + 1指的是取到了p后面的地址空间,结果为随机值。
printf("%d", strlen(&p[0] + 1));
&p[0]渠道的是'a'这个元素的地址,+1就跳过一个char型,取到'b'的地址,结果是5。
结果:(32位)
(二)二维数组
#include <stdio.h>
int main() {
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a[0][0]));
printf("%d\n", sizeof(a[0]));
printf("%d\n", sizeof(a[0] + 1));
printf("%d\n", sizeof(*(a[0] + 1)));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(*(a + 1)));
printf("%d\n", sizeof(&a[0] + 1));
printf("%d\n", sizeof(*(&a[0] + 1)));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a[3]));
}
画个图帮助大家理解:
下面来一条条解释:
printf("%d\n", sizeof(a));
a单独放在sizeof()里面表示的是整个数组,结果为3 * 4 * 4(int) = 48。
printf("%d\n", sizeof(a[0][0]));
a[0][0]表示a的第一行第一个元素,结果是4。
printf("%d\n", sizeof(a[0]));
a[0]代表第一行的数组名,数组名单独放在sizeof()里表示整个数组,于是这里的结果就是第一行的元素个数 * sizeof(int)= 16。
printf("%d\n", sizeof(a[0] + 1));
此时a[0]既单独放在 sizeof()内部,也没有&,所以这里的a[0]表示首元素地址也就是a[0][0]地址,+1则跳过一个int型,表示a[0][1]的地址,结果为4或8。
printf("%d\n", sizeof(*(a[0] + 1)));
a[0] + 1表示第一行第二个元素的地址,解引用表示这个元素,结果为4。
printf("%d\n", sizeof(a + 1));
a表示首元素地址,二位数组的首元素表示第一行的地址,+1跳过一行来到a[1],表示第二行的地址,所以结果为4或8。
printf("%d\n", sizeof(*(a + 1)));
a+1表示第二行的地址,解引用表示第二行,所以计算的是第二行的大小,结果为16。
printf("%d\n", sizeof(&a[0] + 1));
&a[0]表示取出第一行的地址,+1表示第二行的地址,结果为4或8。
printf("%d\n", sizeof(*(&a[0] + 1)));
&a[0] + 1取出的是第二行的地址,解引用表示第二行,计算的是第二行的大小,结果为16。
printf("%d\n", sizeof(*a));
a表示首元素地址即第一行的地址,*a表示第一行大小,结果为16。
*a <----> *(a+0) <----> a[0]
printf("%d\n", sizeof(a[3]));
a[3]单独放在sizeof()里理论上来说是数组第四行,虽然数组没有第四行,但是由于sizeof()内部的表达式并不会被真正访问,是不参与运算的,所以结果为16。
结果:(32位)
结束啦~~散花~~
有什么作者写的不对的地方欢迎在评论区指正哦,请多多的点赞吧!谢谢大家qaq