【C语言】:sizeof和strlen对比_超详解

1、sizeof和strlen的对比

1.1 sizeof

sizeof 计算的是变量所占内存内存空间的⼤⼩,单位是字节。如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的⼤⼩。

注意:sizeof 只关注占⽤内存空间的⼤⼩,不关注内存中存放什么数据。

#include<stdio.h>
int main()
{
	int a = 7;
	short s = 4;
	printf("%d\n", sizeof(s = a + 2));//2
	printf("%d\n", s);//4
	return 0;
}

为什么上面这个例子运行出的结果是2和4呢?从这个例子我们就可以明显察觉到sizeof只关注数据的类型,我们这里来解释一下。

a是整型,2也是整型,两者相加为整型;再将其赋给short类型的s,结果还是short类型,short类型占2个字节的空间,因此第一个printf输出结果为2。将a与2的和赋值给s,没有用sizeof计算其内存空间大小,因此第二个printf输出结果为s的值为4。

1.2 strlen

strlen 是C语⾔库函数,功能是求字符串⻓度。函数原型如下:

size_t strlen ( const char * str );

统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。
strlen 函数会⼀直向后找 \0 字符,直到找到为⽌,所以可能存在越界查找。

#include<stdio.h>
#include<string.h>
int my_strlen(char* str)
{
	int count = 0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	char arr[] = "abc";
	int ret = my_strlen(arr);
	printf("%u\n", ret);
	return 0;
}

1.3 sizeof 和 strlen的对比

sizeofstrlen
1. sizeof是操作符1. strlen是库函数,使⽤需要包含头⽂件 string.h
2. sizeof计算操作数所占内存的⼤⼩,单位是字节2. srtlen是求字符串⻓度的,统计的是 \0 之前字符的隔个数
3. 不关注内存中存放什么数据3. 关注内存中是否有 \0 ,如果没有 \0 ,就会持续往后找,可能会越界

2、数组和指针试题解析

2.1 一维数组

#include<stdio.h>
int mian()
{
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));
	return 0;
}
//数组名单独放在sizeof的内部,表示的是整个数组的大小
//int是整型,占4个字节,一个数组a有4个元素,因此4*4=16
printf("%d\n", sizeof(a + 0));
//数组名是数组首元素的地址,a+0=a还是首元素的地址,地址的大小是4/8个字节
printf("%d\n", sizeof(*a));
//数组名是数组首元素的地址,*a就是首元素,a的每个元素是int类型,因此大小是4个字节
printf("%d\n",sizeof(a+1));
//数组名是数组首元素的地址,a+1代表数组中的第二个元素的地址,是地址大小就为4/8个字节
printf("%d\n",sizeof(a[1]));
//a[1]代表数组下标为1的那个元素,也就是数组中第二个元素的大小,为4个字节
printf("%d\n",sizeof(&a));
//&a是数组的地址,是地址就为4/8个字节
printf("%d\n",sizeof(*&a));
//*&a等价于a,他的类型是int(*)[4],计算的是整个数组的大小,为4*4=16个字节
printf("%d\n",sizeof(&a+1));
//&a+1相对于取地址a是跳过了整个数组,但是&a+1任然是地址,是地址就为4/8个字节
printf("%d\n",sizeof(&a[0]));
//&a[0]是指数组下标为0,也就是首元素的地址,是地址就为4/8个字节
printf("%d\n",sizeof(&a[0]+1));
//&a[0]+1表示数组中第二个元素的地址,是地址就为4/8个字节

我们这里运行验证一下:

#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;
}

在这里插入图片描述

2.2 字符数组

  • 代码1
