【sizeof与strlen:内存计算与字符串长度的奥秘】

一.sizeof

  1. sizeof是用于计算变量类型所占内存内存空间⼤⼩的操作符,单位是字节
    注意:sizeof是操作符,不是库函数!!!

  2. sizeof 只关注占⽤内存空间的⼤⼩,不在乎内存中存放什么数据。

  3. sizeof不进行计算。

  4. sizeof返回值是size_t类型。

下面举一个例子:

int main()
{
	int m = 2;
	int n = 10;
	printf("%zd\n", sizeof(n));
	printf("%zd\n", sizeof n);
	printf("%zd\n", sizeof(int));
	printf("%zd\n", sizeof(m + n));
	return	0;
}

运行截图如下:
在这里插入图片描述

二. strlen

  1. strlen是用于计算字符串长度的库函数。使用时需要包含头文件string.h

  2. strlen是从给定地址开始,向后统计 ‘\0’ 之前字符串中字符的个数。由此可见,strlen是关注内存中所存放数据的。

  3. strlen所统计的字符串中必须存在’\0’,否则会出现越界访问情况。

  4. strlen返回值是size_t类型。

下面举一个例子:

#include<stdio.h>
#include<string.h>

int main()
{
	char arr1[] = { "abcdefg" };
	char arr2[] = { 'a','b','c','d','e','f','g','\0'};
	char arr3[] = { 'a','b','c','d','e','f','g'};
	printf("%zd\n", strlen(arr1));
	printf("%zd\n", strlen(arr2));
	printf("%zd\n", strlen(arr3));
	return	0;
}

运行截图如下:
在这里插入图片描述

三.sizeof和strleen练习

做练习前,先补充一些知识:
数组名的含义:

  1. sizeof(数组名),这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩。

  2. &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址

  3. 除此之外所有的数组名都表⽰⾸元素的地址

内存大小:
1.char占一个字节。
2.int占4个字节。
3.地址占4或8个字节。

下面举一个例子:

int main()
{
	int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%zd\n", sizeof(a));//打印数组a的内存大小
	printf("%p\n", a);//打印a的首元素的地址
	printf("%p\n", a+1);//相比a多4
	printf("%p\n", &a);//打印整个数组a的地址
	printf("%p\n", &a+1);//相比&a多40
	printf("%d\n", a[0]); //打印a的首元素
	return 0;
}

运行截图如下:
在这里插入图片描述

  1. 一维数组
    试题如下:
int main()
{
	int a[] = { 1,2,3,4 };
	printf("%zd\n", sizeof(a));
	printf("%zd\n", sizeof(a + 0));
	printf("%zd\n", sizeof(*a));
	printf("%zd\n", sizeof(a + 1));
	printf("%zd\n", sizeof(a[1]));
	printf("%zd\n", sizeof(&a));
	printf("%zd\n", sizeof(*&a));
	printf("%zd\n", sizeof(&a + 1));
	printf("%zd\n", sizeof(&a[0]));
	printf("%zd\n", sizeof(&a[0] + 1));
	return 0;
}

解析如下:

int main()
{
	int a[] = { 1,2,3,4 };
	printf("%zd\n", sizeof(a));//打印整个数组a的大小
	printf("%zd\n", sizeof(a + 0));//a+0放在一起,a表示数组首元素地址,a+0打印数组首元素地址大小
	printf("%zd\n", sizeof(*a));//a在这里表示数组首元素地址,相当于&a[0],*a就相当于a[0],打印第一个元素的内存大小
	printf("%zd\n", sizeof(a + 1));//与a+0同理,a+1放在一起,a表示数组首元素地址,a+1打印数组第二个元素地址大小
	printf("%zd\n", sizeof(a[1]));//与a[0]同理,打印数组第二个元素大小
	printf("%zd\n", sizeof(&a));//打印整个数组a的地址大小
	printf("%zd\n", sizeof(*&a));//a先与&结合,&a为整个数组a的地址,则*&a就是整个数组a,打印整个数组a的大小
	printf("%zd\n", sizeof(&a + 1));//与&a同理,打印整个数组a后面的地址大小
	printf("%zd\n", sizeof(&a[0])); //打印第一个元素的地址大小
	printf("%zd\n", sizeof(&a[0] + 1));//与&a同理,打印第二个元素的地址大小
	return 0;
}

运行截图如下:
在这里插入图片描述

  1. 字符数组
    试题如下:
    这里为了观看代码方便,所以arr重复定义了,
    运行结果截图,我会分开放置.

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

解析如下:

