跳到主要内容

C++ 字符数组

字符数组是C++中一种特殊的数组类型,专门用于存储字符序列,包括文本、句子和单词等。在C++中,字符数组与字符串有着密切的关系,了解它们的工作原理对于文本处理至关重要。

什么是字符数组?

字符数组是一个存储字符类型(char)数据的数组。它可以存储多个字符,并且在C++中经常用于表示字符串。

cpp
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

上面的代码创建了一个包含6个元素的字符数组,最后一个元素是'\0',这是一个特殊的空字符(null character),用于标记字符串的结束。

备注

在C++中,字符串实际上是以空字符'\0'结尾的字符数组。这个空字符是字符串的终止符,帮助函数知道字符串在哪里结束。

字符数组的声明与初始化

基本声明

你可以像声明普通数组那样声明一个字符数组:

cpp
char arrayName[size];

其中size是数组的大小,表示它可以存储的字符数量。

初始化方法

字符数组有几种初始化方式:

1. 通过单个字符初始化

cpp
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

2. 使用字符串字面量(推荐方式)

cpp
char greeting[] = "Hello";

在这种情况下,C++编译器会自动在字符串末尾添加空字符'\0',并且会自动计算数组大小为6(5个字符加上终止符)。

3. 声明后逐个赋值

cpp
char greeting[6];
greeting[0] = 'H';
greeting[1] = 'e';
greeting[2] = 'l';
greeting[3] = 'l';
greeting[4] = 'o';
greeting[5] = '\0';

字符数组与字符串字面量的区别

虽然字符数组可以用来表示字符串,但C++中的字符串字面量(如"Hello")与字符数组是有区别的:

  1. 字符串字面量是只读的,不能被修改
  2. 字符数组是可以修改的

例如:

cpp
char str[] = "Hello";  // 创建字符数组,可以修改
str[0] = 'J'; // 合法,修改为"Jello"

const char* ptr = "Hello"; // 指向字符串字面量,不能修改
// ptr[0] = 'J'; // 非法,会导致未定义行为

字符数组的操作

输入输出

可以使用cincout来读取和输出字符数组:

cpp
#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() 读取整行

cpp
#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()

cpp
#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()

cpp
#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()

cpp
#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()

cpp
#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. 简单的文本编辑器

cpp
#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. 简单的密码验证系统

cpp
#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类来处理字符串,因为它更安全、更方便:

cpp
#include <iostream>
#include <string>
using namespace std;

int main() {
string name;
cout << "请输入您的名字: ";
getline(cin, name);
cout << "您好," << name << "!" << endl;
return 0;
}
提示

std::string可以自动管理内存,避免了缓冲区溢出的风险,并提供了更多方便的字符串操作函数。当你熟悉了字符数组的基础后,强烈建议转向使用std::string

字符数组的常见错误

  1. 忘记添加终止字符:字符数组如果没有以'\0'结尾,会导致未定义行为。
cpp
char name[5] = {'J', 'o', 'h', 'n'};  // 没有终止符
cout << name; // 可能会打印出"John"后跟随随机字符,直到找到某个内存中的'\0'
  1. 缓冲区溢出:向字符数组写入超过其容量的数据。
cpp
char name[5];
strcpy(name, "Alexander"); // 危险!会覆盖相邻内存
  1. 使用==比较字符串:在C++中,字符数组不能直接使用==进行比较,需使用strcmp
cpp
char str1[] = "Hello";
char str2[] = "Hello";

if (str1 == str2) { // 错误:比较的是指针,而非内容
// 这段代码可能不会执行
}

if (strcmp(str1, str2) == 0) { // 正确:比较字符串内容
// 这段代码会执行
}

总结

字符数组是C++中处理文本的基础方式,了解它的工作原理对于理解字符串处理非常重要。本文介绍了:

  • 字符数组的定义和声明
  • 不同的初始化方式
  • 字符数组与字符串字面量的区别
  • 常见的字符串操作函数
  • 实际应用场景
  • 与现代C++ std::string 的对比

虽然现代C++提供了更便捷的std::string类,但理解字符数组仍然很重要,因为它是C++字符串处理的基础,也是与C语言兼容的桥梁。

练习

  1. 编写一个程序,统计用户输入的字符串中元音字母(a, e, i, o, u)的个数。
  2. 创建一个程序,将用户输入的字符串反转并显示出来。
  3. 实现一个简单的凯撒密码程序,将输入的文本中每个字母向后移动3位(如a变为d)。
  4. 编写一个程序,检查用户输入的字符串是否是回文(正读反读都一样,如"madam")。
  5. 创建一个简单的单词计数程序,统计用户输入文本中的单词数量。

进一步阅读资源

  • C++标准库中的<cstring>头文件
  • 了解std::string类及其与字符数组的互操作
  • 字符编码和多字节字符处理
  • 字符串安全性问题及防范措施

通过掌握字符数组的基础知识,你将为C++中更复杂的字符串处理打下坚实的基础。