第一部分:char - 字符类型
char 是 C 语言中的一个基本数据类型,它的全称是 "character"(字符),它的本质是一个小的整数。

(图片来源网络,侵删)
char 的存储
在内存中,char 类型通常占用 1 个字节(8 bits),它被用来表示一个字符,'A', 'b', '1', 等。
关键点: 计算机不直接存储字符 'A',而是存储它对应的数字编码,最常用的编码是 ASCII (American Standard Code for Information Interchange)。
'A'的 ASCII 码是65'B'的 ASCII 码是66'a'的 ASCII 码是97'0'的 ASCII 码是48
这意味着,你可以对 char 类型进行算术运算。
#include <stdio.h>
int main() {
char c1 = 'A';
char c2 = 'B';
// 输出字符
printf("c1 is: %c\n", c1); // %c 是格式化输出字符的占位符
// 输出字符对应的 ASCII 码
printf("ASCII code of c1 is: %d\n", c1); // %d 是格式化输出整数的占位符
// 算术运算
char c3 = c1 + 1;
printf("c1 + 1 is: %c\n", c3); // 输出 'B'
return 0;
}
char 的两种形式
C 语言中的 char 有两种形式,它们在语法上几乎一样,但用途不同:

(图片来源网络,侵删)
char: 可以存储正负值(范围通常是 -128 到 127),它既可以表示字符,也可以作为一个小整数使用。unsigned char: 只能存储非负值(范围通常是 0 到 255),当你只关心原始字节,而不关心它是否代表一个可打印字符时(例如处理图像文件、网络数据包),通常会使用unsigned char。
第二部分:C 语言中的字符串
这是初学者最容易出错的地方。C 语言本身并没有一个原生的 "string"(字符串)数据类型,所谓的 "字符串" 是通过字符数组来实现的。
字符串的表示:以 '\0' 结尾的字符数组
C 语言中的字符串被定义为一个字符数组,并且这个数组的最后一个元素必须是空字符(Null Character),写作 '\0'。
'\0'的 ASCII 码是0。'\0'是一个特殊的标记,它告诉字符串处理函数(如printf,strlen等):“字符串到这里就结束了”。
示例:
#include <stdio.h>
int main() {
// 方式一:显式地包含 '\0'
char str1[] = {'H', 'e', 'l', 'l', 'o', '\0'};
printf("str1: %s\n", str1); // %s 是格式化输出字符串的占位符
// 方式二:编译器自动添加 '\0' (最常用)
// 当你用双引号 "" 定义一个字符串字面量时,C 编译器会自动在末尾加上 '\0'
char str2[] = "Hello";
// str2 在内存中实际是: {'H', 'e', 'l', 'l', 'o', '\0'}
// 方式三:使用指针
// 这里 "Hello" 仍然是一个以 '\0' 结尾的字符数组,str3 指向它的第一个元素 'H'
char *str3 = "Hello";
return 0;
}
字符串 vs. 字符数组
虽然字符串是字符数组,但并非所有字符数组都是字符串。

