C语言 char *、char []、const char *、string的区别与相互转换


1.VS运行程序,出现“烫烫烫烫烫烫烫烫烫…”

在 Debug 模式下,
VC 会把未初始化的栈内存全部填成 0xcc,当字符串看就是 烫烫烫烫……
会把未初始化的堆内存全部填成 0xcd,当字符串看就是 屯屯屯屯……


2. VS不可以char *p=“abcd”

注意:编译器是把"abcd"作为“abcd\0”来处理的,有五个字符
为什么要加上’\0’?,‘\0’代表空格符,在字符串结尾加上‘\0’,代表字符串已经结束,读到\0的时候会停下来,不然会沿着内存地址一直读下去,读到什么乱七八糟的东西就不知道了,比如会读到类似 “烫烫烫烫”的东西

原因——“abcd”是字符串常量,不可更改,必须加上const用常量指针,即 const char *p = “abcd”
const char *p="hello"分配在静态存储区,不可以改变.
char p[]="hello"分配在堆上.


3.char *、char []、const char *、string 的区别

const char * 只是说指针指向的内容不可变,但指针本身可以再赋值

注意:看const 是放在*的左边还是右边 看const是修饰指针变量,还是修饰所指向的内存空变量

const char *p1 ; char * const p1 ; const char * const p1; //三者都不一样
const int a; int const b;  	//const修饰 a b意义相同
const char *c; 				//const修饰c所执行的内存空间,c所值得内存空间不能被修改
char * const d; 			//d是一个常量指针;

1.char * //字符指针,指向字符的指针

2.const char *,字符串常量,即像"aaa"这样的类型

3.string 是std::basic_string模板类的实例化,是一个类(C++的STL才有),string str=“aaa”; 其实是 const char *转class ,string重载了=号,把“aaa”封装成std::string

4.char a[8]; // a的类型是 char [8],如果是char a[6]; 则a的类型就是char [6] 既长度为N的字符数组


4.char *、char []、const char *、string 的转换

在这里插入图片描述
转化规律总结下:

1.转化成char[],可以用strcpy_s ,或者遍历字符串的方式
string 转char[] : strncpy_s(a, string.c_str(), N); 也可以用上图的遍历string
const char * 转char[] : strcpy_s(a, const char *); 也可以用上图的strncpy_s
char * 转char[] : strcpy_s(a, char *); 也可以用上图的strncpy_s

2.char[]变成别的,直接赋值

3.转化为std::string 最简单,可以直接=, 因为string太强大了,把=号重载了很多遍

4.const char *转化到 char * 使用const_cast<char *>

5.string转化为char * 用c_str()


5.函数返回指向局部变量的指针,其指向的内容若不被保护,将会被系统回收内存(篡改内存数据)

#include "stdlib.h"
#include "string.h"
#include "stdio.h"

#define _CRT_SECURE_NO_WARNINGS

const char *getStr1()
{
	const char *p = "abcd";
	printf("%s\n%p\n", p,p);
	return p;
}

char *getStr2()
{
	char str[] = "abcd";
	char *p = str;
	printf("%s\n%p\n", p, p);
	return p;
}

void main(void)
{	
	printf("getStr1():%s\n", getStr1());
	printf("getStr2():%s\n", getStr2());

	system("pause");
}

1.getstr1(): const在编译时候就确定好地址,其指向的内容不可更改。
在这里插入图片描述2.getstr2(): char[]数组作为局部变量,在函数返回时内存会被系统回收,数据遭到篡改,无参考价值。
在这里插入图片描述

