C语言字符串详解
1. 什么是字符串?
在C语言中,字符串是以null字符(`'\0')结尾的字符数组。字符串不是C语言的基本数据类型,而是通过字符数组来实现的。
字符串的特点:
- 以null字符
'\0'
结尾 - 存储在字符数组中
- 可以使用字符串字面量初始化
- 有一系列标准库函数用于处理
2. 字符串的基本概念
C语言字符串 字符串声明 字符串输入输出 字符串函数 字符串操作 动态字符串 字符数组 字符串字面量 printf/scanf gets/puts fgets/fputs strlen/strcpy strcat/strcmp strchr/strstr 遍历 修改 搜索 malloc/free 动态分配
3. 字符串的声明和初始化
基本字符串操作
c
#include <stdio.h>
#include <string.h>
int main() {
printf("=== 字符串声明和初始化 ===\n");
// 方式1:字符数组(不是字符串,因为没有null终止符)
char arr1[] = {'H', 'e', 'l', 'l', 'o'};
// 方式2:字符串(以null字符'\0'结尾)
char arr2[] = "Hello"; // 自动添加'\0'
// 方式3:指定大小的字符数组
char arr3[10] = "Hello";
// 方式4:逐个初始化
char arr4[6];
arr4[0] = 'H';
arr4[1] = 'e';
arr4[2] = 'l';
arr4[3] = 'l';
arr4[4] = 'o';
arr4[5] = '\0'; // 重要:必须添加null终止符
// 方式5:字符指针指向字符串字面量
char *str_ptr = "Hello World";
printf("arr1 (字符数组): ");
for (int i = 0; i < 5; i++) {
printf("%c", arr1[i]);
}
printf("\n");
printf("arr2 (字符串): %s\n", arr2);
printf("arr3: %s\n", arr3);
printf("arr4: %s\n", arr4);
printf("str_ptr: %s\n", str_ptr);
// 字符串长度 vs 数组大小
printf("arr2字符串长度: %lu\n", strlen(arr2));
printf("arr2数组大小: %lu\n", sizeof(arr2)); // 包括'\0'
// 显示字符串内容(包括null字符)
printf("arr2详细内容: ");
for (int i = 0; i <= strlen(arr2); i++) {
if (arr2[i] == '\0') {
printf("'\\0' ");
} else {
printf("'%c' ", arr2[i]);
}
}
printf("\n");
return 0;
}
字符串字面量 vs 字符数组
c
#include <stdio.h>
int main() {
printf("=== 字符串字面量 vs 字符数组 ===\n");
// 字符串字面量(存储在只读内存)
char *literal1 = "Hello";
char *literal2 = "Hello";
// 字符数组(存储在可写内存)
char array1[] = "Hello";
char array2[] = "Hello";
printf("字符串字面量:\n");
printf("literal1: %s (地址: %p)\n", literal1, literal1);
printf("literal2: %s (地址: %p)\n", literal2, literal2);
printf("字面量地址相同吗? %s\n", literal1 == literal2 ? "是" : "否");
printf("\n字符数组:\n");
printf("array1: %s (地址: %p)\n", array1, array1);
printf("array2: %s (地址: %p)\n", array2, array2);
printf("数组地址相同吗? %s\n", array1 == array2 ? "是" : "否");
// 修改尝试
array1[0] = 'h'; // ✅ 可以修改
printf("修改后array1: %s\n", array1);
// literal1[0] = 'h'; // ❌ 运行时错误:尝试修改只读内存
return 0;
}
4. 字符串输入输出
基本输入输出函数
c
#include <stdio.h>
#include <string.h>
int main() {
char name[50];
char sentence[100];
printf("=== 字符串输入输出 ===\n");
// 使用scanf输入字符串(遇到空格停止)
printf("请输入你的名字(不要有空格): ");
scanf("%s", name);
printf("你好, %s!\n", name);
// 清除输入缓冲区
while (getchar() != '\n');
// 使用fgets输入包含空格的字符串
printf("请输入一句话: ");
fgets(sentence, sizeof(sentence), stdin);
// 移除fgets读取的换行符
size_t len = strlen(sentence);
if (len > 0 && sentence[len - 1] == '\n') {
sentence[len - 1] = '\0';
}
printf("你输入的是: %s\n", sentence);
// 使用puts输出(自动添加换行)
printf("使用puts输出: ");
puts(sentence);
// 使用printf输出
printf("使用printf输出: %s\n", sentence);
return 0;
}
安全的字符串输入
c
#include <stdio.h>
#include <string.h>
#include <ctype.h>
// 安全的字符串输入函数
void safeInput(char *buffer, int size, const char *prompt) {
printf("%s", prompt);
if (fgets(buffer, size, stdin) != NULL) {
// 移除换行符
size_t len = strlen(buffer);
if (len > 0 && buffer[len - 1] == '\n') {
buffer[len - 1] = '\0';
} else {
// 清除输入缓冲区剩余字符
int c;
while ((c = getchar()) != '\n' && c != EOF);
}
}
}
// 去除字符串两端的空格
void trimString(char *str) {
char *start = str;
char *end = str + strlen(str) - 1;
// 去除开头空格
while (isspace(*start)) start++;
// 去除结尾空格
while (end > start && isspace(*end)) end--;
// 移动字符串
memmove(str, start, end - start + 1);
str[end - start + 1] = '\0';
}
int main() {
char name[50];
char email[100];
printf("=== 安全的字符串输入 ===\n");
// 使用安全输入函数
safeInput(name, sizeof(name), "请输入你的全名: ");
safeInput(email, sizeof(email), "请输入你的邮箱: ");
printf("\n输入验证:\n");
printf("姓名: '%s'\n", name);
printf("邮箱: '%s'\n", email);
// 测试去除空格
char test_string[] = " 前后有空格的字 符串 ";
printf("\n去除空格测试:\n");
printf("原始: '%s'\n", test_string);
trimString(test_string);
printf("去除后: '%s'\n", test_string);
return 0;
}
5. 字符串处理函数
C语言提供了丰富的字符串处理函数,这些函数在string.h
头文件中声明。
基本字符串函数
c
#include <stdio.h>
#include <string.h>
int main() {
printf("=== 基本字符串函数 ===\n");
char str1[50] = "Hello";
char str2[50] = "World";
char str3[100];
char str4[50];
// strlen - 字符串长度
printf("str1长度: %lu\n", strlen(str1));
// strcpy - 字符串复制
strcpy(str3, str1);
printf("复制后str3: %s\n", str3);
// strcat - 字符串连接
strcat(str3, " ");
strcat(str3, str2);
printf("连接后str3: %s\n", str3);
// strcmp - 字符串比较
printf("str1和str2比较: %d\n", strcmp(str1, str2));
printf("str1和\"Hello\"比较: %d\n", strcmp(str1, "Hello"));
// strncpy - 安全复制
strncpy(str4, str3, sizeof(str4) - 1);
str4[sizeof(str4) - 1] = '\0'; // 确保null终止
printf("安全复制str4: %s\n", str4);
// strncat - 安全连接
char str5[20] = "Hello";
strncat(str5, " World!!!", sizeof(str5) - strlen(str5) - 1);
printf("安全连接str5: %s\n", str5);
return 0;
}
字符串搜索函数
c
#include <stdio.h>
#include <string.h>
int main() {
printf("=== 字符串搜索函数 ===\n");
char text[] = "Hello World! Welcome to C programming.";
char *result;
printf("原始文本: %s\n", text);
// strchr - 查找字符第一次出现
result = strchr(text, 'W');
if (result != NULL) {
printf("找到'W': %s\n", result);
}
// strrchr - 查找字符最后一次出现
result = strrchr(text, 'o');
if (result != NULL) {
printf("最后一个'o': %s\n", result);
}
// strstr - 查找子字符串
result = strstr(text, "Welcome");
if (result != NULL) {
printf("找到'Welcome': %s\n", result);
}
// strpbrk - 查找任何指定字符的第一次出现
result = strpbrk(text, "aeiou");
if (result != NULL) {
printf("第一个元音字母: %c (在: %s)\n", *result, result);
}
// strspn - 查找只包含指定字符的初始段长度
char digits[] = "12345abc";
size_t span = strspn(digits, "0123456789");
printf("'%s'中数字前缀长度: %lu\n", digits, span);
// strcspn - 查找不包含指定字符的初始段长度
span = strcspn(text, " ,.!");
printf("第一个分隔符前长度: %lu\n", span);
return 0;
}
字符串分割函数
c
#include <stdio.h>
#include <string.h>
int main() {
printf("=== 字符串分割函数 ===\n");
char csv_data[] = "John,25,Engineer,New York";
char path[] = "/home/user/documents/file.txt";
char sentence[] = "This is a sample sentence with multiple words";
printf("CSV数据: %s\n", csv_data);
printf("路径: %s\n", path);
printf("句子: %s\n", sentence);
// 使用strtok分割字符串
printf("\n分割CSV数据:\n");
char *token = strtok(csv_data, ",");
int field_count = 0;
while (token != NULL) {
printf("字段 %d: %s\n", ++field_count, token);
token = strtok(NULL, ",");
}
// 分割路径
printf("\n分割路径:\n");
char path_copy[100];
strcpy(path_copy, path);
token = strtok(path_copy, "/");
while (token != NULL) {
printf("路径组件: %s\n", token);
token = strtok(NULL, "/");
}
// 分割句子为单词
printf("\n分割句子为单词:\n");
char sentence_copy[100];
strcpy(sentence_copy, sentence);
token = strtok(sentence_copy, " ");
int word_count = 0;
while (token != NULL) {
printf("单词 %d: %s\n", ++word_count, token);
token = strtok(NULL, " ");
}
return 0;
}
6. 自定义字符串函数
理解字符串函数的最好方式是自己实现它们。
自定义字符串函数实现
c
#include <stdio.h>
#include <stddef.h>
// 自定义字符串长度函数
size_t myStrlen(const char *str) {
const char *s = str;
while (*s != '\0') {
s++;
}
return s - str;
}
// 自定义字符串复制函数
char* myStrcpy(char *dest, const char *src) {
char *start = dest;
while (*src != '\0') {
*dest = *src;
dest++;
src++;
}
*dest = '\0';
return start;
}
// 自定义字符串连接函数
char* myStrcat(char *dest, const char *src) {
char *start = dest;
// 找到dest的结尾
while (*dest != '\0') {
dest++;
}
// 复制src到dest的结尾
while (*src != '\0') {
*dest = *src;
dest++;
src++;
}
*dest = '\0';
return start;
}
// 自定义字符串比较函数
int myStrcmp(const char *str1, const char *str2) {
while (*str1 && *str2 && *str1 == *str2) {
str1++;
str2++;
}
return *(unsigned char*)str1 - *(unsigned char*)str2;
}
// 自定义字符串反转函数
char* myStrrev(char *str) {
if (str == NULL) return NULL;
char *start = str;
char *end = str;
char temp;
// 找到字符串结尾
while (*end != '\0') {
end++;
}
end--; // 指向最后一个字符
// 反转字符串
while (start < end) {
temp = *start;
*start = *end;
*end = temp;
start++;
end--;
}
return str;
}
// 自定义字符串查找函数
char* myStrchr(const char *str, int ch) {
while (*str != '\0') {
if (*str == ch) {
return (char*)str;
}
str++;
}
return NULL;
}
int main() {
printf("=== 自定义字符串函数 ===\n");
char str1[50] = "Hello";
char str2[50] = "World";
char result[100];
printf("myStrlen(\"%s\") = %lu\n", str1, myStrlen(str1));
myStrcpy(result, str1);
printf("myStrcpy: %s\n", result);
myStrcat(result, " ");
myStrcat(result, str2);
printf("myStrcat: %s\n", result);
printf("myStrcmp(\"%s\", \"%s\") = %d\n", str1, str2, myStrcmp(str1, str2));
printf("myStrcmp(\"%s\", \"%s\") = %d\n", str1, "Hello", myStrcmp(str1, "Hello"));
char rev_str[] = "Hello";
printf("myStrrev(\"%s\") = %s\n", rev_str, myStrrev(rev_str));
char *found = myStrchr("Hello World", 'W');
if (found != NULL) {
printf("myStrchr找到'W': %s\n", found);
}
return 0;
}
7. 字符串与数字转换
数字与字符串相互转换
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
printf("=== 字符串与数字转换 ===\n");
// 字符串转整数
char int_str[] = "12345";
char float_str[] = "123.45";
char hex_str[] = "1A3F";
int int_val = atoi(int_str);
long long_val = atol(int_str);
double double_val = atof(float_str);
printf("atoi(\"%s\") = %d\n", int_str, int_val);
printf("atol(\"%s\") = %ld\n", int_str, long_val);
printf("atof(\"%s\") = %.2f\n", float_str, double_val);
// 使用strtol进行更安全的转换
char *endptr;
long safe_long = strtol(hex_str, &endptr, 16); // 16进制
printf("strtol(\"%s\", 16) = %ld\n", hex_str, safe_long);
// 数字转字符串
char buffer[50];
int num = 12345;
double pi = 3.14159;
sprintf(buffer, "整数: %d", num);
printf("sprintf: %s\n", buffer);
sprintf(buffer, "浮点数: %.2f", pi);
printf("sprintf: %s\n", buffer);
// 安全的数字转字符串(snprintf)
snprintf(buffer, sizeof(buffer), "格式化: %d, %.2f", num, pi);
printf("snprintf: %s\n", buffer);
return 0;
}
高级数字转换
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
// 安全的字符串转整数函数
int safeStringToInt(const char *str, int *result) {
if (str == NULL || *str == '\0') {
return 0; // 失败
}
char *endptr;
errno = 0; // 清除错误
long val = strtol(str, &endptr, 10);
// 检查错误
if (errno == ERANGE || val > INT_MAX || val < INT_MIN) {
return 0; // 溢出
}
// 检查是否整个字符串都被转换
if (*endptr != '\0') {
return 0; // 无效字符
}
*result = (int)val;
return 1; // 成功
}
// 安全的字符串转浮点数函数
int safeStringToDouble(const char *str, double *result) {
if (str == NULL || *str == '\0') {
return 0;
}
char *endptr;
errno = 0;
double val = strtod(str, &endptr);
if (errno == ERANGE) {
return 0; // 溢出
}
if (*endptr != '\0') {
return 0; // 无效字符
}
*result = val;
return 1;
}
int main() {
printf("=== 安全的数字转换 ===\n");
char valid_int[] = "12345";
char invalid_int[] = "123abc";
char overflow_int[] = "999999999999999";
char valid_double[] = "123.456";
char invalid_double[] = "123.45.6";
int int_result;
double double_result;
// 测试有效的整数转换
if (safeStringToInt(valid_int, &int_result)) {
printf("成功转换整数: %d\n", int_result);
} else {
printf("整数转换失败: %s\n", valid_int);
}
// 测试无效的整数转换
if (safeStringToInt(invalid_int, &int_result)) {
printf("成功转换整数: %d\n", int_result);
} else {
printf("整数转换失败: %s\n", invalid_int);
}
// 测试溢出的整数转换
if (safeStringToInt(overflow_int, &int_result)) {
printf("成功转换整数: %d\n", int_result);
} else {
printf("整数转换失败(溢出): %s\n", overflow_int);
}
// 测试有效的浮点数转换
if (safeStringToDouble(valid_double, &double_result)) {
printf("成功转换浮点数: %.3f\n", double_result);
} else {
printf("浮点数转换失败: %s\n", valid_double);
}
// 测试无效的浮点数转换
if (safeStringToDouble(invalid_double, &double_result)) {
printf("成功转换浮点数: %.3f\n", double_result);
} else {
printf("浮点数转换失败: %s\n", invalid_double);
}
return 0;
}
8. 动态字符串
动态字符串操作
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 动态字符串结构
typedef struct {
char *data;
size_t length;
size_t capacity;
} DynamicString;
// 创建动态字符串
DynamicString* createDynamicString(size_t initial_capacity) {
DynamicString *str = malloc(sizeof(DynamicString));
if (str == NULL) return NULL;
str->data = malloc(initial_capacity);
if (str->data == NULL) {
free(str);
return NULL;
}
str->data[0] = '\0';
str->length = 0;
str->capacity = initial_capacity;
return str;
}
// 追加字符串到动态字符串
int appendString(DynamicString *str, const char *append) {
size_t append_len = strlen(append);
size_t new_length = str->length + append_len;
// 检查是否需要扩容
if (new_length + 1 > str->capacity) {
size_t new_capacity = str->capacity * 2;
while (new_capacity <= new_length + 1) {
new_capacity *= 2;
}
char *new_data = realloc(str->data, new_capacity);
if (new_data == NULL) {
return 0; // 失败
}
str->data = new_data;
str->capacity = new_capacity;
}
// 追加字符串
strcpy(str->data + str->length, append);
str->length = new_length;
return 1; // 成功
}
// 获取C风格字符串
const char* getCString(const DynamicString *str) {
return str->data;
}
// 释放动态字符串
void freeDynamicString(DynamicString *str) {
if (str != NULL) {
free(str->data);
free(str);
}
}
// 清空动态字符串
void clearDynamicString(DynamicString *str) {
str->data[0] = '\0';
str->length = 0;
}
int main() {
printf("=== 动态字符串操作 ===\n");
// 创建动态字符串
DynamicString *dyn_str = createDynamicString(16);
if (dyn_str == NULL) {
printf("创建动态字符串失败!\n");
return 1;
}
printf("初始状态: 长度=%lu, 容量=%lu\n",
dyn_str->length, dyn_str->capacity);
// 追加多个字符串
appendString(dyn_str, "Hello");
appendString(dyn_str, " ");
appendString(dyn_str, "World!");
appendString(dyn_str, " This is a dynamic string example.");
printf("追加后: 长度=%lu, 容量=%lu\n",
dyn_str->length, dyn_str->capacity);
printf("内容: %s\n", getCString(dyn_str));
// 清空并重新使用
clearDynamicString(dyn_str);
appendString(dyn_str, "重新开始!");
printf("清空后: %s\n", getCString(dyn_str));
// 释放内存
freeDynamicString(dyn_str);
return 0;
}
9. 实际应用示例
示例1:简单的文本分析器
c
#include <stdio.h>
#include <string.h>
#include <ctype.h>
// 文本分析结构
typedef struct {
int char_count;
int word_count;
int line_count;
int sentence_count;
} TextStats;
// 分析文本
TextStats analyzeText(const char *text) {
TextStats stats = {0, 0, 0, 0};
int in_word = 0;
for (int i = 0; text[i] != '\0'; i++) {
// 字符计数
stats.char_count++;
// 行计数
if (text[i] == '\n') {
stats.line_count++;
}
// 句子计数
if (text[i] == '.' || text[i] == '!' || text[i] == '?') {
stats.sentence_count++;
}
// 单词计数
if (isspace(text[i])) {
in_word = 0;
} else if (!in_word) {
in_word = 1;
stats.word_count++;
}
}
// 如果文本不以换行符结束,也要计数最后一行
if (stats.char_count > 0) {
stats.line_count++;
}
return stats;
}
// 查找最长的单词
void findLongestWord(const char *text, char *longest_word, int max_length) {
char current_word[100];
char longest[100] = "";
int word_index = 0;
int in_word = 0;
for (int i = 0; text[i] != '\0'; i++) {
if (isspace(text[i]) || ispunct(text[i])) {
if (in_word) {
current_word[word_index] = '\0';
if (strlen(current_word) > strlen(longest)) {
strcpy(longest, current_word);
}
word_index = 0;
in_word = 0;
}
} else {
current_word[word_index++] = text[i];
in_word = 1;
}
}
// 处理最后一个单词
if (in_word) {
current_word[word_index] = '\0';
if (strlen(current_word) > strlen(longest)) {
strcpy(longest, current_word);
}
}
strncpy(longest_word, longest, max_length - 1);
longest_word[max_length - 1] = '\0';
}
int main() {
printf("=== 简单文本分析器 ===\n");
char sample_text[] = "Hello world! This is a sample text.\n"
"It contains multiple lines and sentences.\n"
"We will analyze this text for statistics.";
printf("分析文本:\n%s\n\n", sample_text);
// 分析文本
TextStats stats = analyzeText(sample_text);
printf("文本统计:\n");
printf("字符数: %d\n", stats.char_count);
printf("单词数: %d\n", stats.word_count);
printf("行数: %d\n", stats.line_count);
printf("句子数: %d\n", stats.sentence_count);
// 查找最长单词
char longest_word[100];
findLongestWord(sample_text, longest_word, sizeof(longest_word));
printf("最长单词: %s (长度: %lu)\n", longest_word, strlen(longest_word));
return 0;
}
示例2:简单的命令行解析器
c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_ARGS 10
#define MAX_ARG_LENGTH 50
// 命令结构
typedef struct {
char *name;
void (*execute)(int argc, char *argv[]);
const char *description;
} Command;
// 各种命令函数
void cmd_help(int argc, char *argv[]) {
printf("可用命令:\n");
printf("help - 显示帮助信息\n");
printf("echo - 回显参数\n");
printf("calc - 简单计算器\n");
printf("exit - 退出程序\n");
}
void cmd_echo(int argc, char *argv[]) {
printf("回显: ");
for (int i = 1; i < argc; i++) {
printf("%s ", argv[i]);
}
printf("\n");
}
void cmd_calc(int argc, char *argv[]) {
if (argc != 4) {
printf("用法: calc <数字1> <操作符> <数字2>\n");
return;
}
double num1 = atof(argv[1]);
double num2 = atof(argv[2]);
char op = argv[3][0];
double result;
switch (op) {
case '+': result = num1 + num2; break;
case '-': result = num1 - num2; break;
case '*': result = num1 * num2; break;
case '/':
if (num2 == 0) {
printf("错误:除数不能为零\n");
return;
}
result = num1 / num2;
break;
default:
printf("错误:不支持的操作符 '%c'\n", op);
return;
}
printf("计算结果: %.2f %c %.2f = %.2f\n", num1, op, num2, result);
}
void cmd_exit(int argc, char *argv[]) {
printf("再见!\n");
exit(0);
}
// 命令表
Command commands[] = {
{"help", cmd_help, "显示帮助信息"},
{"echo", cmd_echo, "回显参数"},
{"calc", cmd_calc, "简单计算器"},
{"exit", cmd_exit, "退出程序"}
};
int command_count = sizeof(commands) / sizeof(commands[0]);
// 解析命令行输入
void parseCommand(char *input) {
char *args[MAX_ARGS];
int argc = 0;
// 使用strtok分割命令行
char *token = strtok(input, " \t\n");
while (token != NULL && argc < MAX_ARGS) {
args[argc++] = token;
token = strtok(NULL, " \t\n");
}
if (argc == 0) {
return; // 空命令
}
// 查找并执行命令
for (int i = 0; i < command_count; i++) {
if (strcmp(args[0], commands[i].name) == 0) {
commands[i].execute(argc, args);
return;
}
}
printf("未知命令: %s\n", args[0]);
printf("输入 'help' 查看可用命令\n");
}
int main() {
printf("=== 简单命令行解析器 ===\n");
printf("输入 'help' 查看可用命令\n\n");
char input[256];
while (1) {
printf("> ");
if (fgets(input, sizeof(input), stdin) == NULL) {
break;
}
// 移除换行符
size_t len = strlen(input);
if (len > 0 && input[len - 1] == '\n') {
input[len - 1] = '\0';
}
// 解析并执行命令
parseCommand(input);
}
return 0;
}
10. 字符串常见错误和最佳实践
常见错误示例
c
#include <stdio.h>
#include <string.h>
int main() {
printf("=== 字符串常见错误 ===\n");
// ❌ 错误1:字符串未正确终止
/*
char str1[5] = {'H', 'e', 'l', 'l', 'o'}; // 缺少'\0'
printf("%s\n", str1); // 未定义行为
*/
// ✅ 正确:确保字符串以'\0'结尾
char str1_correct[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
printf("正确终止: %s\n", str1_correct);
// ❌ 错误2:缓冲区溢出
/*
char str2[10] = "Hello";
strcat(str2, " World! This is too long!"); // 缓冲区溢出
*/
// ✅ 正确:使用安全的字符串函数
char str2_correct[20] = "Hello";
strncat(str2_correct, " World!", sizeof(str2_correct) - strlen(str2_correct) - 1);
printf("安全连接: %s\n", str2_correct);
// ❌ 错误3:修改字符串字面量
/*
char *str3 = "Hello";
str3[0] = 'h'; // 运行时错误
*/
// ✅ 正确:使用字符数组或动态分配
char str3_correct[] = "Hello";
str3_correct[0] = 'h';
printf("可修改字符串: %s\n", str3_correct);
// ❌ 错误4:未检查字符串函数返回值
/*
char src[10] = "Too long!";
char dest[5];
strcpy(dest, src); // 缓冲区溢出
*/
// ✅ 正确:检查边界和使用安全函数
char src_correct[10] = "Hello";
char dest_correct[10];
if (strlen(src_correct) < sizeof(dest_correct)) {
strcpy(dest_correct, src_correct);
printf("安全复制: %s\n", dest_correct);
} else {
printf("错误:源字符串太长\n");
}
return 0;
}
最佳实践
c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// ✅ 好的实践:使用安全的字符串函数
void safeStringCopy(char *dest, size_t dest_size, const char *src) {
if (dest == NULL || src == NULL || dest_size == 0) {
return;
}
// 使用strncpy并确保null终止
strncpy(dest, src, dest_size - 1);
dest[dest_size - 1] = '\0';
}
// ✅ 好的实践:检查字符串长度
int isValidString(const char *str, size_t max_length) {
if (str == NULL) return 0;
size_t len = strlen(str);
return len > 0 && len < max_length;
}
// ✅ 好的实践:动态字符串构建
char* buildDynamicString(const char *part1, const char *part2) {
if (part1 == NULL || part2 == NULL) {
return NULL;
}
size_t len1 = strlen(part1);
size_t len2 = strlen(part2);
char *result = malloc(len1 + len2 + 1);
if (result != NULL) {
strcpy(result, part1);
strcat(result, part2);
}
return result;
}
int main() {
printf("=== 字符串最佳实践 ===\n");
// 安全字符串复制
char buffer[10];
safeStringCopy(buffer, sizeof(buffer), "Hello World");
printf("安全复制: '%s'\n", buffer);
// 字符串验证
printf("'Hello' 是有效字符串吗? %s\n",
isValidString("Hello", 10) ? "是" : "否");
printf("NULL 是有效字符串吗? %s\n",
isValidString(NULL, 10) ? "是" : "否");
// 动态字符串构建
char *dynamic_str = buildDynamicString("Hello ", "World!");
if (dynamic_str != NULL) {
printf("动态构建: %s\n", dynamic_str);
free(dynamic_str);
}
return 0;
}