面试题答案
一键面试内存分配关系
- 字符串常量:字符串常量存储在程序的只读数据段。例如
"Hello"
这样的字符串常量,在程序运行期间其值不能被修改,占用一段连续的内存空间。 const char*
:const char*
是一个指针,它可以指向字符串常量。指针本身存储在栈上(如果是局部变量),而它指向的字符串常量在只读数据段。例如const char* str = "Hello";
,str
在栈上,"Hello"
在只读数据段。string
:string
类对象存储在栈上(如果是局部变量),它内部有一个指向动态分配内存的指针,该动态分配的内存用于存储字符串内容,位于堆上。例如string s = "Hello";
,s
本身在栈上,s
内部指向的存储"Hello"
的内存位于堆上。
转换方式及内存管理
const char*
转string
:- 可以使用
string
的构造函数。例如:
const char* cstr = "Hello"; string s(cstr);
- 内存管理:
string
类会在堆上分配足够的空间来存储cstr
指向的字符串内容,然后复制字符串。当string
对象生命周期结束时,string
类的析构函数会释放堆上分配的内存。
- 可以使用
string
转const char*
:- 可以使用
string
类的c_str()
成员函数。例如:
string s = "Hello"; const char* cstr = s.c_str();
- 内存管理:
c_str()
返回的指针指向string
对象内部的字符数组(该数组以'\0'
结尾),但string
类对象负责管理这块内存。调用者不应尝试释放该指针指向的内存。而且,只要string
对象的内容不发生改变,c_str()
返回的指针就保持有效。如果string
对象发生改变(例如插入、删除字符),c_str()
返回的指针可能不再有效。
- 可以使用
- 字符串常量转
string
:- 同样使用
string
的构造函数。例如:
string s = "Hello";
- 内存管理:
string
类在堆上分配内存来存储字符串常量的内容,并复制字符串。当string
对象销毁时,释放堆上的内存。
- 同样使用
- 字符串常量转
const char*
:- 直接赋值即可。例如:
const char* cstr = "Hello";
- 内存管理:
cstr
指向只读数据段中的字符串常量,不需要额外的内存分配或释放操作,因为字符串常量的生命周期与程序相同。
可能出现的内存问题及解决方案
- 内存泄漏(
const char*
转string
):- 问题:如果在构造
string
对象后,没有正确释放相关资源(例如在异常情况下),可能导致内存泄漏。 - 解决方案:使用智能指针或确保
string
对象在作用域结束时正常析构。例如,在try - catch
块中正确处理异常,避免资源泄漏。
- 问题:如果在构造
- 悬空指针(
string
转const char*
):- 问题:如果
string
对象被销毁,而其c_str()
返回的指针仍在使用,就会产生悬空指针。 - 解决方案:确保在
string
对象的生命周期内使用c_str()
返回的指针,或者在需要长期使用字符串内容时,将其复制到新的const char*
指向的独立分配的内存中(例如使用strdup
函数,在 C++ 中可以自己实现复制逻辑)。
- 问题:如果
- 缓冲区溢出:
- 问题:当从
const char*
向string
转换或反向转换时,如果操作不当,可能导致缓冲区溢出。例如,在手动复制const char*
内容到string
预留的缓冲区时,如果const char*
内容过长就会溢出。 - 解决方案:使用安全的字符串操作函数,
string
类本身在处理字符串复制等操作时相对安全,但在手动操作时要注意边界检查。
- 问题:当从