sizeof和strlen的对比
sizeof()
计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。sizeof ()
只关注占⽤内存空间的大小,不在乎内存中存放什么数据。strlen()
是C语言库函数,功能是求字符串长度。 函数原型:
size_t strlen ( const char * str );
统计的是从 strlen()
函数的参数 str
中这个地址开始向后, \0
之前字符串中字符的个数。strlen()
函数会⼀直向后找\0
字符,直到找到为止,所以可能存在越界查找。
那我们思考一下如果我们传一个字符给strlen()
会怎么样?详细请看下面求strlen(*arr)
,这时我们会讲到实际案例!!!
那我们再思考一下如果我们传一个数组地址给strlen()
会怎么样?详细请看下面求strlen(&arr)
,这时我们会讲到实际案例!!!
在开始下面的介绍前还有一点非常重要,数组名的意义:
3. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
4. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
5. 除此之外所有的数组名都表示首元素的地址。
计算一维数组
整形数组
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));
我们先看一下输出的结果:
1.sizeof(a);
//sizeof(数组名) 计算的是数组的总大小-=单位字节–16
2.sizeof(a+0);
//肯定有人想问上一个还是16字节,怎么这儿就变成8了?其实这里a+0
是一个表达式,并不满足sizeof(数组名)形式,所以这里a
还是首元素地址,a+0
还为首元素地址,地址大小都为4 / 8字节
3.sizeof(*a);//这里a是首元素地址,所以*a就是首元素的类型(int)的大小,即为4
4.sizeof(a+1);//这里a为首元素地址,则a+1就是第二个元素地址,类比于2.,为4 / 8字节
5.sizeof(a[1]);//第二个元素大小,4
6.sizeof(&a);//&a取出的是数组的地址,是地址都是4 / 8
7.sizeof(*&a);//&a是数组a的地址,*解引用后则就是数组a,此处计算的还是数组的大小,16字节
8…sizeof(&a+1);//根据上面我们不难想到,此处&a+1相当于&a跳过了一个数组,但还是一个地址,为4 / 8字节
9…sizeof(&a[0]);//首元素地址,4 / 8字节
10…sizeof(&a[0]+1);//第二个元素的地址,4 / 8字节
字符数组
字符数组与整形数组的sizeof()
用法极其相似,这里就不多介绍了!
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));
运行结果:
1.strlen(arr);
2.strlen(arr+0);
我们可以看出这个字符数组并没有以'\0'
结尾,所以strlen()
计算首元素地址时,就产生了随机值!所以第一个和第二个是随机值!
3.strlen(*arr);
4. strlen(arr[1]);
开头我们介绍了strlen()函数接收的是一个地址。此处的*arr是数组首元素,arr[1]是数组第二个元素。所以编译器就会报错。还可以再深入讲一下,既然strlen()接收的是一个地址,而*arr是字符a,ASCII表的值为97,,此时strlen()就会把97当成一个地址去访问空间,但这个地址不是我们所拥有的空间,就形成了非法访问。
这里0x0000000000000061
其实就是97,这也就印证了我们的说法。
5.strlen(&arr);
6.strlen(&arr+1);
7.strlen(&arr[0]+1);
&arr
,&arr+1
,&arr[0]+1
其实都是地址,虽然第一个是一个数组的地址,但他的地址与首元素地址一样,所以为随机值,第二个跳过了一个数组所以为随机值-6,6是数组大小,第三个以为跳过了数组中的一个元素,所以为随机值-1。
可以看出虽然&arr
是一个数组地址,类型为数组指针char(*p)[6]
,事实上这只是当成一个地址看待,并不会真正影响结果。
字符串
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[0]+1));
我们看到这其实就会想到这不就是char arr[] = { 'a','b','c','d','e','f' ,'\0'};
吗?没错!这里sizeof()
计算方法还是与上面是一样的,但strlen()
还是要说一下的。
1.strlen(arr);
2.strlen(arr+0);
既然有了'\0'为结尾,那结果肯定就是字符串长度了,即为6
3.strlen(&arr);//这就会返回'\0'之前字符个数,即为6
4.strlen(&arr+1);//但是这里&arr+1跳过了数组arr,于是返回了一个随机值
5.strlen(&arr[0]+1);//这指向的是'b'的地址,于是返回5
计算常量字符串
char *p = "abcdef"; 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));
这儿难道是把"abcdef"
放到p
里面?其实这里的p
仅仅放了'a'
的地址
1.sizeof(p);//这儿就是计算指针变量p的地址,4 / 8字节
2.sizeof(p+1);//p+1得到的是字符'b'的地址,4 / 8字节
3.sizeof(*p);//*p其实就是字符串的第一个字符'a',1字节
4.sizeof(p[0]);//事实上这里的p[0]就等价于*(p+0),就是第一个元素,1字节
5.sizeof(&p);//这里&p把指针p的地址取出来了,4 / 8字节
char *p = "abcdef"; printf("%d\n", strlen(p)); printf("%d\n", strlen(&p)); printf("%d\n", strlen(&p+1));
1.strlen(p);
//上面也分析过了,p
存放的就是'a'
的地址,strlen()
找到'\0'
结束,所以就是6了
2.strlen(&p);
3.strlen(&p+1);
//&p
是指针p
的地址,这里我画了一张图来说明一下:
所以这里求出来的其实是随机值!
计算二维数组
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]));
我们看看编译器输出的结果吧!!!下面讲解一下为什么。
1.sizeof(a);
//这里的a
代表整个二维数组的数组名,大小为124,36字节
2.sizeof(a[0][0]);
//这则是数组第一个元素,4字节
3.sizeof(a[0]);
//a[0]
是二维数组的第一行作为一维数组的数组名,所以sizeof()
所求的是数组第一行的大小,大小为44,16字节
4.sizeof(a[0]+1);
//此处a[0]
表示第一行的数组名,表示的是首元素地址,其实就是第一行第一个元素的地址,所以a[0]+1
就表示第一行第二个元素的地址,4 / 8字节
5.sizeof(*(a[0]+1));
//如上*a[0]+1
就是第一行第二个元素,4字节
6.sizeof(a+1);
//我们考虑一下这是谁的地址呢?a
是二维数组的数组名,是首元素地址,而二维数组的首元素是他的第一行,那么a
就是第一行的地址,那么加一后就是第二行的地址,4 / 8字节
从这我们也可以看出两个地址相差了16,正是4个整形的大小,所以这也验证了上面,加一后跳过了一行。
7.sizeof(*(a+1));//如6.,解引用后就代表第二行,16字节
8.sizeof(&a[0]+1);//&a[0]取出第一行地址,加一后为第二行地址,4 / 8字节
9.sizeof(*(&a[0]+1));//解引用得到数组第二行,16字节
10.sizeof(*a);//a是首元素地址,第一行地址,解引用后为第一行,16字节
11.sizeof(a[3]);//a[3]是数组第四行,虽没有第四行,但根据数组类型,计算的任是一行有四个整形的数组大小,所以还为16