【C语言】sizeof与strlen在指针和数组上的作用


一、sizeof

sizeof是C语言的一种 单目操作符 不是函数,如C语言的其他操作符++、–等。它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定。

例如:
sizeof(type)
sizeof(int)=4

注:sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。

二、strlen

头文件:string.h
库函数 size_t strlen(const char *str) 计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。

 size_t strlen(const char *str)

在这里插入图片描述

注:sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小,并以字符’\0’为结束标志,遇到’\0’立即停止。

三、比较:

  • sizeof 是计算对象或者类型创建的对象所占内存空间的大小,单位是字节 sizeof 是操作符,不是函数。
  • strlen 求字符串长度的,计算的是字符串中\0之前出现的字符的个数 统计到\0为止,如果没有看到\0,会继续往后找 strlen, 是库函数。

四、实例:


//关于数组名
//数组名是数组首元素的地址
//但是有2个例外:
//1. sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小,单位是字节
//2. &数组名 - 数组名也表示整个数组,取出的是整个数组的地址
//除了这个2个例外,你见到的所有的数组名都表示首元素的地址
//& - 取地址操作符
//* - 解引用操作符

int main()
{
	int a[] = { 1,2,3,4 };
	//int* p = a;
	//int (*pa)[4] = &a;
	//printf("%p\n", p);
	//printf("%p\n", p+1);

	//printf("%p\n", pa);
	//printf("%p\n", pa+1);

	//a  - int*
	//&a - int (*)[4]

	printf("%d\n", sizeof(a));//16,a作为数组名单独放在sizeof内部,计算的是数组的总大小,单位是字节
	printf("%d\n", sizeof(a + 0));//a并非单独放在sizeof内部,也没有&,所以数组名a就是数组首元素的地址
	//a+0还是数组首元素的地址,是地址大小就是 4/8 个字节
	printf("%d\n", sizeof(*a));//a是首元素的地址,*a就是首元素,sizeof(*a)就算的就是首元素的大小 - 4
	//a  - int*
	//*a - int
	printf("%d\n", sizeof(a + 1));//a是首元素的地址,a+1是第二个元素的地址,sizeof(a+1)计算的是指针的大小 - 4/8
	//a - int*
	//a+1, 跳过一个int
	printf("%d\n", sizeof(a[1]));//a[1]就是数组的第二个元素,sizeof(a[1])的大小 - 4个字节
	printf("%d\n", sizeof(&a));//&a取出的数组的地址,数组的地址,也是地址呀,sizeof(&a)就是 4/8 个字节

	printf("%d\n", sizeof(*&a));//&a是数组的地址,是数组指针类型,*&a是都数组指针解引用,访问一个数组的大小
	//16字节
	//sizeof(*&a) ==> sizeof(a)  =16
	
	printf("%d\n", sizeof(&a + 1));//&a数组的地址,&a+1跳过整个数组,&a+1还是地址,是 4/8 个字节
	printf("%d\n", sizeof(&a[0]));//a[0]是数组的第一个元素,&a[0]是第一个元素的地址,是 4/8 个字节
	printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一个元素的地址,&a[0]+1就是第二个元素的地址,是 4/8 个字节

	//&a[0] - int*
	//&a[0]+1 -> &a[1]

	return 0;
}

如sizeof(&a + 1):取地址取的是整个数组的地址,&a+1则是跳过了整个数组,也就指向末尾元素,而sizeof(a+1)则是以a的类型int*为标准,所以a+1, 跳过一个int,也就是第二个元素的地址

在这里插入图片描述

在这里插入图片描述

注:凡是地址在x86和32位机器都是4个字节,在64四位机器下是8个字节


字符串也和整数数组差不多

#include <string.h>

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };

	printf("%d\n", strlen(arr));//随机值,arr是数组名,但是没有放在sizeof内部,也没&,arr就是首元素的地址
	//strlen得到arr后,从arr数组首元素的地方开始计算字符串的长度,直到直到\0,但是arr数组中没有\0,arr内存的后边是否有\0,在什么位置
	//是不确定的,所以\0之前出现了多少个字符是随机的。
	//
	printf("%d\n", strlen(arr + 0));//arr是数组首元素的地址,arr+0还是首元素的地址
	//随机值

	//printf("%d\n", strlen(*arr));//arr是数组首元素的地址,*arr 是首元素 - ‘a’ - 97
	//strlen就把‘a’的ASCII码值 97 当成了地址
	//err 会非法访问内存
	 
	//printf("%d\n", strlen(arr[1]));//arr[1] - 'b' - 98 - err

	printf("%d\n", strlen(&arr));//随机值,&arr是数组的地址,数组的地址也是指向数组起始位置,和第一个案例一样
	printf("%d\n", strlen(&arr + 1));//随机值
	printf("%d\n", strlen(&arr[0] + 1));//随机值


	printf("%d\n", sizeof(arr));//arr是数组名,并且是单独放在sizeof内部,计算的是数组总大小,单位是字节 - 6
	printf("%d\n", sizeof(arr + 0));//arr是数组名,并非单独放在sizeof内部,arr表示首元素的地址,arr+0还是首元素的地址
	//是地址大小就是4/8
	
	printf("%d\n", sizeof(*arr));//arr是首元素的地址,*arr就是首元素,sizeof计算的是首元素的大小,是1字节
	printf("%d\n", sizeof(arr[1]));//arr[1]是数组的第二个元素,sizeof(arr[1])计算的是第二个元素的大小,1个字节
	printf("%d\n", sizeof(&arr));//&arr- 取出的是数组的地址,sizeof(&arr))计算的是数组的地址的大小,是地址就是4/8字节
	printf("%d\n", sizeof(&arr + 1));//&arr是数组的地址,&arr+1跳过整个数组,指向'f'的后边,&arr+1的本质还是地址,是地址就是4/8字节
	printf("%d\n", sizeof(&arr[0] + 1));//&arr[0]是‘a’的地址,&arr[0]+1是'b'的地址,是地址就是4/8字节
	//&arr[0] - char*
	return 0;
}

