- 核心概念:C 语言没有内置的 "string" 类型
- C 语言中的字符串是如何表示的?
- 最重要的字符串函数库:
<string.h> - C++ 中的
std::string(作为对比) - 总结与最佳实践
核心概念:C 语言没有内置的 "string" 类型
这一点是理解 C 语言字符串的关键,与 C++、Java、Python 等现代语言不同,C 语言没有一个原生的、名为 string 的数据类型。

你不能这样写:
// 错误!C 语言中没有 string 类型 string name = "Alice";
C 语言是如何处理文本(字符串)的呢?答案是:通过字符数组。
C 语言中的字符串是如何表示的?
在 C 语言中,字符串被实现为一个以 空字符 ('\0') 结尾的字符数组。
- 字符数组: 一系列连续的内存空间,每个空间存放一个
char类型的字符。 - 空字符 (
'\0'): 这是一个特殊的字符,其 ASCII 码值为 0,它标志着字符串的结束,C 语言标准库中的所有字符串函数都依赖这个空字符来判断字符串的长度。
两种主要的字符串声明方式:
使用字符数组

char str1[] = "Hello, World!";
// 等价于:
// char str1[] = {'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0'};
- 内存布局:
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | H | e | l | l | o | , | | W | o | r | l | d | ! | \0 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - 特点:
- 编译器会自动计算字符个数并添加结尾的
'\0'。 - 数组的大小是固定的。
sizeof(str1)的值是 14(13个字符 + 1个'\0')。 - 这种方式声明的字符串是可修改的。
- 编译器会自动计算字符个数并添加结尾的
使用字符指针
char *str2 = "Hello, World!";
-
内存布局:
str2是一个指针变量,它存储的是字符串字面量"Hello, World!"在内存中的首地址。- 字符串字面量通常存储在程序的只读数据段。
str2本身是一个变量,可以指向其他地址,但它最初指向的内容是不可修改的。
-
特点:
str2是一个指针,它指向字符串的第一个字符。sizeof(str2)的值通常不是字符串的长度,而是指针变量本身的大小(在 64 位系统上是 8 字节,在 32 位系统上是 4 字节)。- 警告:尝试修改
str2指向的内容是未定义行为,通常会导致程序崩溃。str2[0] = 'M'; // 错误!可能导致段错误
最重要的字符串函数库:<string.h>
为了方便我们操作字符串,C 标准库提供了 <string.h> 头文件,里面包含了一系列非常有用的函数。

