c语言指针内存把我整懵了

预备知识:

1,变量:(有两个东西)
  • 声明一个变量,系统给变量分配了一个存储单元,它是一个地址域和一个值域的统称。
2,普通变量和指针变量的区别:(值域有区别)
  • 普通变量:值域中存放具体的数据
  • 指针变量:值域中存放地址
3,赋值操作:(赋值就是覆盖值域!)
  • 值域覆盖值域,即普通变量 a, b 相互赋值情况: a = b。这里是 a 的值域用 b 的值域进行覆盖,a 和 b 的地址域并没有进行操作!(这里补充一下指针变量 p1, p2 相互赋值的情况:p1 = p2。这里是 p1 的值域用 p2 的值域覆盖。)
  • 地址域覆盖值域,即指针变量 p 和普通变量 var 相互赋值情况:p = &var。这里是 p 的值域用 var 的地址域进行覆盖。

代码:

int main(void){

	int var=0;	
	int *p = NULL; // 一级指针
	int **pp = NULL; // 二级指针


	p = &var;	// 一级指针保存 var 的地址

	
	pp = &p;	// 二级指针保存 p 的地址

	printf("address of var: %d\n", &var);
	printf("address of p: %d\n", &p);
	printf("address of pp: %d\n", &pp);
	printf("\n");
	printf("value of p: %d\n", *p);
	printf("value of pp: %d\n", *pp);
	printf("value of p: %d\n", **pp);


	
	return 0;
	
}

运行结果

在这里插入图片描述

整理结果:

地址域值域
var 的地址:1703716var 的值:3
p 的地址:1703720p 的值:3
pp 的地址:1703724pp 的一级取值:1703716pp 的二级取值:3

问题提出:

  • 问题来了,基于对预备知识的理解,也就是 p 的值域应该存储 var 的地址域,而 pp 的一级值域应该存储 p 的地址域。然而,上述代码运行后,整理出来的结果中,p 的值域却是 var 的值域,pp 的一级值域却是 var 的地址域。

问题解决:(*p)的理解

注意: 取出值域意思是下一级的指针域,连带值意思是下一级的指针域的值域)

  • 首先明确预备知识是没有错的,代码运行结果也没有错,错的地方在于对 星号 * 的理解上

  • (*p)的意思是取出 p 的值域(也就是 var 的地址域)的连带值,该值就是 var 的值域 3 。

  • (*pp)的意思是取出 pp 的值域(也就是 p 的地址域)的连带值,该值就是 p 的值域,也就是 var 的地址域 1703716。

  • (**pp)等价于 (*(*pp)),意思是先进行 *pp 操作取出 p 的值域,然后再进行 (*p)操作取出 p 的值域的连带值。

  • 总结星号 * 的意思是取出值域的连带值。这么理解有点儿绕,图示说明:

    白色的是地址域,红色的是值域。以 p 为例,p 的下一级是 var,而 p 的值域保存的是 var 的地址域,var 的地址域连带值域就是 3。

  • 【当然官方说法是 (*p )表示: p 指向地址的内容,简记:取内容。这么记忆我自己不好理解,记成:取值域连带值,还挺可以】

延申一个问题:

下面的代码第 8 行,为什么运行不正确?不是说 p 是指针变量,那么它的值域保存的就是地址吗?为什么取了一个 a 的地址给它,还不对了呢?

int main(void){
	
	int *p = NULL;
	
	int a[3] = {1, 2, 3};


	p = &a; // 这里运行错误


	
	return 0;
	
}

答案: 这里又体会到了,同级别赋值就是值域赋值,不同级别赋值就是低级别的指针域赋值给高级别的值域。基于这个理解,这里可以将第 8 行右边,降低级别为普通变量,改为:p = &a[0],成功运行。也可以将第 8 行左边升高一个级别,为二级指针变量,会发现失败。但是如果 a 不是数组指针,而是一个普通的指针,将左边升高一个级别的操作则是没问题的。如下代码:

int main(void){
	
	int **p1 = NULL; // p1 升高一个级别,二级指针

	int *p2 = NULL; // p2 为一级指针

	p1 = &p2;
	



	
	return 0;
	
}

这里就又抛出了一个问题

为什么数组指针的情况,将左边升为二级指针失败了呢?也就是如下代码:


int main(void){
	
	int **p1 = NULL; // p1 升高一个级别,二级指针
	
	int a[3] = {1, 2, 3}; // a 是一级指针


	p1 = &a;
	

	
	return 0;
	
}

答案:数组名的本质是 &a[0],而 &a 的意思是int *[] 类型。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值