<think>好的,我现在要解释这三个指针声明的区别const char **p; char *const *p; char **const p;。首先,我得回忆一下C语言const的用法,特别是当它和指针结合时的位置问题。 首先,const的位置不同,修饰的对象也不同。例如,const char *p 表示p是一个指向常量字符的指针,也就是说不能通过p修改所指向的字符,但p本身可以指向其他地址。而char * const p 则表示p是一个常量指针,指向字符类型,这时候p的指向不能改变,但可以通过p修改所指向的字符。 现在来看这三个声明: 第一个是const char **p;。这里的const修饰的是char,也就是说,p是一个指向指针的指针,而这个被指向的指针指向的是const char。也就是说,**p是一个常量字符,不能通过*p或p来修改这个字符的值。不过p本身可以指向不同的指针,那些指针也必须指向const char。比如,p可以指向一个const char*数组的元素,但每个元素都是指向常量字符的指针。 第二个是char *const *p;。这里const修饰的是中间的*,即p是一个指向常量指针的指针,这个常量指针指向char类型。也就是说,*p是一个指向char的常量指针,所以*p不能被修改(即不能改变*p所指向的地址),但可以通过*p修改所指向的char的值。而p本身可以指向不同的指针,但这些指针本身是常量指针,指向char。例如,p可以是一个数组,数组中的每个元素都是char *const类型,而p可以遍历这个数组,但每个数组元素自己的指向不能被改变。 第三个是char **const p;。这里const修饰的是最外层的指针p,所以p本身是一个常量指针,指向一个指向char的指针。也就是说,p的地址不能改变,不能再指向其他地方,但可以通过*p或者**p来修改所指向的char的值。例如,p可能被初始化为指向某个char **变量,之后不能再改变p的值,但可以通过p来修改该变量的内容。 为了验证是否正确,我需要考虑每个声明中const的位置,并确定其作用域。比如,对于const char **p,constchar前面,所以被指向的字符是常量。而char *const *p,const*后面,所以中间的指针是常量。char **const p中,const在变量名旁边,所以指针p本身是常量。 可能容易混淆的是中间的情况,即char *const *p。这时候,*p是一个const指针,指向char。也就是说,不能通过p来改变*p的值(即*p不能指向其他地方),但可以通过*p来修改它指向的字符。而p本身可以指向不同的指针,只要这些指针是char *const类型。 另外,还要注意指针的级别。这三个都是二级指针,但const修饰的位置不同,导致不同的限制。需要举例说明每个情况下的合法操作和非法的操作,以帮助理解。 例如: 对于const char **p: - **p = 'a'; 这是非法的,因为**p是const char,不能修改。 - *p = new_char_ptr; 这是合法的,因为*p是一个指向const char的指针,可以改变其指向。 - p = &another_ptr; 合法,因为p本身不是const。 对于char *const *p: - *p = new_char_ptr; 非法,因为*p是const指针,不能改变指向。 - **p = 'a'; 合法,因为char不是const,可以通过*p修改。 - p = &another_const_ptr; 合法,因为p本身可以改变指向另一个char *const指针。 对于char **const p: - p = &another_ptr; 非法,因为p本身是const。 - *p = new_char_ptr; 合法,因为*p是一个char指针,可以改变指向。 - **p = 'a'; 合法,因为指向的char可以被修改。 总结来说,这三个声明的区别在于const修饰的位置不同,分别限制了不同的部分:指向的内容、中间的指针,或者最外层的指针本身。理解这些需要仔细分析每个const的作用范围,以及指针的层级关系。</think>以下是对三个指针声明的详细解析,通过对比表格和示例帮助理解复杂指针声明中的`const`用法: ```c const char **p; // 二级指针:指向【常量字符指针】的指针 char *const *p; // 二级指针:指向【字符型常量指针】的指针 char **const p; // 常量二级指针:指向字符指针的常量指针 ``` ### 📌 三维对比表 | 声明形式 | 指针层级 | 可修改区域 | 典型应用场景 | |------------------|----------|---------------------------|--------------------------| | `const char **p` | 二级指针 | 可以改变p的指向<br>可以改变*p的值<br>**不能修改**最终字符 | 只读字符串数组的遍历 | | `char *const *p` | 二级指针 | 可以改变p的指向<br>**不能改变** *p的值<br>可以修改最终字符 | 固定指针数组的遍历 | | `char **const p` | 二级指针 | **不能改变**p的指向<br>可以改变*p的值<br>可以修改最终字符 | 固定指针数组的引用 | ### 🧩 内存模型分析 ```c /* 示例数据 */ char str1[] = "Hello"; char str2[] = "World"; char *ptr_arr[] = {str1, str2, NULL}; ``` #### 1️⃣ `const char **p` 示例 ```c const char **p = ptr_arr; // 需要强制类型转换 // 允许的操作: p++; // ✅ 移动指针到下一个元素 *p = "NewString"; // ✅ 修改指针数组元素(但实际应避免,因为元素是char*) // 禁止的操作: **p = 'h'; // ❌ 不能修改原始字符串内容 ``` #### 2️⃣ `char *const *p` 示例 ```c char *const *p = ptr_arr; // 允许的操作: p++; // ✅ 移动指针到下一个元素 **p = 'W'; // ✅ 修改str2首字符为'W' // 禁止的操作: *p = str1; // ❌ 不能修改指针数组元素 ``` #### 3️⃣ `char **const p` 示例 ```c char **const p = ptr_arr; // 允许的操作: *p = str2; // ✅ 修改指针数组首个元素的指向 **p = 'h'; // ✅ 修改str1首字符为'h' // 禁止的操作: p++; // ❌ 指针本身不可变 ``` ### 🔄 类型转换关系图 ``` 常规指针 ──────┬───▶ const char ** (增加只读属性需要显式转换) │ ├───▶ char *const * (安全自动转换) │ └───▶ char **const (安全自动转换) ``` ### 💡 使用建议 1. 优先使用`const char **`处理只读数据,增强类型安全性 2. 当需要固定指针数组元素时,使用`char *const *`声明 3. 对于需要固定访问入口的场景,使用`char **const`声明 4. 注意编译器警告,必要时使用强制类型转换:`(const char **)ptr` 通过这种层级化的分析方式,可以更清晰地理解`const`在多级指针中的不同作用范围。实际开发中建议结合编译器的类型检查功能,验证指针操作的合法性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值