下面是一些最常用的函数:
| 函数 | 描述 | 示例 |
|---|---|---|
strlen(s) |
返回字符串 s 的长度(不包括结尾的 '\0')。 |
len = strlen("abc"); // len 的值是 3 |
strcpy(dest, src) |
将字符串 src(源)复制到 dest(目标)中。目标空间必须足够大! |
strcpy(buffer, "Hello"); |
strcat(dest, src) |
将字符串 src 连接到 dest 的末尾。目标空间必须足够大! |
strcat(buffer, " World!"); |
strcmp(s1, s2) |
比较两个字符串,返回值: - 0:s1 和 s2 相等- < 0:s1 小于 s2 (按字典序)- > 0:s1 大于 s2 |
if (strcmp(name, "admin") == 0) { ... } |
strncpy(dest, src, n) |
安全版本的 strcpy,最多复制 n 个字符。注意:src 比 n 短,dest 不会自动添加 '\0'! |
strncpy(buffer, "Hi", 5); |
strncat(dest, src, n) |
安全版本的 strcat,最多连接 n 个字符。 |
strncat(buffer, "!", 1); |
strchr(s, c) |
在字符串 s 中查找字符 c,返回指向该字符的指针,如果找不到则返回 NULL。 |
p = strchr("hello", 'l'); // p 指向第二个 'l' |
strstr(s1, s2) |
在字符串 s1 中查找子串 s2,返回指向子串首字符的指针,如果找不到则返回 NULL。 |
p = strstr("hello world", "world"); |
示例代码:
#include <stdio.h>
#include <string.h> // 必须包含这个头文件
int main() {
char str1[50] = "Hello"; // 确保空间足够大
char str2[] = ", C String!";
char str3[50];
// 1. strlen
printf("Length of str1: %zu\n", strlen(str1)); // 使用 %zu 打印 size_t 类型
// 2. strcpy
strcpy(str3, str1); // 将 str1 复制到 str3
printf("After strcpy, str3 is: %s\n", str3);
// 3. strcat
strcat(str3, str2); // 将 str2 连接到 str3
printf("After strcat, str3 is: %s\n", str3);
// 4. strcmp
if (strcmp(str1, "Hello") == 0) {
printf("str1 is equal to 'Hello'\n");
}
// 5. strncpy (更安全)
char dest[10];
strncpy(dest, "This is a very long string", 9); // 只复制9个字符
dest[9] = '\0'; // 手动添加结束符!非常重要!
printf("After strncpy, dest is: %s\n", dest);
return 0;
}
C++ 中的 std::string (作为对比)
很多人在学习 C 语言时,会听到 C++ 的 std::string,这常常造成混淆。
-
*C 语言 (`char`)**:
- 本质: 一个指向字符的指针。
- 管理: 手动管理内存,你需要自己分配足够的内存(
malloc/new),并在使用后释放(free/delete),如果忘记'\0',函数就会越界读取,导致严重错误(缓冲区溢出)。 - 操作: 依赖
<string.h>中的 C 风格函数,使用起来不够直观(如strcpy(dest, src)需要记住参数顺序)。
-
C++ (
std::string):-
本质: 一个类,封装了字符数组和相关的操作。
-
管理: 自动管理内存,当你创建
std::string对象时,它会自动分配内存;当对象生命周期结束时,析构函数会自动释放内存,你完全不用担心内存泄漏。 -
操作: 提供了成员函数和操作符重载,使用起来非常直观和方便。
#include <string> #include <iostream> int main() { std::string s1 = "Hello"; std::string s2 = ", C++ String!"; // 自动管理内存,无需担心大小 std::string s3 = s1 + s2; // 使用 + 操作符连接,非常直观 // 获取长度使用成员函数 std::cout << "Length of s3: " << s3.length() << std::endl; // 访问和修改像普通数组一样安全 s3[0] = 'M'; std::cout << "s3 is now: " << s3 << std::endl; return 0; }
-
总结对比:
| 特性 | C String (char*) | C++ std::string |
| :--- | :--- | :--- |
| 类型 | 指针 | 类对象 |
| 内存管理 | 手动 (malloc, free) | 自动 (RAII) |
| 安全性 | 低,容易出错(缓冲区溢出) | 高,边界检查更完善 |
| 易用性 | 较低,函数式调用 | 高,面向对象,操作符重载 |
| 性能 | 轻量级,直接操作内存 | 稍重,但有优化(如写时拷贝) |
总结与最佳实践
-
记住核心: C 语言中的
string不是一种类型,而是以'\0'结尾的字符数组。 -
两种声明:
char str[] = "...":用于定义可修改的字符串,数组大小固定。char *str = "...":用于定义指向只读字符串字面量的指针。
-
使用
<string.h>: 所有字符串操作都应使用标准库函数,不要自己用循环实现,这样既安全又高效。 -
注意安全:
- 使用
strcpy和strcat时,务必确保目标缓冲区足够大,否则会导致缓冲区溢出,这是严重的安全漏洞。 - 优先使用更安全的
strncpy和strncat,但要注意它们不会自动添加'\0',你需要手动处理。
- 使用
-
现代 C++ 的选择: 如果你在使用 C++,强烈推荐使用
std::string来处理所有文本,它能为你解决绝大多数 C 风格字符串带来的麻烦,只有在需要与 C 语言库交互或进行底层性能优化时,才使用const char*或char*。
希望这个详细的解释能帮助你彻底理解 C 语言中的 string!
