前言
阅读本文章,笔者会向你介绍sizeof和strlen的定义以及两者的区别,笔者还会通过讲解具体的笔试题带你深入理解。
一 sizeof介绍
在C语言中,sizeof是判断数据类型长度符的关键字。
(注意sizeof不是函数,它在程序没有运行时就计算出结果了)。
sizeof作用就是返回一个对象或者类型所占的内存字节数
#include <stdio.h>
int main()
{
int arr[10];
printf("%d", sizeof(arr));
return 0;
}
- sizeof单位是字节,因此结果为40
二 strlen介绍
strlen是一个计算给定字符串的(unsigned int型)长度的函数
(不包括’\0’在内)。
它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符’\0’为止。
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "asdf";
printf("%d", strlen(str));
return 0;
}
- 结果为4,计算的是所含元素的个数。
三 strlen和sizeof
1.适用范围
sizeof:
1.计算数组所包含的字节数。
2.用于数据类型,如 sizeof (int)。
3.用于指针,根据编译器是X64 or X86, 得到 8 or 4。
strlen:
用于计算字符串长度。
2.sizeof和数组名
数组名通常代表首元素地址,但存在两个特殊情况。
1.sizeof中包含的数组名代表整个数组,因此得到的结果为整个数组包含的字节数
2.&arr代表整个数组的地址,而不代表首元素地址。当我们给它+1时会跳过整个数组。
- 两个十六进制数相减可以得到40,也就是arr包含的字节数。
四 题目实战
1.一维数组
//一维数组
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));//指针
printf("%d\n",sizeof(*a));//int类型
printf("%d\n",sizeof(a+1));//指针
printf("%d\n",sizeof(a[1]));//int类型
printf("%d\n",sizeof(&a));//指针
printf("%d\n",sizeof(*&a));//* 和 &可以看成相互抵消,等于sizeof(a)
printf("%d\n",sizeof(&a+1));//指针
printf("%d\n",sizeof(&a[0]));//指针
printf("%d\n",sizeof(&a[0]+1));//指针
运行结果:
-
当sizeof后面仅有首元素地址时,a代表整个数组,输出数组包含的所有字节数,因此第一个为16。但是如果改变为 printf("%d\n",sizeof(a+0)); 此时a就代表首元素地址。
-
这串代码在X86环境下运行,因此sizeof指针为8, sizeof(int)类型的是4
-
a[2] 可以看成 *(a + 2)。
2.字符数组
//字符数组
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//arr占据的全部空间
printf("%d\n", sizeof(arr+0));//指针
printf("%d\n", sizeof(*arr));// 首元素'a'
printf("%d\n", sizeof(arr[1]));//首元素'a'
printf("%d\n", sizeof(&arr));//指针
printf("%d\n", sizeof(&arr+1));//指针
printf("%d\n", sizeof(&arr[0]+1));//指针
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));//随机值
运行结果
-
用这种方式定义arr时,数组的最后没有 ‘\0’ ,因此strlen(指针) 返回值无法确定,返回随机值。
-
strlen接收指针,无法读取*arr和arr[1]。
-
为什么&arr+1明明越界了还能输出呢?
因为sizeof是一个关键字,而不是函数,里面的内容并不会运算。
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//abcdef占的空间+'\0'
printf("%d\n", sizeof(arr+0));//首元素地址
printf("%d\n", sizeof(*arr));//字符a
printf("%d\n", sizeof(arr[1]));//字符a
printf("%d\n", sizeof(&arr));//指针
printf("%d\n", sizeof(&arr+1));//指针
printf("%d\n", sizeof(&arr[0]+1));//指针
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
运行结果:
-
以char arr[] = " abcdef " ; 定义的字符串会在末尾自动加上’ \0 ',sizeof也会加上它所占的空间。
-
&arr+1跳过了’ \0 ',所以不知道在哪里停止,输出随机值。
char *p = "abcdef";
printf("%d\n", sizeof(p));//指针(此时不是数组名)
printf("%d\n", sizeof(p+1));//指针
printf("%d\n", sizeof(*p));//首元素a
printf("%d\n", sizeof(p[0]));//首元素a
printf("%d\n", sizeof(&p));//指针
printf("%d\n", sizeof(&p+1));//指针
printf("%d\n", sizeof(&p[0]+1));//指针
printf("%d\n", strlen(p));//元素个数
printf("%d\n", strlen(p+1));//元素个数-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));//元素个数-1
- p为指针并且指向字符串首元素的地址。
运行结果:
- 不要把指针当做数组名
3.二维数组
//二维数组
int a[3][4] = {0};
printf("%d\n",sizeof(a));//数组名单独在sizeof中代表整个数组
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));//等于a+1
printf("%d\n",sizeof(*(&a[0]+1)));//等于*(a+1)
printf("%d\n",sizeof(*a));//第一行的数组名
printf("%d\n",sizeof(a[3]));//表示一个包含四个元素数组的数组名
运行结果:
-
这道题有点复杂,我们画个图来理解。
-
左边是一个3*4的二维数组(内存中是连续的,这样画是为了方便理解),第一行的数据可以用 a[0][j] 表示,j的范围是0~3。由此我们可以类比旁边的一维数组,我们把二维数组看成三个一维数组,然后就可以假设——a[0]就是第一行这个“一维数组”的数组名。同理,a[1]就是第二行数组的数组名。
-
a是二维数组的数组名,也就是数组首元素的地址,我们已经知道二维数组的首元素是a[0],那么a就是a[0]的地址即 a = &a[0]。