在这里插入图片描述
在这里插入图片描述

注:strlen括号里面要存地址,不能放数据,不然会非法访问。strlen得到arr后,从arr数组首元素的地方开始计算字符串的长度,直到直到\0,但是arr数组中没有\0,arr内存的后边是否有\0,在什么位置是不确定的,所以\0之前出现了多少个字符是随机的。


int main()
{
	char* p = "abcdef";

	printf("%d\n", strlen(p));//*p是存地址的,p是首元素地址,大小是6个字节
	printf("%d\n", strlen(p + 1));//如果p并非单独放在里面,则表示的首元素地址,p+1则是跳p的类型char的一个字节,指向p[1], 大小是5个字节
	/*printf("%d\n", strlen(*p));*///*p=p[0]='a'=97,不是地址,访问错误
	/*printf("%d\n", strlen(p[0]));*/
	printf("%d\n", strlen(&p));//取整个字符串的地址,6个字节
	printf("%d\n", strlen(&p + 1));//同上所说,跳过了整个字符数组,出现随机值
	printf("%d\n", strlen(&p[0] + 1));//也是&P[0]+1=&P[1],5个字节

	printf("%zu\n", sizeof(p));//*p是存地址的,p是首元素地址,凡是地址就是4/8字节
	printf("%zu\n", sizeof(p + 1));//p+1则指向p[1]的地址,4/8字节
	printf("%zu\n", sizeof(*p));//*p表示的首元素的数据p[0]='a',char的类型则是1字节
	printf("%zu\n", sizeof(p[0]));//p[0]='a',char的类型则是1字节
	printf("%zu\n", sizeof(&p));//取地址p也是取的*p的地址,相当于char* *pp=&p,凡是地址就是4/8字节
	printf("%zu\n", sizeof(&p + 1));//&p+1则是跳过这个地址,也还是地址,凡是地址就是4/8字节
	printf("%zu\n", sizeof(&p[0] + 1));//&P[0]+1=&P[1],凡是地址就是4/8字节

	return 0;
}

在这里插入图片描述
注意:指针就是用来存放地址的!


#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]));//a[0][0]是一个整型元素,大小是4个字节
	printf("%d\n", sizeof(a[0]));//把二维数组的每一行看做一维数组的时候,a[0]是第一行的数组名,第一行的数组名单独放在sizeof内部
	//计算的是第一行的总大小,单位是字节 - 16
	printf("%d\n", sizeof(a[0] + 1));//a[0]虽然是第一行的数组名,但是并非单独放在sizeof内部
	//a[0]作为第一行的数组名并非表示整个第一行这个数组,a[0]就是第一行首元素的地址,a[0]--> &a[0][0] - int*
	//a[0]+1,跳过一个int,是a[0][1]的地址  4/8字节
	printf("%d\n", sizeof(*(a[0] + 1)));//a[0]+1是第一行第二个元素的地址,所以*(a[0]+1)就是a[0][1],大小是4个字节
	
	printf("%d\n", sizeof(a + 1));//a是二维数组的数组名,没单独放在sizeof内部,也没有&,所以a就是数组首元素的地址
	//二维数组,我们把它想象成一维数组,它的第一个元素就是二维数组的第一行
	//a就是第一行的地址,a+1 是第二行的地址,是地址,大小就是 4/8 个字节
	//a - &a[0]
	//a+1 - &a[1]
	//a+2 - &a[2]

	printf("%d\n", sizeof(*(a + 1)));//a+1是第二行的地址,*(a+1) 找到的就是第二行,sizeof(*(a + 1))计算的就是第二行的大小
	//16
	//*(a+1) --> a[1]
	//sizeof(*(a + 1)) --> sizeof(a[1])
	//
	printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一行的地址,&a[0]+1就是第二行的地址,sizeof(&a[0] + 1)计算的第二行地址大小
	//单位是字节 - 4/8

	printf("%d\n", sizeof(*(&a[0] + 1)));//&a[0] + 1是第二行的地址,*(&a[0] + 1)拿到的就是第二行,大小就是16个字节
	//*(&a[0]+1) --> a[1]

	printf("%d\n", sizeof(*a));//a表示首元素的地址,就是第一行的地址 - &a[0]
	//*a - 拿到的就是第一行 - 大小就是16个字节
	//*a -> *(a+0) -> a[0]
	//
	printf("%d\n", sizeof(a[3]));//代码没问题
	//a[3]是二维数组的第4行,虽然没有第四行,但是类型能够确定,大小就是确定的。大小就是一行的大小,单位是字节 - 16
	//能够分析出 a[3]的类型是:int [4]
	// 
	//任何一个表达式有2个属性
	//3+5
	//值属性:8
	//类型属性:int

	return 0;
}

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SuhyOvO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值