(图片来源网络,侵删)
- 字符串:必须以
'\0'- 字符数组:只是一个字符的集合,不一定以
'\0' - 字符数组:只是一个字符的集合,不一定以
示例:
#include <stdio.h>
#include <string.h> // 用于 strlen 函数
int main() {
// 这是一个字符串,因为它以 '\0'
char my_string[] = "Hi";
printf("Length of my_string: %zu\n", strlen(my_string)); // 输出 2
// 这只是一个字符数组,不是字符串
char my_chars[5] = {'H', 'i', '!', '!', '!'};
// my_chars 没有以 '\0'
// 如果你尝试用 %s 输出它,会发生未定义行为
// printf("my_chars: %s\n", my_chars); // 危险!可能会打印出乱码,甚至导致程序崩溃
// 你可以像普通数组一样逐个字符访问
my_chars[0] = 'J';
printf("my_chars[0]: %c\n", my_chars[0]); // 输出 'J'
return 0;
}
第三部分:char 数组与 char 指针
这两种方式都可以用来表示字符串,但它们有重要的区别。
char 数组 (Character Array)
- 本质:一块连续的内存空间,用于存储字符(包括
'\0')。 - 数组的内容可以被修改。
- 内存位置:通常存储在栈上。
char greeting[50] = "Hello"; greeting[0] = 'J'; // 合法,可以修改内容 strcpy(greeting, "New Greeting"); // 合法,可以修改内容
char 指针 (Character Pointer)
- 本质:一个变量,它存储的是字符串第一个字符的内存地址。
- 指向一个字符串常量,通常不应该被修改。
- 内存位置:指针变量本身在栈上,但它指向的字符串常量通常存储在只读数据段。
char *message = "Hello"; // message[0] = 'J'; // 危险!这通常会导致未定义行为,因为 "Hello" 是一个常量,存储在只读内存区。 // strcpy(message, "New Message"); // 同样危险,不能修改它指向的内容。 // 你可以修改指针本身,让它指向别的地方 char another_message[] = "World"; message = another_message; // 合法,message 指向 "World"
总结区别:
| 特性 | char greeting[] |
char *message |
|---|---|---|
| 内存分配 | 编译时分配固定大小的空间(在栈上) | 指针变量在栈上,指向别处(通常是只读区) |
| 大小 | 固定,由声明决定 | 指针大小固定(通常是4或8字节),指向的字符串大小不固定 |
| 常见用途 | 存储和修改可变长度的字符串 | 传递字符串、指向字符串常量 |
第四部分:常用的字符串处理函数
为了方便操作字符串,C 标准库 <string.h> 提供了一系列函数,使用这些函数时,请确保目标缓冲区足够大,避免缓冲区溢出。
strlen(str): 获取字符串长度(不包括'\0')。strcpy(dest, src): 将src字符串复制到dest。dest必须足够大。strncpy(dest, src, n): 安全一点的复制,最多复制n个字符。strcat(dest, src): 将src字符串拼接到dest末尾。dest必须足够大。strcmp(s1, s2): 比较两个字符串,返回 0(相等)、正数(s1 > s2)、负数(s1 < s2)。sprintf(buffer, format, ...): 格式化数据并写入字符串缓冲区,类似printf,但输出目标是字符串。
示例:
#include <stdio.h>
#include <string.h>
int main() {
char first_name[50] = "John";
char last_name[] = "Doe";
char full_name[100]; // 确保空间足够
// 1. 拼接字符串
strcpy(full_name, first_name); // full_name 现在是 "John"
strcat(full_name, " "); // full_name 现在是 "John "
strcat(full_name, last_name); // full_name 现在是 "John Doe"
printf("Full Name: %s\n", full_name);
// 2. 获取长度
printf("Length of full_name: %zu\n", strlen(full_name)); // 输出 8
// 3. 比较字符串
if (strcmp(first_name, "John") == 0) {
printf("First name is indeed John.\n");
}
return 0;
}
第五部分:现代 C++ 中的 std::string
如果你正在使用 C++,强烈建议使用 std::string 而不是 C 风格的字符数组。std::string 是一个类,它为你处理了所有底层的内存管理、大小调整和拼接等操作,更加安全和方便。
#include <iostream>
#include <string> // C++ string header
int main() {
// C++ std::string
std::string s1 = "Hello";
std::string s2 = " World";
// 可以直接拼接,无需担心缓冲区
std::string s3 = s1 + s2;
std::cout << "s3: " << s3 << std::endl;
// 可以轻松获取长度
std::cout << "Length of s3: " << s3.length() << std::endl;
// 可以像数组一样访问和修改
s3[0] = 'J';
std::cout << "Modified s3: " << s3 << std::endl;
return 0;
}
| 概念 | 描述 | 关键点 |
|---|---|---|
char |
基本数据类型,表示一个字符,本质是1字节的整数。 | 占用1字节,可以进行算术运算。 |
| 字符串 | C 语言中没有原生类型,用字符数组实现。 | 必须以'\0'结尾作为结束标记。 |
char[] |
字符数组,用于存储字符串,内容可修改,大小固定。 | 存储在栈上,适合存储和修改可变字符串。 |
| *`char`** | 字符指针,通常指向字符串常量,内容不可修改。 | 指向只读区,适合传递字符串或指向常量。 |
<string.h> |
C 标准库,提供字符串操作函数。 | 使用时务必注意缓冲区大小,防止溢出。 |
std::string |
C++ 标准库,安全的字符串类。 | 自动管理内存,是 C++ 中处理字符串的首选。 |
