C语言字符串与内存操作函数完全指南
引言
在C语言编程中,字符串和内存操作是日常开发中最常见的任务之一。C标准库提供了一系列强大的函数来处理这些操作,但理解它们的原理和正确使用方法至关重要。本文将详细介绍常用的字符串和内存操作函数,包括它们的使用方法、模拟实现以及实际示例。
目录
引言
正文
1. 字符分类函数
2. 字符转换函数
3. strlen的使用和模拟实现
4. strcpy的使用和模拟实现
5. strcat的使用和模拟实现
6. strcmp的使用和模拟实现
7. strncpy函数的使用
8. strncat函数的使用
9. strncmp函数的使用
10. strstr的使用和模拟实现
11. strtok函数的使用
12. strerror函数的使用
13. memcpy使用和模拟实现
14. memmove使用和模拟实现
15. memset函数的使用
16. memcmp函数的使用
总结
正文
1. 字符分类函数
字符分类函数用于判断字符的类型,都在<ctype.h>
头文件中定义。
示例:
#include <stdio.h>
#include <ctype.h>int main() {char ch = 'A';printf("isalpha('%c') = %d\n", ch, isalpha(ch)); // 输出: 1printf("isdigit('%c') = %d\n", ch, isdigit(ch)); // 输出: 0printf("isupper('%c') = %d\n", ch, isupper(ch)); // 输出: 1return 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); // 输出: 13return 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); // 输出: 13return 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); // 输出: Helloreturn 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); // 输出: Helloreturn 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++;// 追加srcwhile ((*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); // 输出: Helloreturn 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 Woreturn 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); // 输出: Worldreturn 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); // 输出: Worldreturn 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: appletoken: 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); // 输出: AAAAAAAAAreturn 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); // 输出: 0return 0;
}
总结
通过本文的学习,我们掌握了:
-
安全性原则:所有模拟函数都使用
assert
进行参数校验,确保程序的健壮性 -
返回值规范:对于原本返回指针的库函数,模拟实现返回
void*
类型,保持接口一致性 -
内存管理:理解了不同函数在处理内存重叠时的行为差异
-
实用技巧:学会了如何正确使用这些函数并理解其内部原理
关键要点:
-
memmove
能够正确处理内存重叠,而memcpy
不保证 -
strncpy
不会自动添加终止符,需要手动处理 -
strtok
会修改原字符串,使用时需要注意 -
字符分类和转换函数使用
int
类型参数,支持EOF处理
掌握这些字符串和内存操作函数是成为优秀C程序员的必备技能,希望本文能为你的学习之路提供帮助!