练习题:C++指针练习


在C++中,const作用于指针时,可以看做是对指针权限的限制。这里我们先把指针的权限归为两种,分别为指向权限修改权限。(ps:以上是为了理解方便,实际并没有如此规定)

	int a = 10, b = 20;
	int* p = &a;

	p = &b;		// 改变指向的权限  ✔
	*p = 30;	// 修改内存的权限  ✔

	const int* cp = &a;	// 限制修改权限
	//*cp = 100;		// error:表达式必须是可修改的左值	修改 ✖
	cp = &b;			// ok.								指向 ✔

	int* const pa = &a;	// 限制指向权限
	*pa = 100;			// ok.								修改 ✔
	//pa = &b;			// error:表达式必须是可修改的左值  指向 ✖

指针的赋值一般遵守权限缩小式的赋值。例如,我有一本书,我有使用权限(我可以看,可以做笔记),借给你后你只有阅读权限(只能看,不能做笔记)。当然,如果我们关系好,我可以赋予你使用权(你拥有读写的权利)。同样的,指针的赋值也是如此。

	int a = 10;
	int* p = &a;	// int*  <==  int *

	int* q = p;				// int*  <== int*
	const int* cp = p;		// const int*  <==  int*	权限缩小,✔
	int* const pa = p;		// int*	 <== int*			注意:int* const pa;是“int*”类型

	//int* p1 = cp;	// error:int*  <== const int *     权限放大,✖
	int* p2 = pa;	// ok.    int*  <== int*

我们可以得出一级指针赋值的公式

int *       <==  int *		// int* 包含 int* 和 int* const类型
int const * <==  int *		// int const * <=等同=> const int *
// 以上公式反过来赋值就是错误的..


练习一:一级指针指向练习题

题目一:下列表达式语句赋值错误的是?

	int a = 10;
	const int* p = &a;
	int* q = p;		

	int a = 10;
	int* const p = &a;
	int* q = p;

	int a = 10;
	int* const p = &a;
	int* const q = p;

	int a = 10;
	int* const p = &a;
	const int* q = p;




答案:(鼠标选中查看)

👉错误:A,正确:B、C、D👈
解析:
	int a = 10;

	const int* p1 = &a;
	int* q1 = p1;				// error:无法从const int * 转为 int *
	/* 分析:
		int* <= cosnt int*

	*/

	int* const p2 = &a;
	int* q2 = p2;
	/* 分析:
		int* <= int*
		
	*/

	int* const p3 = &a;
	int* const q3 = p3;
	/* 分析:
		int* <= int*
		
	*/

	int* const p4 = &a;
	const int* q4 = p4;
	/* 分析:
		cosnt int* <= int*
		
	*/


练习二:二级指针指向练习题

题目二:下列表达式语句错误的有。

// 选项A
int a = 10;
int* p1 = &a;
const int** q1 = &p1;	

// 选项B
int a = 10;
int* p2 = &a;
int* const* q2 = &p2;

// 选项C
int a = 10;
int* p3 = &a;
int** const q3 = &p3;

// 选项D
int a = 10;
int* const p4 = &a;
int** q4 = &p4;	

// 选项E
int a = 10;
const int* p5 = &a;
int* const* q5 = &p5;	



答案:(鼠标选中查看)

👉错误:A、D、E,正确:B、C👈
A选项;

错误; 注:如果const修饰的是二级指针,我们需要对二级指针的逐层解引用进行分析。

	int* p1 = &a;
	const int** q1 = &p1;	//error  无法从“int * *”转换为“const int** ”

int* p1 = &a; p1的类型为int* 取地址为 int **
const int** q1 = &p1; q1的类型为 const int **
则指针赋值过程为 const int ** <= int* *

分析:

  • const作用于(**q1),修饰二级指针。表示不可通过q1a 的值进行修改。
  • *q1 解引用一次后,为一级指针,即 p1 。但是 p1 存在对 a 修改的风险,因此无法直接赋值。

修改方案:

  • 方案一:直接限定一级指针p1。保证p1不会修改a的值,即const int * p1= &a; const int** q1 = &p1;
  • 方案二:间接限定q1,使其指向时缩小权限,对解引用后的(*q1)修改的权限做出限制,如:const int * const * q1;
	// 方案一
	const int* p12 = &a;
	const int** q12 = &p12;

	// 方案二
	int* p11 = &a;
	const int* const* q11 = &p1;
B选项;

正确; 注:如果const修饰的是一级指针,我们可以抛开二级指针的表象,但看一级指针的赋值操作是否正确。如本例。

	int* p2 = &a;			
	int* const* q2 = &p2;
	/* 分析:
		int* const*  <==  int* *
		const修饰 *q2,即cosnt修饰一级指针
		cosnt*  <== *				// 去掉前面的 int* <= int*
		int const *  <== int *		// 添加一个任意类型,如int
			如👆所示,这是一个权限缩小的一级指针赋值,✔
	*/
C选项;

正确; 注:如果两边类型相同,则无需进行判断。如本例。

	int* p3 = &a;
	int** const q3 = &p3;

	cout << typeid(q3).name() << endl;	//输出 q3 类型   int * *
	/* 分析:
		int**const  <== int* *  即  int**  <== int* *
		两边类型相同,无需进行特殊判断,✔
	*/