#include<stdio.h>
int main()
{
	char a[]={'a','b','c','d','e','f'};
	printf("%d\n",sizeof(a));
	return 0;
}
//数组名单独放在数组的内部,表示的是整个数组的大小
//char是字符数据类型,占一个字节,一个数组有6个元素,因此占1*6=6个字节
printf("%d\n",sizeof(a+0));
//a没有单独放在sizeof的内部,a+0表示数组首元素的地址,是地址就为4/8个字节
printf("%d\n",sizeof(*a));
//a表示数组首元素的地址,*a就表示首元素,占1个字节
printf("%d\n",sizeof(a[1]));
//a[1]表示数组下标为1,也就是第二个元素,占1个字节
printf("%d\n",sizeof(&a));
//&a是数组的地址,是地址就为4/8个字节
printf("%d\n",sizeof(&a+1));
//&a+1表示跳过整个数组后的地址,是地址就为4/8个字节
printf("%d\n",sizeof(&a[0]+1));
//&a[0]表示首元素的地址,+1就为第二个元素的地址,是地址就为4/8个字节

最后运行看一下结果:

#include<stdio.h>
int main()
{
	char a[] = { 'a','b','c','d','e','f' };
	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));
	printf("%d\n", sizeof(&a + 1));
	printf("%d\n", sizeof(&a[0] + 1));
	return 0;
}

在这里插入图片描述
测试过sizeof后,我们用同样的方法来测试一下strlen。

strlen的作用是求字符串的长度,他统计的是字符串中’\0’之前的个数,遇到’\0’就停止。

  • 代码2
#include<stdio.h>
int main()
{
	char a[] = { 'a','b','c','d','e','f' };
	printf("%d\n",strlen(a));
	return 0;
}
//数组a中没有'\0',因此打印结果是一个随机值
printf("%d\n",strlen(a+0));
//数组名是数组首元素的地址,a+0还是数组首元素的地址,是地址大小就为4/8个字节
printf("%d\n",strlen(*a));
//*a表示数组的首元素,数组首元素为'a',a的ASCLL码值为97,错误写法

上面这个代码中我们需要注意的是,strlen函数参数的部分需要传一个地址,当传递的是’a’时,'a’的ASCLL码值是97,就是将97当作地址传参。

strlen就会从97这个地址开始统计字符串的长度,这就会造成非法访问了,因此这种写法是错误的。

printf("%d\n",strlen(a[1]));
//a[1]表示数组下标为1的元素,也就是'b',b的ASCLL码值是98,也是错误写法
printf("%d\n",strlen(&a));
//&a表示整个数组的地址,数组的地址和首元素的地址的值是一样的
//那么传递给strlen函数后,依然是从数组的第一个元素的位置开始往后数,没有'\0',因此为随机值
printf("%d\n",strlen(&a+1));
//&a+1表示跳过一个数组,从最后一个元素的位置往后数,为随机值
printf("%d\n",strlen(&a[0]+1));
//&a[0]+1表示数组中第二个元素,从第二个元素的位置往后数,为随机值

我们运行起来验证一下:

#include<stdio.h>
#include<string.h>
int main()
{
	char a[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(a));
	printf("%d\n", strlen(a + 0));
	//printf("%d\n", strlen(*a));  
	//printf("%d\n", strlen(a[1]));
	printf("%d\n", strlen(&a));
	printf("%d\n", strlen(&a + 1));
	printf("%d\n", strlen(&a[0] + 1));
	return 0;
}

在这里插入图片描述

当数组是连续的字符串时,我们可以对比一下sizeof和strlen用法的不同。

  • 代码3
#include<stdio.h>
int main()
{
	char a[] = "abcdef";
	printf("%d\n", sizeof(a));
	return 0;
}
//数组是char[7]类型,一个元素占一个字节,因此整个数组占7个字节
printf("%d\n", sizeof(a+0));
//a+0代表数组首元素的地址,是地址就为4/8个字节
printf("%d\n", sizeof(*a));
//a代表数组首元素的地址,*a就代表数组的首元素,大小为1个字节
printf("%d\n", sizeof(a[1]));
//a[1]代表数组下标为1也就是数组中第二个元素,大小为1个字节
printf("%d\n", sizeof(&a));
//&a表示整个数组的地址,是地址就为4/8个字节
printf("%d\n", sizeof(&a+1));
//&a+1表示跳过整个数组的地址,是地址就为4/8个字节
printf("%d\n", sizeof(&a[0]+1));
//&a[0]+1表示第二个元素的地址,是地址就为4/8个字节

最后运行验证一下:

