在 C 语言编程中,字符与字符串操作是最基础也最频繁的任务之一。标准库提供了一系列强大的函数来处理这些任务,它们主要分为两类:字符函数(处理单个字符)和字符串函数(处理以\0结尾的字符数组)。熟练掌握这些函数的使用和原理,不仅能提升代码效率,还能加深对 C 语言内存管理的理解。
一、字符分类函数
C 语言标准库<ctype.h>中提供了一系列字符分类函数,它们用于判断一个字符(实际是其 ASCII 值)属于哪个类别。这些函数的返回值为非零(真)或零(假)。
常用函数包括:
表格
| 函数名 | 功能 |
|---|---|
isalpha | 判断是否为字母(a-z, A-Z) |
isdigit | 判断是否为十进制数字(0-9) |
isalnum | 判断是否为字母或数字 |
islower | 判断是否为小写字母(a-z) |
isupper | 判断是否为大写字母(A-Z) |
isspace | 判断是否为空白字符(空格、换行、制表符等) |
使用示例:
#include <stdio.h>
#include <ctype.h>
int main() {
char ch = 'A';
if (isalpha(ch)) {
printf("%c is an alphabet.\n", ch); // 输出: A is an alphabet.
}
if (isupper(ch)) {
printf("%c is an uppercase letter.\n", ch); // 输出: A is an uppercase letter.
}
return 0;
}
二、字符转换函数
同样在<ctype.h>中,有两个非常实用的字符转换函数,用于在大小写之间转换。
表格
| 函数名 | 功能 |
|---|---|
tolower | 将大写字母转换为小写 |
toupper | 将小写字母转换为大写 |
注意:如果输入的字符本身不是字母,这两个函数会直接返回原字符。
使用示例:
#include <stdio.h>
#include <ctype.h>
int main() {
char lower = 'b';
char upper = 'Y';
printf("%c -> %c\n", lower, toupper(lower)); // 输出: b -> B
printf("%c -> %c\n", upper, tolower(upper)); // 输出: Y -> y
return 0;
}
三、strlen 的使用和模拟实现
strlen函数用于计算字符串的长度,即从字符串起始地址开始,直到遇到第一个\0为止的字符个数(不包含\0本身)。它声明在<string.h>头文件中。
1. 使用
size_t strlen(const char *str);
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello, World!";
printf("Length: %zu\n", strlen(str)); // 输出: Length: 13
return 0;
}
2. 模拟实现
我们可以通过指针遍历的方式来模拟实现strlen的功能:
// 方法一:计数器方式
size_t my_strlen1(const char *str) {
size_t count = 0;
while (*str != '\0') {
count++;
str++;
}
return count;
}
// 方法二:递归方式(不创建临时变量)
size_t my_strlen2(const char *str) {
if (*str == '\0') {
return 0;
}
return 1 + my_strlen2(str + 1);
}
// 方法三:指针-指针方式
size_t my_strlen3(const char *str) {
const char *start = str;
while (*str != '\0') {
str++;
}
return str - start;
}
四、strcpy 的使用和模拟实现
strcpy是字符串拷贝函数,用于将一个字符串的内容(包括\0)拷贝到另一个字符数组中。
1. 使用
c
运行
char *strcpy(char *dest, const char *src);
注意事项:
- 源字符串
src必须以\0结尾。- 目标空间
dest必须足够大,以容纳源字符串,否则会导致缓冲区溢出。- 目标空间
dest必须是可修改的(不能是字符串常量)。
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello";
char dest[20] = {0};
strcpy(dest, src);
printf("%s\n", dest); // 输出: Hello
return 0;
}
2. 模拟实现
#include <assert.h>
char *my_strcpy(char *dest, const char *src) {
// 保存目标字符串的起始地址
char *ret = dest;
// 断言指针不为空
assert(dest != NULL && src != NULL);
// 拷贝内容,直到遇到\0
while ((*dest++ = *src++)) {
;
}
return ret;
}
五、strcat 的使用和模拟实现
strcat是字符串追加函数,用于将一个字符串追加到另一个字符串的末尾。
1. 使用
c
运行
char *strcat(char *dest, const char *src);
注意事项:
- 目标字符串
dest必须有足够的空间来容纳追加后的总长度。- 源字符串
src和目标字符串dest都必须以\0结尾。- 不能自己追加自己(如
strcat(str, str);),这会导致\0被覆盖,函数陷入死循环。
c
运行
#include <stdio.h>
#include <string.h>
int main() {
char str[20] = "Hello";
strcat(str, " World!");
printf("%s\n", str); // 输出: Hello World!
return 0;
}
2. 模拟实现
#include <assert.h>
char *my_strcat(char *dest, const char *src) {
char *ret = dest;
assert(dest != NULL && src != NULL);
// 1. 找到dest字符串的末尾\0
while (*dest) {
dest++;
}
// 2. 从dest的末尾开始拷贝src
while ((*dest++ = *src++)) {
;
}
return ret;
}
六、strcmp 的使用和模拟实现
strcmp是字符串比较函数,用于比较两个字符串的内容。它是按字符的 ASCII 值逐位进行比较的。
1. 使用
int strcmp(const char *str1, const char *str2);
- 如果
str1 < str2,返回值小于 0。 - 如果
str1 == str2,返回值等于 0。 - 如果
str1 > str2,返回值大于 0。
#include <stdio.h>
#include <string.h>
int main() {
printf("%d\n", strcmp("app", "apple")); // 输出: -108 (或其他负数)
printf("%d\n", strcmp("apple", "app")); // 输出: 108 (或其他正数)
printf("%d\n", strcmp("abc", "abc")); // 输出: 0
return 0;
}
2. 模拟实现
#include <assert.h>
int my_strcmp(const char *str1, const char *str2) {
assert(str1 != NULL && str2 != NULL);
while (*str1 == *str2) {
if (*str1 == '\0') {
return 0; // 两个字符串完全相等
}
str1++;
str2++;
}
// 返回两个字符的差值
return *str1 - *str2;
}
七、strncpy 函数的使用
strncpy是strcpy的 “安全” 版本,它允许指定最多拷贝多少个字符。
c
运行
char *strncpy(char *dest, const char *src, size_t n);
- 从
src拷贝最多n个字符到dest。 - 如果
src的长度小于n,则在拷贝完src后,会用\0填充剩余的n - strlen(src)个字节。 - 如果
src的长度大于或等于n,则dest将不会以\0结尾!这是一个非常重要的陷阱,使用后必须手动在dest的第n个位置设置\0。
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[20] = {0};
strncpy(dest, src, 5);
dest[5] = '\0'; // 手动添加结束符,确保是字符串
printf("%s\n", dest); // 输出: Hello
return 0;
}
八、strncat 函数的使用
strncat是strcat的 “安全” 版本,它允许指定最多追加多少个字符。
char *strncat(char *dest, const char *src, size_t n);
- 从
src追加最多n个字符到dest的末尾。 - 函数会自动在最终的
dest末尾添加一个\0。 - 如果
src的长度小于n,则只追加到src的\0为止。
#include <stdio.h>
#include <string.h>
int main() {
char dest[20] = "Hello";
char src[] = "xxxxWorld!";
strncat(dest, src, 5);
printf("%s\n", dest); // 输出: HelloxxxxW
return 0;
}
九、strncmp 函数的使用
strncmp是strcmp的 “限制” 版本,它允许指定最多比较前n个字符。
int strncmp(const char *str1, const char *str2, size_t n);
- 只比较两个字符串的前
n个字符,或者直到出现不同字符 / 遇到\0为止。
#include <stdio.h>
#include <string.h>
int main() {
printf("%d\n", strncmp("app", "apple", 3)); // 输出: 0 (前3个字符相同)
printf("%d\n", strncmp("apple", "app", 4)); // 输出: 正数 (第4个字符'l' vs '\0')
return 0;
}
十、strstr 的使用和模拟实现
strstr是字符串查找函数,用于在一个字符串(haystack)中查找另一个字符串(needle)首次出现的位置。
1. 使用
char *strstr(const char *haystack, const char *needle);
- 如果找到,返回指向
needle在haystack中首次出现位置的指针。 - 如果未找到,返回
NULL。 - 如果
needle是空字符串,返回haystack。
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "I love C language, C is fun!";
char substr[] = "C";
char *pos = strstr(str, substr);
if (pos != NULL) {
printf("Found at position: %td\n", pos - str); // 输出: Found at position: 7
}
return 0;
}
2. 模拟实现
#include <assert.h>
char *my_strstr(const char *haystack, const char *needle) {
assert(haystack != NULL && needle != NULL);
// 如果子串是空串,直接返回原串
if (*needle == '\0') {
return (char *)haystack;
}
const char *s1, *s2;
const char *start = haystack;
while (*start) {
s1 = start;
s2 = needle;
// 逐个字符比较
while (*s1 && *s2 && (*s1 == *s2)) {
s1++;
s2++;
}
// 如果s2走到了末尾,说明找到了
if (*s2 == '\0') {
return (char *)start;
}
// 否则,从下一个字符开始重新匹配
start++;
}
// 遍历完都没找到
return NULL;
}
十一、strtok 函数的使用
strtok是字符串分割函数,用于将一个字符串按照指定的分隔符分割成若干个 “令牌”(token)。
char *strtok(char *str, const char *delim);
使用要点:
- 首次调用时,
str指向要分割的字符串,delim指向分隔符字符串。- 后续调用时,
str必须为NULL,delim可以与之前相同或不同。- 函数会修改原字符串,将分隔符替换为
\0,因此传入的str不能是字符串常量,必须是可修改的字符数组。- 函数内部会维护一个静态指针,记录下一次分割的起始位置,因此它不是线程安全的。
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "a,b,c,d,e";
char *token = strtok(str, ",");
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, ",");
}
// 输出:
// a
// b
// c
// d
// e
return 0;
}
十二、strerror 函数的使用
strerror函数用于将错误码(errno)转换为对应的可读的错误信息字符串。它声明在<string.h>头文件中。
char *strerror(int errnum);
在 C 标准库中,很多函数在执行失败时会设置全局变量errno的值,strerror可以帮助我们快速定位错误原因。
#include <stdio.h>
#include <string.h>
#include <errno.h> // 必须包含errno.h
int main() {
FILE *fp = fopen("non_existent_file.txt", "r");
if (fp == NULL) {
printf("Error opening file: %s\n", strerror(errno));
// 输出: Error opening file: No such file or directory
}
return 0;
}
&spm=1001.2101.3001.5002&articleId=158744011&d=1&t=3&u=d89b7e8df709411b8285067afb7d4d8e)
2236

被折叠的 条评论
为什么被折叠?



