[C语言]数组和指针的sizeof 与 strlen的输出

本次学习sizeofstrlen的输出

前提知识:

  • 有指针基础(学习过 指针数组、数组指针,函数指针)
  • 有数组基础(对 一维数组 与 二维数组 的 传参有了解)

这次学习有个非常非常非常重要的知识点,贯彻了整篇文章,请大家务必要牢记

大家都知道,数组名 是首元素的地址

但是有两个例外:

  1. sizeof(数组名),这里的数组名是表示整个数组的,计算的是整个数组的大小,单位是字节。

  2. &数组名,这里的数组名也表示整个数组,取出的是数组的地址

一定要牢记这两个例外

开始我们的练习,大家可以先不看我的注释,自己分析一下输出结果是多少。

​ 指针(地址)的大小是根据系统来定义的

32位(x86)的机器 指针大小为4个字节

64位(x64)的机器 指针大小为8个字节

第一轮 数组1

int main()
{
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));	//16            在sizeof中,单独存放一个数组名,表示整个数组的地址,所以得到的是整个数组的字节
	printf("%d\n", sizeof(a + 0));	//4 or 8	这里的a不是单独存放了,所以a示首元素的地址,a+0还是首元素的地址的 
	printf("%d\n", sizeof(*a));		//4			a表示首元素地址,*a是对首元素地址的解引用,也就是首元素
	printf("%d\n", sizeof(a + 1));	//4 or 8	表示第二个元素的地址,这里的a不是单独存放了,所以a示首元素的地址,+1后就是第二个元素的地址
	printf("%d\n", sizeof(a[1]));	//4		数组下标索引1,得到第二个元素
	printf("%d\n", sizeof(&a));	//4 or 8    表示是数组的地址,数组的地址也是地址,地址大小就是 4 or 8
	printf("%d\n", sizeof(*&a));    //16		1.可以理解为*和&相互抵消,*&a相当于a,所以sizeof(a) = 16;
								//2.&a是数组的地址,它的类型是int (*)[4] 数组指针,如果解引用,访问的就是4个int的数组,大小是16byte。  

        printf("%d\n", sizeof(&a + 1));	//4 or 8	&a是整个数组的地址,&a+1后跳过整个数组,虽然已经不是数组内的地址了,但越界的地址也是地址,地址也是4 or 8
	printf("%d\n", sizeof(&a[0]));	//8			&a[0]取出的就是第一个元素的地址
	printf("%d\n", sizeof(&a[0] + 1));//4		&a[0]+1 就是第二个元素的地址,地址大小就是4 or 8 byte
	return 0;
}

以上就是第一轮的分析,掌握了在进入下一轮

第二轮 数组2

本轮含有 strlen 求取字符串长度

再次普及一下:

  • strlen只能计算出 字符串 的长度,单位是byte,当 strlen 在字符串中找到 '\0' 后计算结束,计算的是 '\0' 之前出现了多少个字符,'0'是字符串的结束标志。需要导入头文件 :string.h
  • sizeof可以计算所有类型的长度,单位也是byte,但是sizeof在计算字符串时,会把 '\0' 也当作一个字符

这次着重看strlen,所以请掌握了第一轮的知识在进入下一轮。

#include <stdio.h>
#include <string.h)
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };//注意!!这个数组中的,都是字符,但并不包括 '\0'
	printf("%d\n", sizeof(arr));		//6
	printf("%d\n", sizeof(arr + 0));	//4/8	首元素地址
	printf("%d\n", sizeof(*arr));		//4/8	首元素
	printf("%d\n", sizeof(arr[1]));		//4		第二个元素
	printf("%d\n", sizeof(&arr));		//4/8	数组的地址
	printf("%d\n", sizeof(&arr + 1));	//4/8	跳过整个数组的地址
	printf("%d\n", sizeof(&arr[0] + 1));//4/8	第二个元素的地址
    
	printf("%d\n", strlen(arr));		//随机值; arr是首元素的地址。但是arr数组中没有'\0',而strlen要找到‘0’后才会停止。结果:随机值,strlen函数关注的是'\0'这个结束符,因为没有 '\0' 这个字符串结束字符
	printf("%d\n", strlen(arr + 0));	//随机值; arr是首元素的地址,arr+0还是首元素的地址,结果是:随机值
	printf("%d\n", strlen(*arr));		//error,编译不过;  strlen需要的是一个地址,从这个地址向后找'\0',统计字符个数,但是*arr表示数组的首元素,也就是‘a’,这时传个strlen的就是‘a’的ascii码值97,就会把97作为起始位置,统计字符串,就会形成内存访问冲突
	printf("%d\n", strlen(arr[1]));		//error,通上一个一样
	printf("%d\n", strlen(&arr));		//随机值: &arr是 arr数组的地址,虽然类型有所差异,但是传参过去后,还是从第一个字符的位置向后数字符,结果还是随机值。
	printf("%d\n", strlen(&arr + 1));	//随机值
	printf("%d\n", strlen(&arr[0] + 1));//随机值
	return 0;
}

本轮的难点在于strlen这个库函数能接收数值吗?答案是:不能,传入数值得话会形成内存访问冲突。

还有就是strlen没哟找到 '\0'时会怎样,答案:直到在内存中找到'\0'为止,而我们不知道什么时候会出现,所以它是一个随机值。