#include<stdio.h>
#include<string.h>
int main()
{
	//代码1:
	char arr[] = { 'a','b','c','d','e','f' };//没有'\0'
	printf("%zd\n", sizeof(arr));//打印整个数组arr的内存大小——6
	printf("%zd\n", sizeof(arr + 0));//arr+0放在一起,arr表示数组首元素地址,arr+0打印数组首元素地址大小——4或8
	printf("%zd\n", sizeof(*arr));//arr在这里表示数组首元素地址,相当于&arr[0],*arr就相当于arr[0],打印第一个元素的内存大小——1
	printf("%zd\n", sizeof(arr[1]));//与arr[0]同理,打印数组第二个元素大小——1
	printf("%zd\n", sizeof(&arr));//打印整个数组arr的地址大小——4或8
	printf("%zd\n", sizeof(&arr + 1));//与&arr同理,打印整个数组arr后面的地址大小——4或8
	printf("%zd\n", sizeof(&arr[0] + 1));//相当于a+1,打印第二个元素的地址大小——4或8
	printf("%zd\n", strlen(arr));//arr表示数组首元素地址,这里表示从数组首元素地址开始,向后统计元素个数,直到遇到'\0',但数组中没有'\0',故越界访问打印随机值
	printf("%zd\n", strlen(arr + 0));//与arr同理,打印随机值
	//printf("%zd\n", strlen(*arr));//*arr表第一个元素,这里把元素作为地址传给strlen,而strlen需要传指针,会打印错误(已注释)
	//printf("%zd\n", strlen(arr[1]));//与*arr同理,会打印错误(已注释)
	printf("%zd\n", strlen(&arr));//&arr表示整个数组的地址,这里仍表示从数组首元素地址开始,向后统计元素个数,直到遇到'\0',但数组中没有'\0',故越界访问打印随机值
	printf("%zd\n", strlen(&arr + 1));//与&arr同理,&arr+1表示整个数组后面的地址,这里表示从整个数组后面的地址开始,向后统计元素个数,直到遇到'\0',故越界访问打印随机值
	printf("%zd\n", strlen(&arr[0] + 1));//与arr+0同理,&arr[0]+1相当于arr+1,表示数组第二个元素的地址,即从第二个元素的地址开始,向后统计元素个数,直到遇到'\0',但数组中没有'\0',故越界访问打印随机值
	//代码2:
	char arr[] = "abcdef";//有'\0'
	printf("%zd\n", sizeof(arr));//打印整个数组arr的内存大小(包括'\0',后面同理)——7
	printf("%zd\n", sizeof(arr + 0));//arr+0放在一起,arr表示数组首元素地址,arr+0打印数组首元素地址大小——4或8
	printf("%zd\n", sizeof(*arr));//arr在这里表示数组首元素地址,相当于&arr[0],*arr就相当于arr[0],打印第一个元素的内存大小——1
	printf("%zd\n", sizeof(arr[1]));//与arr[0]同理,打印数组第二个元素大小——1
	printf("%zd\n", sizeof(&arr));//打印整个数组arr的地址大小——4或8
	printf("%zd\n", sizeof(&arr + 1));//与&arr同理,打印整个数组arr后面的地址大小——4或8
	printf("%zd\n", sizeof(&arr[0] + 1));//相当于a+1,打印第二个元素的地址大小——4或8
	printf("%zd\n", strlen(arr));//arr表示数组首元素地址,这里表示从数组首元素地址开始,向后统计元素个数,直到遇到'\0'(不包括'\0',后面同理)。——6
	printf("%zd\n", strlen(arr + 0));//与arr同理,这里表示从数组首元素地址开始,向后统计元素个数,直到遇到'\0'。——6
	//printf("%zd\n", strlen(*arr));//*arr表第一个元素,这里把元素作为地址传给strlen,而strlen需要传指针,会打印错误(已注释)
	//printf("%zd\n", strlen(arr[1]));//与*arr同理,会打印错误(已注释)
	printf("%zd\n", strlen(&arr));//&arr表示整个数组的地址,这里仍表示从数组首元素地址开始,向后统计元素个数,直到遇到'\0'。——6
	printf("%zd\n", strlen(&arr + 1));//与&arr同理,&arr+1表示整个数组后面的地址,这里表示从整个数组后面的地址开始,向后统计元素个数,直到遇到'\0',越界访问打印随机值。
	printf("%zd\n", strlen(&arr[0] + 1));//与arr+0同理,&arr[0]+1相当于arr+1,表示数组第二个元素的地址,即从第二个元素的地址开始,向后统计元素个数,直到遇到'\0'。——5
	//代码3:
	char* p = "abcdef";//相当于char* p[]={"abcdef"},但不等于
	printf("%zd\n", sizeof(p));//p存放的是字符串的地址,打印地址大小——4或8
	printf("%zd\n", sizeof(p + 1));//p是指针,存放的是地址,p+1存放的还是地址,是地址就是4或8
	printf("%zd\n", sizeof(*p));//对指针解引用,打印字符串首元素内存大小。——1
	printf("%zd\n", sizeof(p[0]));//表打印字符串内第一个元素大小——1
	printf("%zd\n", sizeof(&p));//p是指针,对指针去地址还是指针,里面存放的仍然是地址,是地址就打印4或8.
	printf("%zd\n", sizeof(&p + 1));//与&p同理,打印地址大小——4或8
	printf("%zd\n", sizeof(&p[0] + 1));//p[0]表字符串内第一个元素,&p[0]就表示字符串内第一个元素的地址,&p[0] + 1表第二个元素的地址,打印地址大小——4或8
	printf("%zd\n", strlen(p));//p字符串首元素地址,打印从字符串首元素到’\0’的元素个数——6
	printf("%zd\n", strlen(p + 1));//p+1字符串第二个元素地址,打印从字符串第二个元素到’\0’的元素个数——5
	//printf("%zd\n", strlen(*p));//*p表第一个元素,这里把元素作为地址传给strlen,而strlen需要传指针,会打印错误(已注释)
	//printf("%zd\n", strlen(p[0]));//p[0]相当于*p,会打印错误(已注释)
	printf("%zd\n", strlen(&p));//对整个字符串取地址,打印整个字符串元素个数——6
	printf("%zd\n", strlen(&p + 1));//与&p同理,打印整个字符串之后元素大小——越界访问随机值
	printf("%zd\n", strlen(&p[0] + 1));//与p+0同理,&p[0]+1相当于arr+1,表示数组第二个元素的地址,即从第二个元素的地址开始,向后统计元素个数,直到遇到'\0'。——5
	return 0;
}