#include<stdio.h>
int main()
{
	char a[] = "abcdef";
	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));
	printf("%d\n", sizeof(&a + 1));
	printf("%d\n", sizeof(&a[0] + 1));
	return 0;
}

在这里插入图片描述

  • 代码4
#include<stdio.h>
#include<string.h>
int main()
{
	char a[] = "abcdef";
	printf("%d\n", strlen(a));
	return 0;
}
//数组a中在f后面有'\0',可得长度为6
printf("%d\n", strlen(a+0));
//数组名表示数组首元素的地址,向后数遇\0停,长度为6
printf("%d\n", strlen(*a));
//*a表示首元素字符'a',错误写法
printf("%d\n", strlen(a[1]));
//a[1]表示数组下标为1的元素,即'b',也是错误写法
printf("%d\n", strlen(&a));
//&a表示首元素的地址,向后数遇\0停,即大小为6
printf("%d\n", strlen(&a+1));
//&a表示首元素的地址,+1表示跳过整个数组,往后数结果为随机值
printf("%d\n", strlen(&a[0]+1));
//&a[0]表示首元素的地址,&a[0]+1表示第二个元素的地址
//从第二个元素往后数遇\0停,大小为5

运行验证一下:

#include<stdio.h>
#include<string.h>
int main()
{
	char a[] = "abcdef";
	printf("%d\n", strlen(a));
	printf("%d\n", strlen(a + 0));
	//printf("%d\n", strlen(*a));
	//printf("%d\n", strlen(a[1]));
	printf("%d\n", strlen(&a));
	printf("%d\n", strlen(&a + 1));
	printf("%d\n", strlen(&a[0] + 1));
	return 0;
}

在这里插入图片描述

  • 代码5
#include<stdio.h>
int main()
{
	char* p = "abcdef";
	printf("%d\n", sizeof(p));
	return 0;
}
//p是一个指针变量,指向首元素的地址,是地址大小就是4/8个字节
printf("%d\n", sizeof(p+1));
//p指向a,p+1跳过一个字符,就是指向b的地址,是地址就是4/8个字节
printf("%d\n", sizeof(*p));
//p是首元素的地址,*p就指向首元素字符'a',大小是1个字节
printf("%d\n", sizeof(p[0]));
//p[0]等价于*(p+0)等价于(*p),指向a,1个字节
printf("%d\n", sizeof(&p));
//&p取出的是地址,是地址就为4/8个字节
printf("%d\n", sizeof(&p+1));
//&p+1表示取跳过一个数组后的地址,是地址就为4/8个字节
printf("%d\n", sizeof(&p[0]+1));
//p[0]等价于*p表示字符'a',&p[0]表示取出字符a的地址
//+1表示跳过一个字符到'b',即指向b的地址,是地址就为4/8个字节

运行验证结果:

#include<stdio.h>
int main()
{
	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));
	printf("%d\n", sizeof(&p + 1));
	printf("%d\n", sizeof(&p[0] + 1));
	return 0;
}

在这里插入图片描述

  • 代码6
#include<stdio.h>
int main()
{
	char* p = "abcdef";
	printf("%d\n", strlen(p));
	return 0;
}
//指针变量p指向a的地址,从a开始数,遇\0停,长度为6
printf("%d\n", strlen(p+1));
//p指向的是a的地址,p+1就跳过一个字符指向b,从b往后数遇\0停,长度为5
printf("%d\n", strlen(*p));
//p表示指向a的地址,*p就表示a,a不能作为地址,错误写法
printf("%d\n", strlen(p[0]));
//p[0]等价于*p,通过p拿到第一个元素'a',不能作为地址,也是错误写法
printf("%d\n", strlen(&p));
//p存放的是首元素的地址,&p值从地址开始往后数,遇不到\0,因此为随机值
printf("%d\n", strlen(&p+1));
//同上,随机值
printf("%d\n", strlen(&p[0]+1));
//&p[0]表示a的地址,+1就是b的地址,往后数遇\0停,长度为5

运行验证结果:

#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;
}

在这里插入图片描述

2.3 二维数组