第三轮 数组3

第三轮只是第二轮的一些衍生,所以难度并不是很大,但也要谨慎看待

从这轮开始,简单的一些题我就直接在后面注释结果了

#include <string.h>
int main()
{
	char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));		// 7  sizeof的计算会包括 '\0' 
	printf("%d\n", sizeof(arr + 0));	// 4/8
	printf("%d\n", sizeof(*arr));		// 1
	printf("%d\n", sizeof(arr[1]));		// 1
	printf("%d\n", sizeof(&arr));		//4/8
	printf("%d\n", sizeof(&arr + 1));	// 4/8
	printf("%d\n", sizeof(&arr[0] + 1));// 4/8

	printf("%d\n", strlen(arr));		// 6
	printf("%d\n", strlen(arr + 0));	// 6
	printf("%d\n", strlen(*arr));		// err
	printf("%d\n", strlen(arr[1]));		// err
	printf("%d\n", strlen(&arr));		// 6
	printf("%d\n", strlen(&arr + 1));	// 随机
	printf("%d\n", strlen(&arr[0] + 1));// 5  从第二个元素开始计算,所以得到5
	return 0;
}

第四轮 指针

之前的是数组的,这组是指针的,虽然指针的和数组的大同小异,但也还是有细微的差别

#include <string.h>
#include <stdio.h>
int main()
{
	char* p = "abcdef";
	printf("%d\n", sizeof(p));			// 4/8	p是地址
	printf("%d\n", sizeof(p + 1));		// 4/8	p+1还是地址
	printf("%d\n", sizeof(*p));			// 1	解引用访问到字符‘a’
	printf("%d\n", sizeof(p[0]));		// 1	下标访问第一个元素,'a'
	printf("%d\n", sizeof(&p));			// 4/8	将p指向的字符指针数组,整个&, 但也还是地址。
	printf("%d\n", sizeof(&p + 1));		// 4/8	跳过整个字符串后的地址还是地址;&p+1,就是跳过p指针在内存中指向的所有内容的地址。
	printf("%d\n", sizeof(&p[0] + 1));	// 4/8	第二个元素的地址

	printf("%d\n", strlen(p));			// 6	从我们传入的这个地址,找到'\0'为止,我们传入的是第一个地址
	printf("%d\n", strlen(p + 1));		// 5	我们传入的是第二个地址,找到'\0'为止
	printf("%d\n", strlen(*p));			// error 不能在strlen中传入数值,会造成内存冲突
	printf("%d\n", strlen(p[0]));		// error 同上
	printf("%d\n", strlen((&p)));		// 随机	存入的是p指向的字符指针数组,会以它为第一个地址,但是之后的在哪里出现'\0',我们不得而知
	printf("%d\n", strlen((&p+1)));		//随机	同上,加一以后不过是跳过了p这个指针指向的字符串,但是之后的在哪里出现'\0',我们也不知道
	printf("%d\n", strlen((&p[0] + 1)));// 5	从第二个元素的地址找'\0'.

	return 0;
}

第五轮 二维数组的sizeof

最终之轮~~(最难一轮)~~,加油!!欧力给

本轮是二维数组的sizeof计算,

科普:

在二维数组中,数组名表示第一行的地址,sizeof(数组名)和 &(数组名)中例外

在二维数组中,a[0]表示,第一行的数组名,在sizeof中计算的也就是第一行的数组大小,以此类推。

int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));			// 48  数组名单独放在sizeof内部,计算的是整个数组的大小
	printf("%d\n", sizeof(a[0][0]));	// 4	计算的是第一行,第一个元素的大小
	printf("%d\n", sizeof(a[0]));		// 16	a[0]表示第一行的数组名。a[0]作为数组名放在sizeof内部,计算的是数组的第一行的大小
	printf("%d\n", sizeof(a[0] + 1));	// 4/8	a[0]作为第一行的数组名,没有&,没有单独放在sizeof内部,所以a[0]表示的就是首元素的地址也就是a[0][0],+1就是表示访问第一行的第二个地址;
	printf("%d\n", sizeof(*(a[0] + 1)));// 4	访问到第二个元素
	printf("%d\n", sizeof(a + 1));		// 4/8	a是第一行的地址,+1后就是第二行的地址
	printf("%d\n", sizeof(*(a + 1)));	// 16	*(a+1)就是第二行,相当于第二行数组名,*(a+1) ==a[1];
	printf("%d\n", sizeof(&a[0] + 1));	//4/8	a[0]是第一行的地址,&a[0]就是第一行的地址,&a[0]+1 就是第二行的地址
	printf("%d\n", sizeof(*(&a[0] + 1)));//16	&a[0]+1是第二行的地址,解引用后就是 a[1];
	printf("%d\n", sizeof(*a));			// 16	a二维数组的数组名,a表示首元素的地址,也就是第一行
	printf("%d\n", sizeof(a[3]));		// 16		感觉a[3]越界了,但是没关系,编译器它会根据数组来推断
	return 0;
}

第五轮的二维数组是最绕的,同志们学习的时候,可以多看几遍

本次分享到此结束

若有错误欢迎批评指正,在下感激不尽,愿你我都能在编程的道路上越走越远!!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值