C++ 字符数组
字符数组是C++中一种特殊的数组类型,专门用于存储字符序列,包括文本、句子和单词等。在C++中,字符数组与字符串有着密切的关系,了解它们的工作原理对于文本处理至关重要。
什么是字符数组?
字符数组是一个存储字符类型(char
)数据的数组。它可以存储多个字符,并且在C++中经常用于表示字符串。
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
上面的代码创建了一个包含6个元素的字符数组,最后一个元素是'\0'
,这是一个特殊的空字符(null character),用于标记字符串的结束。
在C++中,字符串实际上是以空字符'\0'
结尾的字符数组。这个空字符是字符串的终止符,帮助函数知道字符串在哪里结束。
字符数组的声明与初始化
基本声明
你可以像声明普通数组那样声明一个字符数组:
char arrayName[size];
其中size
是数组的大小,表示它可以存储的字符数量。
初始化方法
字符数组有几种初始化方式:
1. 通过单个字符初始化
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
2. 使用字符串字面量(推荐方式)
char greeting[] = "Hello";
在这种情况下,C++编译器会自动在字符串末尾添加空字符'\0'
,并且会自动计算数组大小为6(5个字符加上终止符)。
3. 声明后逐个赋值
char greeting[6];
greeting[0] = 'H';
greeting[1] = 'e';
greeting[2] = 'l';
greeting[3] = 'l';
greeting[4] = 'o';
greeting[5] = '\0';
字符数组与字符串字面量的区别
虽然字符数组可以用来表示字符串,但C++中的字符串字面量(如"Hello"
)与字符数组是有区别的:
- 字符串字面量是只读的,不能被修改
- 字符数组是可以修改的
例如:
char str[] = "Hello"; // 创建字符数组,可以修改
str[0] = 'J'; // 合法,修改为"Jello"
const char* ptr = "Hello"; // 指向字符串字面量,不能修改
// ptr[0] = 'J'; // 非法,会导致未定义行为
字符数组的操作
输入输出
可以使用cin
和cout
来读取和输出字符数组:
#include <iostream>
using namespace std;
int main() {
char name[50];
cout << "请输入您的名字: ";
cin >> name; // 注意:这只会读取到第一个空格
cout << "您好," << name << "!" << endl;
return 0;
}
输入: John Doe
输出: 您好,John!
使用cin
读取字符数组时,它只会读取到第一个空白字符(空格、制表符或换行符)。要读取包含空格的整行文本,应使用cin.getline()
。
使用 cin.getline() 读取整行
#include <iostream>
using namespace std;
int main() {
char name[50];
cout << "请输入您的全名: ";
cin.getline(name, 50); // 读取最多49个字符(保留一个位置给'\0')
cout << "您好," << name << "!" << endl;
return 0;
}
输入: John Doe
输出: 您好,John Doe!
字符数组的常见操作
C++提供了<cstring>
库,其中包含许多用于处理字符数组的函数:
1. 计算字符串长度:strlen()
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char greeting[] = "Hello, World!";
cout << "字符串长度: " << strlen(greeting) << endl; // 不计算'\0'
cout << "数组大小: " << sizeof(greeting) << endl; // 包含'\0'
return 0;
}
输出:
字符串长度: 13
数组大小: 14
2. 字符串复制:strcpy()
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char source[] = "Hello, World!";
char destination[20];
strcpy(destination, source);
cout << "复制后的字符串: " << destination << endl;
return 0;
}
输出:
复制后的字符串: Hello, World!
使用strcpy()
时要确保目标数组有足够的空间存储源字符串,否则会导致缓冲区溢出。更安全的替代方案是使用strncpy()
,它允许指定最大复制的字符数。
3. 字符串连接:strcat()
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char first[50] = "Hello, ";
char second[] = "World!";
strcat(first, second);
cout << "连接后的字符串: " << first << endl;
return 0;
}
输出:
连接后的字符串: Hello, World!
4. 字符串比较:strcmp()
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char str1[] = "apple";
char str2[] = "banana";
int result = strcmp(str1, str2);
if (result < 0) {
cout << str1 << " 在字典序上小于 " << str2 << endl;
} else if (result > 0) {
cout << str1 << " 在字典序上大于 " << str2 << endl;
} else {
cout << str1 << " 等于 " << str2 << endl;
}
return 0;
}
输出:
apple 在字典序上小于 banana
字符数组的实际应用场景
1. 简单的文本编辑器
#include <iostream>
#include <cstring>
using namespace std;
int main() {
const int MAX_LINES = 10;
const int MAX_CHARS = 100;
char text[MAX_LINES][MAX_CHARS];
int lineCount = 0;
cout << "简单文本编辑器 (最多 " << MAX_LINES << " 行)\n";
cout << "每行输入完后按Enter,输入空行结束\n";
// 读取输入
while (lineCount < MAX_LINES) {
cout << lineCount + 1 << "> ";
cin.getline(text[lineCount], MAX_CHARS);
// 如果是空行则结束输入
if (strlen(text[lineCount]) == 0) {
break;
}
lineCount++;
}
// 显示文本
cout << "\n--- 您输入的文本 ---\n";
for (int i = 0; i < lineCount; i++) {
cout << text[i] << endl;
}
return 0;
}
2. 简单的密码验证系统
#include <iostream>
#include <cstring>
using namespace std;
int main() {
const char correctPassword[] = "secure123";
char inputPassword[50];
bool isAuthenticated = false;
int attempts = 0;
const int MAX_ATTEMPTS = 3;
while (attempts < MAX_ATTEMPTS && !isAuthenticated) {
cout << "请输入密码: ";
cin.getline(inputPassword, 50);
if (strcmp(inputPassword, correctPassword) == 0) {
isAuthenticated = true;
} else {
attempts++;
cout << "密码错误!还剩 " << (MAX_ATTEMPTS - attempts) << " 次机会\n";
}
}
if (isAuthenticated) {
cout << "认证成功!欢迎使用系统。" << endl;
} else {
cout << "认证失败!请稍后再试。" << endl;
}
return 0;
}
字符数组与现代C++
尽管字符数组在C++中很常见,但现代C++更推荐使用std::string
类来处理字符串,因为它更安全、更方便:
#include <iostream>
#include <string>
using namespace std;
int main() {
string name;
cout << "请输入您的名字: ";
getline(cin, name);
cout << "您好," << name << "!" << endl;
return 0;
}
std::string
可以自动管理内存,避免了缓冲区溢出的风险,并提供了更多方便的字符串操作函数。当你熟悉了字符数组的基础后,强烈建议转向使用std::string
。
字符数组的常见错误
- 忘记添加终止字符:字符数组如果没有以
'\0'
结尾,会导致未定义行为。
char name[5] = {'J', 'o', 'h', 'n'}; // 没有终止符
cout << name; // 可能会打印出"John"后跟随随机字符,直到找到某个内存中的'\0'
- 缓冲区溢出:向字符数组写入超过其容量的数据。
char name[5];
strcpy(name, "Alexander"); // 危险!会覆盖相邻内存
- 使用
==
比较字符串:在C++中,字符数组不能直接使用==
进行比较,需使用strcmp
。
char str1[] = "Hello";
char str2[] = "Hello";
if (str1 == str2) { // 错误:比较的是指针,而非内容
// 这段代码可能不会执行
}
if (strcmp(str1, str2) == 0) { // 正确:比较字符串内容
// 这段代码会执行
}
总结
字符数组是C++中处理文本的基础方式,了解它的工作原理对于理解字符串处理非常重要。本文介绍了:
- 字符数组的定义和声明
- 不同的初始化方式
- 字符数组与字符串字面量的区别
- 常见的字符串操作函数
- 实际应用场景
- 与现代C++
std::string
的对比
虽然现代C++提供了更便捷的std::string
类,但理解字符数组仍然很重要,因为它是C++字符串处理的基础,也是与C语言兼容的桥梁。
练习
- 编写一个程序,统计用户输入的字符串中元音字母(a, e, i, o, u)的个数。
- 创建一个程序,将用户输入的字符串反转并显示出来。
- 实现一个简单的凯撒密码程序,将输入的文本中每个字母向后移动3位(如a变为d)。
- 编写一个程序,检查用户输入的字符串是否是回文(正读反读都一样,如"madam")。
- 创建一个简单的单词计数程序,统计用户输入文本中的单词数量。
进一步阅读资源
- C++标准库中的
<cstring>
头文件 - 了解
std::string
类及其与字符数组的互操作 - 字符编码和多字节字符处理
- 字符串安全性问题及防范措施
通过掌握字符数组的基础知识,你将为C++中更复杂的字符串处理打下坚实的基础。