指针、数组、字符数组、二维数组等在内存中的分布剖析

本篇介绍:

  • 一维数组
  • 字符数组
  • 二维数组
//一维数组
int main()
{
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));
	//a是数组名,sizeof中单独一个数组名是求整个数组的大小,所以是16

	printf("%d\n", sizeof(a + 0));
	//a是数组名,数组名等于数组首元素的地址,a+0表示第一个元素的地址,地址的大小是4或8个字节

	printf("%d\n", sizeof(*a));
	//a是数组名也是首元素的地址,解引用就是首元素,大小是4个字节

	printf("%d\n", sizeof(a + 1));
	//a是数组首元素的地址,a+1就是数组第二个元素的地址,是一个指针,大小是4或8个字节

	printf("%d\n", sizeof(a[1]));
	//a[1]表示数组第二个元素,是一个整型,大小是4个字节

	printf("%d\n", sizeof(&a));
	//&a是整个数组的地址,用来存放地址需要指针,指针的大小是4或8个字节

	printf("%d\n", sizeof(*&a));
	//*&a就等于a,整个数组的大小,所以是16

	printf("%d\n", sizeof(&a + 1));
	//&a对整个数组取地址,&a+1跳过一个数组的大小,但是它是一个指针,所以大小是4或8个字节

	printf("%d\n", sizeof(&a[0]));
	//&a[0]对数组第一个元素取地址,用指针变量来存储,大小是4或8个字节

	printf("%d\n", sizeof(&a[0] + 1));
	//&a[0]+1表示对第一个元素取地址后+1,指向了数组的第二个元素,也是一个地址,用指针来存放,        
    所以大小是4或8个字节

	return 0;
}

运算结果:

//字符数组
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));
	//arr数组名表示整个数组的大小,所以大小是6个字节

	printf("%d\n", sizeof(arr + 0));
	//在这里arr是数组名,表示数组首元素的地址,+0表示往后走0位,所以还是第一个元素的地址,用指针来存放,所以大小是4或8个字节

	printf("%d\n", sizeof(*arr));
	//在这里arr是数组名,表示数组首元素的地址,解引用表示第一个元素,因为是char类型变量,所以大小是1个字节

	printf("%d\n", sizeof(arr[1]));
	//arr[1]表示数组第二个元素,大小是1个字节

	printf("%d\n", sizeof(&arr));
	//arr是数组名,表示数组首元素的地址,&arr就是存放首元素地址的指针,大小是4或8个字节

	printf("%d\n", sizeof(&arr + 1));
	//&arr+1表示一个地址,跳过一个char*的大小,所以大小是4或8个字节

	printf("%d\n", sizeof(&arr[0] + 1));
	//&arr[0]表示对数组首元素取地址,+1表示第二个元素的地址,所以大小是4或8个字节


	
	printf("%d\n", strlen(arr));
	//随机值,因为数组名表示数组首元素的地址,从首地址开始往后走,直到遇见\0结束,而我们不知道在何处遇到\0,所以为随机值

	printf("%d\n", strlen(arr + 0));
	//随机值,和它上面一行的意思一样

	//printf("%d\n", strlen(*arr));
	//非法访问,arr表示数组首元素的地址,解引用表示数组首元素'a',对应的ASCII码是97,把97当做一个地址去访问,但是这个地址不是我的

	//printf("%d\n", strlen(arr[1]));
	//非法访问,arr[1]表示数组第二个元素'b',对应的ASCII码是98,把98当做一个地址去访问,但是这个地址不是我的

	printf("%d\n", strlen(&arr));
	//随机值,&arr取出的是整个数组的地址,从这个地址开始往后找\0,直到遇到\0结束

	printf("%d\n", strlen(&arr + 1));
	//随机值,&arr表示整个数组的地址,+1跳过整个数组,开始往后找\0

	printf("%d\n", strlen(&arr[0] + 1));
	//随机值,&arr[0]取出首元素的地址,+1表示第二个元素的地址,往后找\0

	return 0;
}

运行结果:

int main()
{
	char arr[] = "abcdef";//[a b c d e f \0]
	printf("%d\n", sizeof(arr));
    //arr单独在sizeof中表示整个数组的大小,大小是7个字节

	printf("%d\n", sizeof(arr + 0));
    //arr表示数组首元素的地址,所以大小是4或8个字节

	printf("%d\n", sizeof(*arr));
    //arr表示数组首元素的地址,解引用表示就是数组的首元素,大小是1个字节

	printf("%d\n", sizeof(arr[1]));
    //arr[1]表示数组第二个元素,大小是1个字节
	
    printf("%d\n", sizeof(&arr));
    //&arr表示整个数组的地址,因为是地址,所以大小是4或8个字节

    printf("%d\n", sizeof(&arr + 1));
    //跳过整个数组,也是地址,所以大小是4或8个字节

    printf("%d\n", sizeof(&arr[0] + 1));
    //数组首元素的地址+1指向数组的第二个元素,也是地址,所以大小是4或8个字节


	printf("%d\n", strlen(arr));//6
	printf("%d\n", strlen(arr + 0));//6
	printf("%d\n", strlen(*arr));
    //非法访问,arr表示数组首元素的地址,解引用表示数组的首元素,首元素是'a',ASCII码是97,地址是97的位置不是我们的
	
    printf("%d\n", strlen(arr[1]));
    //非法访问,arr[1]表示数组第二个元素'a',ASCII码是98,地址是98的位置不是我们的
	
    printf("%d\n", strlen(&arr));
    //6,&arr是整个数组的地址,从这里往后找\0
	
    printf("%d\n", strlen(&arr + 1));
    //随机值,往后跳了一个数组,从这里往后找\0
	
    printf("%d\n", strlen(&arr[0] + 1));
    //5,从第二个元素往后走,找\0,
	return 0;
}

运行结果:

int main()
{
	char* p = "abcdef";//[a b c d e f \0]
	printf("%d\n", sizeof(p));
	//指针的大小是4或8个字节

	printf("%d\n", sizeof(p + 1));
	//指针的大小是4或8个字节

	printf("%d\n", sizeof(*p));
	//p指向a,解引用表示字符a,大小是1个字节
	
	printf("%d\n", sizeof(p[0]));
	//p[0]表示字符a,大小是1个字节
	
	printf("%d\n", sizeof(&p));
	//指针的大小是4或8个字节
	
	printf("%d\n", sizeof(&p + 1));
	//跳过一个char*的大小,还是一个地址,大小是4或8个字节
	
	printf("%d\n", sizeof(&p[0] + 1));
	//表示第二个字符的地址,大小是4或8个字节


	printf("%d\n", strlen(p));//6
	printf("%d\n", strlen(p + 1));//5
	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));//5
	
	return 0;
}

运行结果:

//二维数组
int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));
	//表示整个数组的大小,大小是48个字节
	
	printf("%d\n", sizeof(a[0][0]));
	//大小是4个字节
	
	printf("%d\n", sizeof(a[0]));
	//a[0]是二维数组的第一个一维数组的数组名,大小是16个字节
	
	printf("%d\n", sizeof(a[0] + 1));
	//第一行第二个元素的地址,相当于&a[0][0]+1,4或8个字节
	
	printf("%d\n", sizeof(*(a[0] + 1)));
	//第一行第二个元素的地址解引用表示a[0][1]这个元素,大小是4个字节
	
	printf("%d\n", sizeof(a + 1));
	//相当于&a[1],第二行的地址,大小是4或8个字节
	
	printf("%d\n", sizeof(*(a + 1)));
	//相当于*&a[1],就等于a[1],大小是16个字节
	
	printf("%d\n", sizeof(&a[0] + 1));
	//第二行的地址,大小是4个字节
	
	printf("%d\n", sizeof(*(&a[0] + 1)));
	//相当于a[1],大小是16个字节
	
	printf("%d\n", sizeof(*a));
	//*&a[0] == a[0], 大小是16个字节
	
	printf("%d\n", sizeof(a[3]));
	//大小是16个字节
	return 0;
}

 运行结果:

 总结:

  1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小
  2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址
  3. 除此之外所有的数组名都表示首元素的地址
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值