运行截图如下:
代码1:
在这里插入图片描述
代码2:
在这里插入图片描述
代码3:
在这里插入图片描述

  1. 二维数组
    试题如下:
#include<stdio.h>
#include<string.h>

int main()
{
	int a[3][4] = { 0 };
	printf("%zd\n", sizeof(a));
	printf("%zd\n", sizeof(a[0][0]));
	printf("%zd\n", sizeof(a[0]));
	printf("%zd\n", sizeof(a[0] + 1));
	printf("%zd\n", sizeof(*(a[0] + 1)));
	printf("%zd\n", sizeof(a + 1));
	printf("%zd\n", sizeof(*(a + 1)));
	printf("%zd\n", sizeof(&a[0] + 1));
	printf("%zd\n", sizeof(*(&a[0] + 1)));
	printf("%zd\n", sizeof(*a));
	printf("%zd\n", sizeof(a[3]));
	return 0;
}

解析如下:

#include<stdio.h>
#include<string.h>

int main()
{
	int a[3][4] = { 0 };//3行4列
	//0 0 0 0
	//0 0 0 0
	//0 0 0 0
	printf("%zd\n", sizeof(a));//表示整个数组,打印整个数组内存大小——48
	printf("%zd\n", sizeof(a[0][0]));//打印第一行第一列元素大小——4
	printf("%zd\n", sizeof(a[0]));//a[0]表示第一行的元素,打印第一行内存大小——16
	printf("%zd\n", sizeof(a[0] + 1));//a[0]+1表示第一行第二个元素的地址,打印地址大小——4或8
	printf("%zd\n", sizeof(*(a[0] + 1)));//*(a[0] + 1)表示第一行第二个元素的元素,打印4
	printf("%zd\n", sizeof(a + 1));//表示数组第二行元素地址,打印第二行地址大小——4或8
	printf("%zd\n", sizeof(*(a + 1)));//表示数组第二行元素,打印第二行内存大小——16
	printf("%zd\n", sizeof(&a[0] + 1));//相当于a+1,打印第二行地址大小——4或8
	printf("%zd\n", sizeof(*(&a[0] + 1)));//相当于 *(a + 1),打印第二行内存大小——16
	printf("%zd\n", sizeof(*a));//表示数组首元素,即第一行元素,打印第一行内存大小——16
	printf("%zd\n", sizeof(a[3]));//越界访问,但仍能根据规律,打印16
	return 0;
}

运行截图如下:
在这里插入图片描述

四.总结

  1. sizeof是操作符,sizeof计算操作数所占内存的⼤⼩,单位是字节,不关注内存中存放什么数据.

  2. strlen是库函数,使⽤需要包含头⽂件 string.h,srtlen是求字符串⻓度的,统计的是 \0 之前字符的个数,关注内存中是否有 \0 ,如果没有 \0 ,就会持续往后找,可能越界。

第一次写,如果有什么问题请见谅,我只是写下自己所学的部分。
当然,有问题的话也欢迎批评指正,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值