欢迎光临
我们一直在努力

C 语言入门:字符数组与字符串处理全解析

1. 引言

在 C 语言中,并没有专门的「字符串类型」,字符串是通过字符数组来存储和处理的。理解字符数组与 string.h 中的常用字符串函数,是掌握 C 语言输入输出、文本处理的基础。

本文将从字符数组讲起,逐个介绍 gets、puts、strcpy、strcat、strcmp、strlen 的用法,最后延伸到二维字符数组的应用场景。

2. 字符与字符数组

2.1 单个字符

C 语言用 char 类型表示单个字符,字符常量用单引号包裹:

char ch = 'A';

字符在内存中本质上存储的是对应的 ASCII 码值,例如 'A' 对应整数 65。

2.2 字符数组

字符数组就是存放多个字符的数组:

char chars[5] = {'h', 'e', 'l', 'l', 'o'};

这个数组有 5 个元素,分别保存了 5 个字符,但它还不是标准意义上的字符串,因为缺少字符串结束标志。

3. 字符串的本质

在 C 语言中,字符串是由字符组成、并以 '\\\\0'(空字符,ASCII 码为 0)作为结束标志的字符序列。

char str[6] = {'h', 'e', 'l', 'l', 'o', '\\\\0'};

更常见的写法是直接用双引号初始化:

char str[] = "hello";

编译器会自动在末尾补上 '\\\\0',因此数组实际长度为 6(5 个字符 + 1 个结束符)。

字符串结束标志 '\\\\0' 至关重要:所有字符串处理函数都依赖它判断字符串在哪里结束。如果字符串数组没有足够的空间存放 '\\\\0',程序可能越界访问,导致不可预期的错误。

4. gets 与 puts:字符串的输入输出

4.1 puts 输出字符串

puts 用于输出一个字符串,并在输出后自动换行:

#include <stdio.h>

int main(void) {
char str[] = "Hello, C!";
puts(str);
return 0;
}

输出结果:

Hello, C!

4.2 gets 输入字符串

gets 用于从标准输入读取一行字符串,直到遇到换行符。它会把换行符替换为 '\\\\0' 存入数组:

#include <stdio.h>

int main(void) {
char name[20];
printf("请输入你的名字:");
gets(name);
printf("你好,");
puts(name);
return 0;
}

⚠️ 重要警告:gets 不检查数组边界。如果用户输入超过数组容量的内容,会发生缓冲区溢出,这是著名的安全隐患,因此 C11 标准已废除 gets。实际开发中请使用更安全的 fgets:

#include <stdio.h>

int main(void) {
char name[20];
printf("请输入你的名字:");
fgets(name, sizeof(name), stdin);
/* 去掉 fgets 保留的换行符 */
name[strcspn(name, "\\n")] = '\\\\0';
printf("你好,%s\\n", name);
return 0;
}

注:上例中的 strcspn 需要包含 <string.h> 头文件。为了循序渐进,学习阶段仍可以用 gets 理解字符串输入原理,但动手写项目时请务必使用 fgets。

5. 常用字符串处理函数

使用以下函数前,需要包含头文件:

#include <string.h>

5.1 strlen:统计字符串长度

strlen 返回字符串中字符的个数,不包括结尾的 '\\\\0'。

#include <stdio.h>
#include <string.h>

int main(void) {
char str[] = "hello";
printf("字符串长度:%zu\\n", strlen(str));
return 0;
}

输出结果:

字符串长度:5

5.2 strcpy:拷贝字符串

strcpy 用于把源字符串(包括 '\\\\0')完整拷贝到目标数组中。

函数原型:char *strcpy(char *dest, const char *src);

#include <stdio.h>
#include <string.h>

int main(void) {
char src[] = "hello";
char dest[20];

strcpy(dest, src);
printf("拷贝结果:%s\\n", dest);
return 0;
}

使用时注意:

  • 目标数组必须有足够的空间容纳源字符串及其 '\\\\0'。
  • dest 不能是字符串字面量(如 char *dest = "abc";),因为字面量通常存放在只读区域。

5.3 strcat:拼接字符串

strcat 把源字符串追加到目标字符串的末尾,目标字符串原本的 '\\\\0' 会被覆盖,最终形成一个新的以 '\\\\0' 结尾的字符串。

函数原型:char *strcat(char *dest, const char *src);

#include <stdio.h>
#include <string.h>

int main(void) {
char first[30] = "Hello";
char second[] = " World";

strcat(first, second);
printf("拼接结果:%s\\n", first);
return 0;
}

输出结果:

拼接结果:Hello World

同样要保证目标数组 first 有足够空间容纳拼接后的全部内容,否则会发生越界。

5.4 strcmp:比较字符串

strcmp 按字典序逐字符比较两个字符串,比较的是字符的 ASCII 码值。

函数原型:int strcmp(const char *s1, const char *s2);

返回值含义:

  • 返回 0:两个字符串相等;
  • 返回正数:s1 大于 s2;
  • 返回负数:s1 小于 s2。

