Appearance
C 标准库 - <string.h>
概述
<string.h> 头文件提供了字符串处理函数,包括字符串复制、连接、比较、搜索、分割等功能。这是 C 语言中最常用的标准库之一。
字符串复制
strcpy()
c
char *strcpy(char *dest, const char *src);复制字符串。
c
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[20];
strcpy(dest, src);
printf("源字符串: %s\n", src);
printf("目标字符串: %s\n", dest);
return 0;
}strncpy()
c
char *strncpy(char *dest, const char *src, size_t n);复制指定长度的字符串。
c
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[10];
strncpy(dest, src, 9);
dest[9] = '\0';
printf("源字符串: %s\n", src);
printf("目标字符串: %s\n", dest);
return 0;
}strdup()
c
char *strdup(const char *s);复制字符串(POSIX)。
c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
const char* src = "Hello, World!";
char* dest = strdup(src);
if (dest != NULL) {
printf("源字符串: %s\n", src);
printf("目标字符串: %s\n", dest);
free(dest);
}
return 0;
}字符串连接
strcat()
c
char *strcat(char *dest, const char *src);连接字符串。
c
#include <stdio.h>
#include <string.h>
int main() {
char dest[50] = "Hello, ";
const char* src = "World!";
strcat(dest, src);
printf("结果: %s\n", dest);
return 0;
}strncat()
c
char *strncat(char *dest, const char *src, size_t n);连接指定长度的字符串。
c
#include <stdio.h>
#include <string.h>
int main() {
char dest[50] = "Hello, ";
const char* src = "World!";
strncat(dest, src, 5);
printf("结果: %s\n", dest);
return 0;
}字符串比较
strcmp()
c
int strcmp(const char *s1, const char *s2);比较字符串。
c
#include <stdio.h>
#include <string.h>
int main() {
const char* str1 = "apple";
const char* str2 = "banana";
const char* str3 = "apple";
int result1 = strcmp(str1, str2);
int result2 = strcmp(str1, str3);
printf("strcmp('%s', '%s') = %d\n", str1, str2, result1);
printf("strcmp('%s', '%s') = %d\n", str1, str3, result2);
return 0;
}strncmp()
c
int strncmp(const char *s1, const char *s2, size_t n);比较指定长度的字符串。
c
#include <stdio.h>
#include <string.h>
int main() {
const char* str1 = "apple pie";
const char* str2 = "apple cake";
int result = strncmp(str1, str2, 5);
printf("strncmp('%s', '%s', 5) = %d\n", str1, str2, result);
return 0;
}strcasecmp()
c
int strcasecmp(const char *s1, const char *s2);忽略大小写比较字符串(POSIX)。
c
#include <stdio.h>
#include <strings.h>
int main() {
const char* str1 = "Hello";
const char* str2 = "HELLO";
int result = strcasecmp(str1, str2);
printf("strcasecmp('%s', '%s') = %d\n", str1, str2, result);
return 0;
}字符串长度
strlen()
c
size_t strlen(const char *s);计算字符串长度。
c
#include <stdio.h>
#include <string.h>
int main() {
const char* str = "Hello, World!";
size_t len = strlen(str);
printf("字符串: %s\n", str);
printf("长度: %zu\n", len);
return 0;
}字符串搜索
strchr()
c
char *strchr(const char *s, int c);查找字符首次出现的位置。
c
#include <stdio.h>
#include <string.h>
int main() {
const char* str = "Hello, World!";
char c = 'o';
char* result = strchr(str, c);
if (result != NULL) {
printf("字符 '%c' 首次出现在位置: %ld\n",
c, result - str);
} else {
printf("未找到字符 '%c'\n", c);
}
return 0;
}strrchr()
c
char *strrchr(const char *s, int c);查找字符最后出现的位置。
c
#include <stdio.h>
#include <string.h>
int main() {
const char* str = "Hello, World!";
char c = 'o';
char* result = strrchr(str, c);
if (result != NULL) {
printf("字符 '%c' 最后出现在位置: %ld\n",
c, result - str);
} else {
printf("未找到字符 '%c'\n", c);
}
return 0;
}strstr()
c
char *strstr(const char *haystack, const char *needle);查找子字符串。
c
#include <stdio.h>
#include <string.h>
int main() {
const char* haystack = "Hello, World!";
const char* needle = "World";
char* result = strstr(haystack, needle);
if (result != NULL) {
printf("子字符串 '%s' 出现在位置: %ld\n",
needle, result - haystack);
} else {
printf("未找到子字符串 '%s'\n", needle);
}
return 0;
}字符串分割
strtok()
c
char *strtok(char *str, const char *delim);分割字符串。
c
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello,World,C,Programming";
const char* delim = ",";
char* token = strtok(str, delim);
printf("分割结果:\n");
while (token != NULL) {
printf(" %s\n", token);
token = strtok(NULL, delim);
}
return 0;
}内存操作
memcpy()
c
void *memcpy(void *dest, const void *src, size_t n);复制内存块。
c
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[20];
memcpy(dest, src, strlen(src) + 1);
printf("源字符串: %s\n", src);
printf("目标字符串: %s\n", dest);
return 0;
}memmove()
c
void *memmove(void *dest, const void *src, size_t n);移动内存块(处理重叠)。
c
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello, World!";
printf("移动前: %s\n", str);
memmove(str + 7, str, 5);
printf("移动后: %s\n", str);
return 0;
}memcmp()
c
int memcmp(const void *s1, const void *s2, size_t n);比较内存块。
c
#include <stdio.h>
#include <string.h>
int main() {
char buf1[] = "Hello";
char buf2[] = "Hello";
char buf3[] = "World";
int result1 = memcmp(buf1, buf2, 5);
int result2 = memcmp(buf1, buf3, 5);
printf("memcmp(buf1, buf2, 5) = %d\n", result1);
printf("memcmp(buf1, buf3, 5) = %d\n", result2);
return 0;
}memset()
c
void *memset(void *s, int c, size_t n);设置内存块。
c
#include <stdio.h>
#include <string.h>
int main() {
char buffer[20];
memset(buffer, 'A', sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';
printf("填充后的字符串: %s\n", buffer);
return 0;
}其他函数
strerror()
c
char *strerror(int errnum);获取错误代码对应的描述。
c
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main() {
FILE* file = fopen("nonexistent.txt", "r");
if (file == NULL) {
printf("错误: %s\n", strerror(errno));
}
return 0;
}实际应用示例
1. 字符串反转
c
#include <stdio.h>
#include <string.h>
void reverse_string(char* str) {
int len = strlen(str);
for (int i = 0; i < len / 2; i++) {
char temp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = temp;
}
}
int main() {
char str[] = "Hello, World!";
printf("原始字符串: %s\n", str);
reverse_string(str);
printf("反转字符串: %s\n", str);
return 0;
}2. 字符串去空格
c
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void trim_whitespace(char* str) {
int i = 0, j = 0;
while (str[i]) {
if (!isspace(str[i])) {
str[j++] = str[i];
}
i++;
}
str[j] = '\0';
}
int main() {
char str[] = " Hello, World! ";
printf("原始字符串: '%s'\n", str);
trim_whitespace(str);
printf("去空格后: '%s'\n", str);
return 0;
}3. 字符串分割为单词
c
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void split_into_words(const char* str) {
char copy[100];
strcpy(copy, str);
char* token = strtok(copy, " ");
printf("单词:\n");
while (token != NULL) {
printf(" %s\n", token);
token = strtok(NULL, " ");
}
}
int main() {
const char* str = "Hello World C Programming";
split_into_words(str);
return 0;
}4. 字符串替换
c
#include <stdio.h>
#include <string.h>
void replace_char(char* str, char old_char, char new_char) {
for (int i = 0; str[i] != '\0'; i++) {
if (str[i] == old_char) {
str[i] = new_char;
}
}
}
int main() {
char str[] = "Hello, World!";
printf("原始字符串: %s\n", str);
replace_char(str, 'o', 'O');
printf("替换后: %s\n", str);
return 0;
}5. 字符串统计
c
#include <stdio.h>
#include <string.h>
#include <ctype.h>
typedef struct {
int letters;
int digits;
int spaces;
int punctuation;
} StringStats;
StringStats analyze_string(const char* str) {
StringStats stats = {0, 0, 0, 0};
for (int i = 0; str[i] != '\0'; i++) {
if (isalpha(str[i])) {
stats.letters++;
} else if (isdigit(str[i])) {
stats.digits++;
} else if (isspace(str[i])) {
stats.spaces++;
} else if (ispunct(str[i])) {
stats.punctuation++;
}
}
return stats;
}
int main() {
const char* str = "Hello, World! 123";
StringStats stats = analyze_string(str);
printf("字符串: %s\n", str);
printf("字母: %d\n", stats.letters);
printf("数字: %d\n", stats.digits);
printf("空格: %d\n", stats.spaces);
printf("标点符号: %d\n", stats.punctuation);
return 0;
}6. 字符串连接
c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* concat_strings(const char* str1, const char* str2) {
size_t len1 = strlen(str1);
size_t len2 = strlen(str2);
char* result = malloc(len1 + len2 + 1);
if (result == NULL) {
return NULL;
}
strcpy(result, str1);
strcat(result, str2);
return result;
}
int main() {
const char* str1 = "Hello, ";
const char* str2 = "World!";
char* result = concat_strings(str1, str2);
if (result != NULL) {
printf("连接结果: %s\n", result);
free(result);
}
return 0;
}7. 字符串查找
c
#include <stdio.h>
#include <string.h>
int find_all_occurrences(const char* str, const char* substr) {
int count = 0;
const char* ptr = str;
while ((ptr = strstr(ptr, substr)) != NULL) {
count++;
ptr++;
}
return count;
}
int main() {
const char* str = "Hello, World! Hello, C!";
const char* substr = "Hello";
int count = find_all_occurrences(str, substr);
printf("子字符串 '%s' 出现次数: %d\n", substr, count);
return 0;
}8. 字符串大小写转换
c
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void to_uppercase(char* str) {
for (int i = 0; str[i] != '\0'; i++) {
str[i] = toupper(str[i]);
}
}
void to_lowercase(char* str) {
for (int i = 0; str[i] != '\0'; i++) {
str[i] = tolower(str[i]);
}
}
int main() {
char str1[] = "Hello, World!";
char str2[] = "Hello, World!";
printf("原始字符串: %s\n", str1);
to_uppercase(str1);
printf("大写: %s\n", str1);
to_lowercase(str2);
printf("小写: %s\n", str2);
return 0;
}9. 字符串验证
c
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int is_valid_email(const char* email) {
int at_count = 0;
int dot_count = 0;
for (int i = 0; email[i] != '\0'; i++) {
if (email[i] == '@') {
at_count++;
} else if (email[i] == '.') {
dot_count++;
}
}
return (at_count == 1 && dot_count >= 1);
}
int main() {
const char* email1 = "user@example.com";
const char* email2 = "invalid-email";
printf("'%s' 是有效邮箱: %d\n", email1, is_valid_email(email1));
printf("'%s' 是有效邮箱: %d\n", email2, is_valid_email(email2));
return 0;
}10. 字符串分割为字符
c
#include <stdio.h>
#include <string.h>
void print_characters(const char* str) {
printf("字符:\n");
for (int i = 0; str[i] != '\0'; i++) {
printf(" [%d] = '%c'\n", i, str[i]);
}
}
int main() {
const char* str = "Hello";
print_characters(str);
return 0;
}注意事项
1. 缓冲区溢出
c
#include <stdio.h>
#include <string.h>
void good_practice() {
char src[] = "Hello, World!";
char dest[20];
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';
printf("%s\n", dest);
}
void bad_practice() {
char src[] = "Hello, World!";
char dest[10];
strcpy(dest, src);
printf("%s\n", dest);
}2. 字符串终止符
c
#include <stdio.h>
#include <string.h>
void good_practice() {
char dest[20];
strncpy(dest, "Hello, World!", 10);
dest[10] = '\0';
printf("%s\n", dest);
}
void bad_practice() {
char dest[20];
strncpy(dest, "Hello, World!", 10);
printf("%s\n", dest);
}3. 内存重叠
c
#include <stdio.h>
#include <string.h>
void good_practice() {
char str[] = "Hello, World!";
memmove(str + 7, str, 5);
printf("%s\n", str);
}
void bad_practice() {
char str[] = "Hello, World!";
memcpy(str + 7, str, 5);
printf("%s\n", str);
}4. strtok 的使用
c
#include <stdio.h>
#include <string.h>
void good_practice() {
char str[] = "Hello,World,C";
char* token = strtok(str, ",");
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, ",");
}
}
void bad_practice() {
char str[] = "Hello,World,C";
char* token = strtok(str, ",");
printf("%s\n", token);
token = strtok(str, ",");
}总结
<string.h> 提供的字符串处理函数是 C 语言编程的基础:
- 功能全面 - 涵盖字符串复制、连接、比较、搜索等
- 易于使用 - 提供了简单直观的接口
- 广泛应用 - 几乎所有 C 程序都会使用
记住:
- 注意缓冲区溢出,使用安全的函数
- 确保字符串正确终止
- 处理内存重叠时使用 memmove
- strtok 会修改原字符串
- 检查函数的返回值