C语言字符串与内存操作函数完全指南
安全性原则:所有模拟函数都使用assert进行参数校验,确保程序的健壮性返回值规范:对于原本返回指针的库函数,模拟实现返回void*类型,保持接口一致性内存管理:理解了不同函数在处理内存重叠时的行为差异实用技巧:学会了如何正确使用这些函数并理解其内部原理memmove能够正确处理内存重叠,而memcpy不保证strncpy不会自动添加终止符,需要手动处理strtok会修改原字符串,使用时需要注意字
引言
在C语言编程中,字符串和内存操作是日常开发中最常见的任务之一。C标准库提供了一系列强大的函数来处理这些操作,但理解它们的原理和正确使用方法至关重要。本文将详细介绍常用的字符串和内存操作函数,包括它们的使用方法、模拟实现以及实际示例。
目录
正文
1. 字符分类函数
字符分类函数用于判断字符的类型,都在<ctype.h>
头文件中定义。
示例:
#include <stdio.h>
#include <ctype.h>
int main() {
char ch = 'A';
printf("isalpha('%c') = %d\n", ch, isalpha(ch)); // 输出: 1
printf("isdigit('%c') = %d\n", ch, isdigit(ch)); // 输出: 0
printf("isupper('%c') = %d\n", ch, isupper(ch)); // 输出: 1
return 0;
}
2. 字符转换函数
#include <stdio.h>
#include <ctype.h>
int main() {
char upper = 'A';
char lower = 'z';
printf("tolower('%c') = '%c'\n", upper, tolower(upper)); // 输出: 'a'
printf("toupper('%c') = '%c'\n", lower, toupper(lower)); // 输出: 'Z'
return 0;
}
3. strlen的使用和模拟实现
使用示例:
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello, World!";
size_t len = strlen(str);
printf("字符串长度: %zu\n", len); // 输出: 13
return 0;
}
模拟实现:
#include <stdio.h>
#include <assert.h>
size_t my_strlen(const char* str) {
assert(str != NULL);
size_t count = 0;
while (*str++) {
count++;
}
return count;
}
int main() {
char str[] = "Hello, World!";
size_t len = my_strlen(str);
printf("模拟strlen结果: %zu\n", len); // 输出: 13
return 0;
}
4. strcpy的使用和模拟实现
使用示例:
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello";
char dest[20];
strcpy(dest, src);
printf("strcpy结果: %s\n", dest); // 输出: Hello
return 0;
}
模拟实现:
#include <stdio.h>
#include <assert.h>
void* my_strcpy(void* dest, const void* src) {
assert(dest != NULL && src != NULL);
char* d = (char*)dest;
const char* s = (const char*)src;
while ((*d++ = *s++));
return dest;
}
int main() {
char src[] = "Hello";
char dest[20];
my_strcpy(dest, src);
printf("模拟strcpy结果: %s\n", dest); // 输出: Hello
return 0;
}
5. strcat的使用和模拟实现
使用示例:
#include <stdio.h>
#include <string.h>
int main() {
char str1[20] = "Hello";
char str2[] = " World!";
strcat(str1, str2);
printf("strcat结果: %s\n", str1); // 输出: Hello World!
return 0;
}
模拟实现:
#include <stdio.h>
#include <assert.h>
void* my_strcat(void* dest, const void* src) {
assert(dest != NULL && src != NULL);
char* d = (char*)dest;
const char* s = (const char*)src;
// 找到dest的结尾
while (*d) d++;
// 追加src
while ((*d++ = *s++));
return dest;
}
int main() {
char str1[20] = "Hello";
char str2[] = " World!";
my_strcat(str1, str2);
printf("模拟strcat结果: %s\n", str1); // 输出: Hello World!
return 0;
}
6. strcmp的使用和模拟实现
使用示例:
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "apple";
char str2[] = "banana";
int result = strcmp(str1, str2);
printf("strcmp结果: %d\n", result); // 输出: 负数
return 0;
}
模拟实现:
#include <stdio.h>
#include <assert.h>
int my_strcmp(const char* str1, const char* str2) {
assert(str1 != NULL && str2 != NULL);
while (*str1 && *str2 && *str1 == *str2) {
str1++;
str2++;
}
return *(unsigned char*)str1 - *(unsigned char*)str2;
}
int main() {
char str1[] = "apple";
char str2[] = "banana";
int result = my_strcmp(str1, str2);
printf("模拟strcmp结果: %d\n", result); // 输出: 负数
return 0;
}
7. strncpy函数的使用
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello World";
char dest[10];
strncpy(dest, src, 5);
dest[5] = '\0'; // 手动添加终止符
printf("strncpy结果: %s\n", dest); // 输出: Hello
return 0;
}
8. strncat函数的使用
#include <stdio.h>
#include <string.h>
int main() {
char str1[20] = "Hello";
char str2[] = " World!";
strncat(str1, str2, 3);
printf("strncat结果: %s\n", str1); // 输出: Hello Wo
return 0;
}
9. strncmp函数的使用
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "apple";
char str2[] = "application";
int result = strncmp(str1, str2, 3);
printf("strncmp结果: %d\n", result); // 输出: 0 (前3个字符相同)
return 0;
}
10. strstr的使用和模拟实现
使用示例:
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello World";
char substr[] = "World";
char* result = strstr(str, substr);
printf("strstr结果: %s\n", result); // 输出: World
return 0;
}
模拟实现:
#include <stdio.h>
#include <assert.h>
void* my_strstr(const void* str1, const void* str2) {
assert(str1 != NULL && str2 != NULL);
const char* s1 = (const char*)str1;
const char* s2 = (const char*)str2;
if (*s2 == '\0') return (void*)s1;
for (; *s1; s1++) {
const char* p1 = s1;
const char* p2 = s2;
while (*p1 && *p2 && *p1 == *p2) {
p1++;
p2++;
}
if (*p2 == '\0') return (void*)s1;
}
return NULL;
}
int main() {
char str[] = "Hello World";
char substr[] = "World";
char* result = my_strstr(str, substr);
printf("模拟strstr结果: %s\n", result); // 输出: World
return 0;
}
11. strtok函数的使用
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "apple,banana,cherry";
char* token;
token = strtok(str, ",");
while (token != NULL) {
printf("token: %s\n", token);
token = strtok(NULL, ",");
}
/* 输出:
token: apple
token: banana
token: cherry
*/
return 0;
}
12. strerror函数的使用
#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;
}
13. memcpy使用和模拟实现
使用示例:
#include <stdio.h>
#include <string.h>
int main() {
int src[] = {1, 2, 3, 4, 5};
int dest[5];
memcpy(dest, src, 5 * sizeof(int));
printf("memcpy结果: ");
for (int i = 0; i < 5; i++) {
printf("%d ", dest[i]); // 输出: 1 2 3 4 5
}
printf("\n");
return 0;
}
模拟实现:
#include <stdio.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num) {
assert(dest != NULL && src != NULL);
char* d = (char*)dest;
const char* s = (const char*)src;
for (size_t i = 0; i < num; i++) {
d[i] = s[i];
}
return dest;
}
int main() {
int src[] = {1, 2, 3, 4, 5};
int dest[5];
my_memcpy(dest, src, 5 * sizeof(int));
printf("模拟memcpy结果: ");
for (int i = 0; i < 5; i++) {
printf("%d ", dest[i]); // 输出: 1 2 3 4 5
}
printf("\n");
return 0;
}
14. memmove使用和模拟实现
使用示例:
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "memmove can handle overlap";
memmove(str + 2, str, 8);
printf("memmove结果: %s\n", str);
return 0;
}
模拟实现:
#include <stdio.h>
#include <assert.h>
void* my_memmove(void* dest, const void* src, size_t num) {
assert(dest != NULL && src != NULL);
char* d = (char*)dest;
const char* s = (const char*)src;
if (d < s) {
// 从前往后拷贝
for (size_t i = 0; i < num; i++) {
d[i] = s[i];
}
} else {
// 从后往前拷贝
for (size_t i = num; i > 0; i--) {
d[i-1] = s[i-1];
}
}
return dest;
}
int main() {
char str[] = "memmove can handle overlap";
my_memmove(str + 2, str, 8);
printf("模拟memmove结果: %s\n", str);
return 0;
}
15. memset函数的使用
#include <stdio.h>
#include <string.h>
int main() {
char buffer[10];
memset(buffer, 'A', 9);
buffer[9] = '\0';
printf("memset结果: %s\n", buffer); // 输出: AAAAAAAAA
return 0;
}
16. memcmp函数的使用
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "apple";
char str2[] = "application";
int result = memcmp(str1, str2, 3);
printf("memcmp结果: %d\n", result); // 输出: 0
return 0;
}
总结
通过本文的学习,我们掌握了:
-
安全性原则:所有模拟函数都使用
assert
进行参数校验,确保程序的健壮性 -
返回值规范:对于原本返回指针的库函数,模拟实现返回
void*
类型,保持接口一致性 -
内存管理:理解了不同函数在处理内存重叠时的行为差异
-
实用技巧:学会了如何正确使用这些函数并理解其内部原理
关键要点:
-
memmove
能够正确处理内存重叠,而memcpy
不保证 -
strncpy
不会自动添加终止符,需要手动处理 -
strtok
会修改原字符串,使用时需要注意 -
字符分类和转换函数使用
int
类型参数,支持EOF处理
掌握这些字符串和内存操作函数是成为优秀C程序员的必备技能,希望本文能为你的学习之路提供帮助!
更多推荐
所有评论(0)