#include <stdio.h>
#include <string.h>

int main(void) {
char a[] = "apple";
char b[] = "banana";

int result = strcmp(a, b);

if (result == 0) {
printf("两个字符串相等\\n");
} else if (result < 0) {
printf("\\"%s\\" 小于 \\"%s\\"\\n", a, b);
} else {
printf("\\"%s\\" 大于 \\"%s\\"\\n", a, b);
}
return 0;
}

输出结果:

"apple" 小于 "banana"

注意:字符串比较不能直接写 a == b,因为那比较的是两个数组的地址,而不是内容。必须使用 strcmp。

6. 二维数组与字符串数组

6.1 二维数组基础

二维数组可以理解为「数组的数组」,常用于存储表格数据:

int matrix[3][4]; /* 3 行 4 列的整型矩阵 */

初始化方式:

int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};

遍历二维数组需要嵌套循环:

#include <stdio.h>

int main(void) {
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};

for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrix[i][j]);
}
printf("\\n");
}
return 0;
}

输出结果:

1 2 3
4 5 6

6.2 二维字符数组:存储多个字符串

二维字符数组最常见的用途是存放一组字符串。每一行是一个一维字符数组,代表一个字符串:

#include <stdio.h>

int main(void) {
char fruits[3][20] = {
"apple",
"banana",
"cherry"
};

for (int i = 0; i < 3; i++) {
puts(fruits[i]);
}
return 0;
}

输出结果:

apple
banana
cherry

这里 char fruits[3][20] 表示可以存放 3 个字符串,每个字符串最多 19 个字符(留 1 位给 '\\\\0')。

6.3 结合字符串函数操作二维字符数组

我们可以把前面学到的函数配合二维字符数组一起使用,例如找出最长的字符串:

#include <stdio.h>
#include <string.h>

int main(void) {
char words[4][20] = {
"cat",
"elephant",
"dog",
"bird"
};

int max_index = 0;

for (int i = 1; i < 4; i++) {
if (strlen(words[i]) > strlen(words[max_index])) {
max_index = i;
}
}

printf("最长的单词是:%s\\n", words[max_index]);
return 0;
}

输出结果:

最长的单词是:elephant

7. 综合示例:一个简易通讯录

下面用一个完整示例,把 gets、puts、strcpy、strcat、strcmp、strlen 和二维数组串起来:

#include <stdio.h>
#include <string.h>

#define MAX_NAMES 3
#define MAX_LEN 20

int main(void) {
char names[MAX_NAMES][MAX_LEN];
char greeting[50] = "你好,";

/* 输入 3 个名字 */
for (int i = 0; i < MAX_NAMES; i++) {
printf("请输入第 %d 个名字:", i + 1);
fgets(names[i], MAX_LEN, stdin);
names[i][strcspn(names[i], "\\n")] = '\\\\0';
}

/* 查找指定的名字 */
char target[MAX_LEN];
printf("请输入要查找的名字:");
fgets(target, MAX_LEN, stdin);
target[strcspn(target, "\\n")] = '\\\\0';

int found = 0;
for (int i = 0; i < MAX_NAMES; i++) {
if (strcmp(names[i], target) == 0) {
strcat(greeting, target);
puts(greeting);
printf("名字长度:%zu\\n", strlen(target));
found = 1;
break;
}
}

if (!found) {
printf("未找到该名字。\\n");
}

return 0;
}

运行示例:

请输入第 1 个名字:Alice
请输入第 2 个名字:Bob
请输入第 3 个名字:Cindy
请输入要查找的名字:Bob
你好,Bob
名字长度:3

8. 常见错误与注意事项

  • 数组越界:使用 strcpy、strcat、gets 时,必须确保目标数组有足够空间。
  • 忘记 '\\\\0':手动构造字符数组当字符串用时,不要遗漏结束标志。
  • 误用 == 比较字符串:== 比较的是地址,而非内容,字符串比较请用 strcmp。
  • strlen 不包含 '\\\\0':分配空间时记得为结束符多留 1 个字节。
  • 尽量不用 gets:学习可以,实际开发请使用 fgets,从源头避免缓冲区溢出。
  • 9. 总结

    • 字符串在 C 语言中是以 '\\\\0' 结尾的字符数组。
    • puts 输出字符串,gets 输入字符串(有安全隐患,推荐用 fgets)。
    • strlen 统计长度(不含 '\\\\0'),strcpy 拷贝,strcat 拼接,strcmp 比较。
    • 二维字符数组适合存储一组字符串,每行代表一个字符串。
    • 使用所有字符串函数前,务必保证目标空间足够,避免越界访问。

    掌握这些基础后,你就可以处理 C 语言中绝大多数文本场景了。建议动手把每个示例都跑一遍,并尝试修改数组容量、观察越界风险,加深理解。

    赞(0)
    未经允许不得转载:171主机测评 » C 语言入门:字符数组与字符串处理全解析
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址