我在刷算法题的时候经常遇到,用了' '出现警告或者使用" "直接报错,尤其是在字符串部分(py玩家后遗症/(ㄒoㄒ)/~~)在详细了解后总结一下加强记忆。
总的来说在 C++ 中,双引号 ""
和单引号 ''
是完全不同的语法元素,数据类型、存储方式有所差异。
对比维度 | 单引号 '' (字符常量) | 双引号 "" (字符串常量) |
---|---|---|
数据类型 | char | const char[] (字符数组) |
存储内容 | 单个字符的 ASCII 码 | 字符序列 + 末尾 '\0' 结束符 |
占用字节 | 固定 1 字节 | 字符数 + 1 字节(含 '\0' ) |
内容限制 | 仅 1 个字符(非空) | 0 个或多个字符(可空) |
赋值对象 | char 变量 | const char* / char[] |
隐式转换 | 可转 int (ASCII 码) | 可转 const char* (首地址) |
示例 | '5' 、'\t' 、'Z' | "" 、"abc" 、"x\ny" |
一、核心定义与数据类型
这是最根本的区别:单引号表示字符常量(char
类型),双引号表示字符串常量(const char[]
类型,本质是字符数组)。
符号 | 表示内容 | 数据类型 | 本质含义 |
---|---|---|---|
'a' | 单个字符常量 | char | 单个 ASCII 字符 |
"a" | 字符串常量 | const char[] | 以 '\0' 结尾的字符数组 |
二、存储方式与字节长度
两者在内存中的存储形式和占用字节数完全不同,这是导致后续所有区别的根源。
1. 单引号(字符常量)
- 存储:直接存储单个字符的 ASCII 码值,占用 1 个字节(
char
类型的标准大小)。 - 示例:
'A'
在内存中存储为 ASCII 码65
(二进制01000001
),仅占 1 字节。 - 长度计算:
sizeof('A') == 1
(固定为 1,与字符无关)。
2. 双引号(字符串常量)
- 存储:本质是 字符数组,除了显式的字符外,末尾会自动添加一个
'\0'
空字符(作为字符串结束标志),总占用字节数 = 显式字符数 + 1。 - 示例:
"A"
在内存中实际是{'A', '\0'}
,占用 2 字节;
"hello"
是{'h','e','l','l','o','\0'}
,占用 6 字节。 - 长度计算:
sizeof("A") == 2
(包含'\0'
的总字节数);strlen("A") == 1
(strlen
统计'\0'
之前的字符数,需包含<cstring>
头文件)。
三、语法规则:内容限制不同
C++ 对两者的语法有严格限制,违反会导致编译错误。
1. 单引号 ''
的限制
- 只能包含 1 个字符:不能为空(
''
编译错误),也不能包含多个字符('ab'
是「多字符常量」,语法不推荐,值为各字符 ASCII 码的组合,结果不确定)。 - 合法示例:
'5'
、'+'
、'\n'
(转义字符,本质是单个字符,ASCII 码为 10)。 - 非法示例:
''
(空字符常量,错误)、'12'
(多字符,不推荐)。
2. 双引号 ""
的限制
- 可包含 0 个或多个字符:空字符串
""
合法(仅存储'\0'
,占 1 字节),多字符也合法(如"123abc"
)。 - 支持转义字符:如
"a\nb"
表示'a'
、换行符'\n'
、'b'
、'\0'
,共 4 字节。 - 合法示例:
""
(空字符串)、"Hello, C++"
、"x\ty"
(包含制表符)。 - 非法示例:无本质非法内容,但需注意转义字符的正确性(如
"a\b"
合法,"a\z"
非法,因为\z
不是有效转义符)。
下面代码最能体现区别
string s3 =s1+s2;//bwabwa
cout << s3<<endl;
//-------------插入push_back()和insert() push_back为void类型,删除erase()
s1.push_back('c');
string s4 = s1; //bwac
s4.insert(s4.begin(),'i');//ibwac
s1.erase(s1.begin()+3); //bwa s1.erase(s.begin() + 1, s.begin() + 3); 删除范围
//--------------replace() repalce()函数:s.replace(pos,len,ss),将s从pos开始的len个字符替换成ss,
s3.replace(2,2,"aa"); //bwabwa->bwaawa
cout<<s3<<endl;
//s.replace(pos,n1,n2,c),将s从pos开始的n1个字符替换成n2个字符c。
s3.replace(2,2,1,'z'); //bwaawa-> bwzwa
四、如何选择区分
两者的使用场景严格依赖于变量 / 函数参数的类型,混用会导致编译错误。
1. 单引号 ''
的使用场景
- 给
char
类型变量赋值:char c1 = 'a'; // 正确:char 变量匹配字符常量 char c2 = 65; // 正确:等价于 'A'(ASCII 码) char c3 = "a"; // 错误:字符串常量(const char[])无法赋值给 char 变量
- 作为
char
类型参数传递给函数:putchar('B'); // 正确:putchar 接收 char 类型 cout << 'c'; // 正确:输出 ASCII 码对应的字符(显示 'c')
2. 双引号 ""
的使用场景
- 给字符串相关类型赋值(字符指针、字符数组):
const char* s1 = "hello"; // 正确:字符串常量赋值给字符指针(指向常量区) char s2[] = "world"; // 正确:字符串常量初始化字符数组(会复制到栈区) char s3[6] = "hello"; // 正确:数组大小 = 字符数 + 1(包含 '\0') char s4[5] = "hello"; // 错误:数组大小不足(需 6 字节,实际仅存 5 个字符,无 '\0')
- 作为字符串参数传递给函数:
cpp
puts("Hi!"); // 正确:puts 接收字符串常量 strlen("test"); // 正确:计算字符串长度(结果为 4) cout << "C++"; // 正确:输出字符串(自动识别 '\0' 结束)
五、隐式转换与兼容性
1. 字符常量('c'
)的隐式转换
- 可隐式转换为
int
类型(值为对应的 ASCII 码):int num = '0'; // 正确:num = 48('0' 的 ASCII 码) cout << 'z'; // 输出 122('z' 的 ASCII 码)
2. 字符串常量("c"
)的隐式转换
- 可隐式转换为
const char*
类型(指向字符串的首地址),但不能转换为int
或char
:const char* p = "abc"; // 正确:p 指向 'a' 的地址 int len = "abc"; // 错误:字符串无法直接转换为 int
- 字符串常量是只读的:赋值给非
const
指针会导致未定义行为(C++11 后编译器会警告):char* p = "hello"; // 不推荐:"hello" 是 const,修改 p[0] 会崩溃 const char* p = "hello";// 正确:明确只读,避免误修改
六、特殊情况:空值与转义字符
1. 空值处理
- 字符常量无 “空值”:
''
非法,若需表示空字符,需用转义字符'\0'
(ASCII 码 0):char null_char = '\0'; // 正确:表示空字符(占 1 字节)
- 字符串常量可有空值:
""
是合法的空字符串,仅包含'\0'
(占 1 字节):const char* empty_str = ""; cout << strlen(empty_str); // 输出 0(无有效字符) cout << sizeof(empty_str); // 输出 8(指针大小,64 位系统) cout << sizeof(""); // 输出 1(仅 '\0')
2. 转义字符的使用
- 单引号中:转义字符需用
\
,如'\''
表示字符'
,'\n'
表示换行符。 - 双引号中:转义字符同样需用
\
,如"\""
表示字符串"
,"a\\b"
表示字符串a\b
。
常见错误示例与原因
- 错误 1:字符串赋值给
char
变量char c = "a"; // 错误:类型不匹配(const char[] → char)
- 错误 2:单引号包含多个字符
char c = 'ab'; // 不推荐:多字符常量,值为 0x6162(依赖编译器,结果不确定)
- 错误 3:字符串数组未留
'\0'
空间char arr[3] = "abc"; // 错误:"abc" 需 4 字节(含 '\0'),数组仅 3 字节,截断导致无结束符
- 错误 4:修改字符串常量
char* s = "hello"; s[0] = 'H'; // 未定义行为:"hello" 是只读常量,修改会崩溃
转载自CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/weixin_47520540/article/details/151683441