ps:如果const修饰的参数右边无“*”号,则该cosnt不作用于类型。如:

	int n = 10;
	// 使用typeid(valtypr).name() 输出变量类型
	int const* p1 = &n;		// int const *
	int* const p2 = &n;		// int *			// 忽略const
	
	int* p = &n;
	int** q = &p;
	//int const** q1 = &p;		
	int const* const* q1 = &p;	   // int const* const*
	int* const* q2 = &p;		   // int* const*
	int** const q3 = &p;		   // int**		// 忽略cosnt
D选项;

错误; 同B选项相同,对于const修饰的一级指针进行判即可。

	int* const p4 = &a;
	int** q4 = &p4;			//error  "int *const *"类型的值不能用于初始化"int **类型的实体

int* const p4 = &a; 类型为 int*,因为const的存在,取地址后类型为 int * const *
int** q4 = &p4; 类型为 int**
则指针赋值过程为 int** <== int* const*

分析:

  • const作用于(p4),修饰一级指针。则我们忽略没有const修饰的部分。即
    * <== const* ,//忽略 int
    部分,该部分赋值时权限没有发生变化。
    int* <== int const * ,给指针确定一个类型,如“int” 类型
  • 如👆,我们可以看到,该表达式语句想从int const* 类型处,获得一个 int* 类型的赋值,也就是说这是权限放大式的赋值。错误原因:该赋值会使得 int* 类型指针对常量(int const* 所指向的值)产生修改的风险。

修改方案:

  • int* <== int const *型赋值改成 int const* <== int const *类型赋值
    即,int*const* q4 = &p4;
E选项;

错误; 注:如果赋值两边都有const时,各论各的分析,如下。

	const int* p5 = &a;
	int* const* q5 = &p5;	//error  无法从"const int **"转换为"int *const *"

分析:

  • 省略分析过程等赋值类型为 int* const* <== const int* *
  • 分情况分析:
    • 提取指针左边部分int* <== const int* ,错误 ✖
    • 提取指针右边部分cosnt * <== *int const * <== int *,正确 ✔
  • 综上,错误 ✖。

修改方案:

  1. 修改指针左边类型:int* <== const int*int* <= int*
  2. 修改指针左边类型:int* <== const int*const int* <= const int*
	//1 int* <= int*
	int* p51 = &a;					// const int* p5  ⇒   int* p51
	int* const* q51 = &p51;
	//2 const int*  <= const int*
	const int* p52 = &a;
	const int* const* q52 = &p52;	// int* const* q5 ⇒   const int* const* q52
方法总结:

对于二级指针的赋值操作判断,看const位置、主要有以下两种情况:

  • 如果 const修饰的是二级指针 如:

    • int const ** ,如选项A。我们需要考虑其解引用情况。cosnt修饰二级指针所指向的值为常量,但是由于一次解引用后的指针会存在修改常量的风险,因此我们需要限制该指针与常量之间进行过度的一级指针
    • 针对此类二级指针,我们只需记住合法的赋值为
      等式两边需同时有constconst int* cosnt* <== int**
      左边等式有两个cosntconst int* cosnt* <== int**
  • 如果 const修饰的是一级指针其他 如:

    1. const修饰的是一级指针int * const *,如选项B。单独剥离出含cosnt类型的一级指针类型进行分析
    2. 即修饰一级指针又修饰二级指针 如, int cosnt * cosnt *
    3. 无const修饰 如, int**int ** cosnt,如选项C、选项D
    • 针对此类二级指针,通过一级指针的比较进行比较即可。
  • 14
    点赞
  • 102
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
以下是一个关于C函数指针练习题的示例代码: ```cpp #include <iostream> using namespace std; // 定义一个函数指针类型 typedef void (*FuncPtr)(int); // 定义一个函数,将传入的整数加1并打印 void addOne(int num) { cout << num + 1 << endl; } // 定义另一个函数,将传入的整数乘以2并打印 void multiplyByTwo(int num) { cout << num * 2 << endl; } int main() { int choice; int num; FuncPtr funcPtr; cout << "请选择操作:1.加1 2.乘以2" << endl; cin >> choice; // 根据用户选择设置函数指针 if (choice == 1) { funcPtr = addOne; } else if (choice == 2) { funcPtr = multiplyByTwo; } else { cout << "无效的选择" << endl; return 0; } cout << "请输入一个整数:" << endl; cin >> num; // 调用函数指针指向的函数 funcPtr(num); return 0; } ``` 这段代码定义了一个函数指针类型 `FuncPtr`,然后根据用户的选择设置函数指针的值。根据选择的不同,函数指针指向不同的函数,然后通过函数指针调用相应的函数。用户输入一个整数,然后根据选择的操作,对该整数进行相应的处理并打印结果。 请注意,这只是一个示例代码,实际的练习题可能会有所不同。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [C++函数、指针、结构体(黑马程序员教程笔记)](https://blog.csdn.net/anlihuaer/article/details/120686223)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [C++指针题](https://blog.csdn.net/qq_62637200/article/details/126795026)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我叫RT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值