#include<stdio.h>
int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));
	return 0;
}
//二维数组为int类型,一个元素所占4个字节
//因此总占3*4*4=48个字节
printf("%d\n", sizeof(a[0][0]));
//a[0][0]表示0行0列的元素,大小为4个字节
printf("%d\n", sizeof(a[0]));
//对于一个二维数组a来说,a[0]表示的就是第一行这个一维数组的数组名
//因此就算作将数组名单独放在sizeof的内部了,计算的是整个数组的大小
//大小为4*4=16个字节
printf("%d\n", sizeof(a[0]+1));
//a[0]作为第一行的数组名,没有单独放在sizeof内部,没有取地址
//a[0]表示数组名首元素的地址,也就是a[0][0]的地址
//a[0][0]的类型是int*,+1表示跳过一个整型
//a[0]+1是第一行第二个元素的地址,是地址就为4/8个字节
printf("%d\n", sizeof(*(a[0]+1)));
//计算的是第一行第二个元素的大小,为4个字节
printf("%d\n", sizeof(a+1));
//a是首元素的地址,是第一行的地址,a+1就是第二行的地址,是地址就为4/8个字节
//类型是int(*)[4]
printf("%d\n", sizeof(*(a+1)));
//a+1是第一行的地址,类型是int(*)[4],是数组指针
//*(a+1)对数组指针进行解引用操作,访问的是第二行的数组
//大小为4*4=16ge字节
printf("%d\n", sizeof(&a[0]+1));
//&a[0]是第一行的地址,&a[0]+1表示第二行的地址,是地址就为4/8个字节
printf("%d\n", sizeof(*(&a[0]+1)));
//&a[0]+1表示第二行的地址,*(&a[0]+1)对第二行进行解引用
//表示第二行的大小,为4*4=16个字节
printf("%d\n", sizeof(*a));
//a表示数组首元素的地址,也就是第一行的地址
//*a就表示第一行d大小,为4*4=16个字节
printf("%d\n", sizeof(a[3]));
//数组a有三行四列,其中第三行的下标是a[2],因此这句话越界访问了
//但是sizeof只关注类型,不会真的计算,而a[3]的类型是int[4]
//所以其大小为4*4=16个字节

我们最后运行验证一下:

#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]));


	return 0;
}

在这里插入图片描述

  • 14
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
`sizeof` 和 `strlen` 是两个在C语言中常用的操作符,用于获取变量或数据的信息。 1. `sizeof`: - `sizeof` 是一个关键字,用于获取数据类型或变量所占用的字节数。 - 它在编译时就能够确定,不需要运行时计算。 - `sizeof` 返回的结果是一个 `size_t` 类型的无符号整数。 - `sizeof` 可以用于计算数据类型、数组、结构体、联合体以及指针等的大小。 示例代码: ```c int num = 10; size_t size = sizeof(num); printf("Size of num: %zu bytes\n", size); int arr[5]; size_t arrSize = sizeof(arr); printf("Size of arr: %zu bytes\n", arrSize); ``` 输出: ``` Size of num: 4 bytes Size of arr: 20 bytes ``` 2. `strlen`: - `strlen` 是一个函数,用于计算字符串的长度,即字符串中字符的个数,不包括终止符 `\0`。 - 它需要在运行时遍历字符串中的字符来计算长度,因此时间复杂度为 O(n),n 是字符串的长度。 - `strlen` 返回的结果是一个 `size_t` 类型的无符号整数。 示例代码: ```c char str[] = "Hello, World!"; size_t length = strlen(str); printf("Length of str: %zu\n", length); char emptyStr[] = ""; size_t emptyLength = strlen(emptyStr); printf("Length of emptyStr: %zu\n", emptyLength); ``` 输出: ``` Length of str: 13 Length of emptyStr: 0 ``` 需要注意的是,`sizeof` 和 `strlen` 的作用不同,`sizeof` 是用于获取数据类型或变量的大小,而 `strlen` 是用于计算字符串的长度。在使用 `strlen` 时要确保字符串以 `\0` 结尾,否则可能导致计算结果不准确。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值