指针重点总结-常量指针-const ptr *,指针常量ptr * const,引用,指针传参,指针修改,指针指向的值修改等问题

C/C++指针踩坑历险记-常量指针-const ptr *,指针常量ptr * const,引用,指针传参,指针修改,指针指向的值修改等问题

好久没写C语言了,不过一直用C++在刷题,遇到指针总有些发憷?初学指针的时候觉得指针好难,其实搞清指针的重要几个概念,指针就不难~对指针一些重点知识进行一个总结。

指针初体验

我们知道指针本质上就是一个存放地址的变量(该变量存放地址,一串你看不懂的数字)。比如

int a = 3;
int* ptr = &a;//就表示指向a的一个变量ptr,ptr内部存放的是一个地址(一串你看不懂的数字)

下面举个例子,直观地展示一下ptr的值

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int a = 3;
	int* ptr = &a;//ptr是一个地址
	printf("0x%x", ptr);//打印ptr的值
}

输出结果

在这里插入图片描述

通过设置断点查看程序执行过程,也可以查看ptr存放的到底是什么

在这里插入图片描述

你现在只需要知道指针就是指向一个内存块的地址,本质上就是一个变量。
对指针有了直观的认识之后,你肯定会想,要一个内存单元的地址有什么用呢?这个地址(0x00d3fb30)我又看不懂。我们要内存中的值(比如上面a的值3)不就行了吗?
其实不然,指针在函数参数传递中大有妙用。请往下看

指针在函数"传值"中的应用

我们知道函数传参过程中,实参和形参结合,也就是形参会等于实参的值,然后函数老大就一脚把实参踹开,之后就不干实参啥事了。

之后在函数内部,函数老大就抓着形参不放,所有的操作都是对实参起作用,和形参无关(暂时这么理解)。下面举个例子

#include<stdio.h>
#include<stdlib.h>
void add(int a) {
	a = a + 1;
	printf("函数内部的a值(形参)为%d\n", a);//形式结合,a=b=3,然后a=a+1=4.
}
int main()
{
	int b = 3;
	add(b);
	printf("函数外部的b值(实参)为%d\n", b);//实参不变,b=3

}

通过这个例子,我们要记住,函数形参和实参结合时,函数内部先将实参的值赋给形参,然后再对形参进行操作。

当形参为地址时,对形参操作也可能会影响实参,下面举例说明

#include<stdio.h>
#include<stdlib.h>
void add(int* a) {//形参为指针,a等于b的地址
	*a = *a + 1;//a也就是b的地址,*表示取出该地址内存中的值3,加1后存放在a地址中。即3+1=4
	printf("函数内部的a地址为0x%x\n", a);//一个地址,和b的地址一样0x136f9c4
	printf("函数内部的a地址内存里面的值为%d\n", *a);//4
}
int main()
{
	int b = 3;
	add(&b);
	printf("函数外部的b的地址为0x%x\n", &b);//b的地址0x136f9c4
	printf("函数外部的b值(实参)为%d\n", b);//在函数内部通过地址改变了b的值,b=4

}

运行结果

在这里插入图片描述

通过这个地址我们需要明白两点

  1. 当函数形参为指针类型时,表示该函数传递一个指针给形参,然后对形参进行操作。此时形参是一个指针,也就是一个地址,我们通过地址可以使实参发生变化。比如例子中改变*a使得实参b发生变化。示意图如下:
    在这里插入图片描述

  2. 为了和传值区分,我们称上面函数传参方式为传址。其实传址本质上还是传值。

传址妙用

传址可以大大减少内存的消耗,试想一下如果b中存放的是一个占很大内存的对象,如果采用传值方式传递,形实结合会新开辟一块和b一样的空间,供函数内部操作。这样会很消耗内存空间。

但如果我们只传递b的一个地址(一串数字的大小),形实结合时,仅仅需要一小块空间就能够存放下b的地址。然后在函数内仅仅需要通过*就可以操作该地址内部的值。此举大大节约空间。但此举操作可能会影响函数外部的对象的值,使用时应该考虑清楚。

用*对指针指向的值修改

毫无疑问,在函数内部用*对形参指向的值进行修改,函数外部的实参值也会变化。如下

#include<stdio.h>
#include<stdlib.h>
void add(int* a) {//形参为指针,a等于b的地址
	*a = *a + 1;//a也就是b的地址,*表示取出该地址内存中的值3,加1后存放在a地址中。即3+1=4
	printf("函数内部的a地址为0x%x\n", a);//一个地址,和b的地址一样0x136f9c4
	printf("函数内部的a地址内存里面的值为%d\n", *a);//4
}
int main()
{
	int b = 3;
	add(&b);
	printf("函数外部的b的地址为0x%x\n", &b);//b的地址0x136f9c4
	printf("函数外部的b值(实参)为%d\n", b);//在函数内部通过地址改变了b的值,b=4

}

但是如果直接对形参修改(不用*),不会对函数外部的实参值有任何影响。如下

直接对指针本身修改

#include<stdio.h>
#include<stdlib.h>
void add(int* a) {//形参为指针


	int c = 10;
	a = &c;//a的值变化了,此时a已经与函数外部的b彻底没关系了。不会影响函数外部b的值。


	printf("函数内部的a地址为0x%x\n", a);//a为c的地址
	printf("函数内部的a地址内存里面的值为%d\n", *a);//*a=10
}
int main()
{
	int b = 3;
	add(&b);
	printf("函数外部的b的地址为0x%x\n", &b);//b的地址
	printf("函数外部的b值(实参)为%d\n", b);//b=3,未发生变化

}

要正确理解 * 表示对该指针指向的内存单元的值进行操作。

直接对形参修改(不用*),表示对该地址修改了。原来形参还和实参指向同一块地址,形参地址一旦修改,形参就彻底和实参失去联系了。再对形参任何操作均不会对函数外部的实参值有任何影响。这点要注意,容易出错。

常量指针

所谓常量指针就是指向常量的指针,表示为const int* 。不能用*去修改内存中的常量。举例

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int a = 3;
	const int* ptr = &a;
	*ptr = 4;//报错:表达式必须是可修改的左值

}

指针常量

指针常量,表示该地址是一个常量,不能修改。表示为int * const.举例

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int a = 3;
	int b = 4;
	int* const ptr= &a;
	ptr = &b;//报错:表达式必须是可修改的左值

}

C++中的引用,本质上就是指针常量。

C++引用

C++引用是C++中特有的,本质上就是指针常量,如果进行修改,一定是指向的内存变化,而不是指针本身。用&表示。在引用的基础上改变,原值也要变,可以看做一个变量的别名。举例

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int a = 3;
	int& ptr= a;//ptr就是a的别名
	printf("%d\n", ptr);//3
	ptr = 5;
	printf("%d\n", ptr);//5
	printf("%d\n", a);//5

}
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值