《C语言内存函数与字符串函数模拟实现详解》 📅 2026/8/5 1:53:13 ## 一、为什么我们要模拟实现库函数在C语言学习过程中模拟实现库函数是提升编程能力的重要方式。它不仅能帮助我们* **深入理解底层原理**知道 strlen 是如何计算出字符串长度的memcpy 是如何拷贝内存的。* **掌握指针和内存操作**模拟实现过程中会大量用到指针运算、内存地址操作这是C语言的核心。* **写出更健壮的代码**了解函数的边界条件如遇到 \0 停止能让我们在使用时避免出错。一句话总结**“造轮子”是为了更好地理解和使用“轮子”**。---## 二、字符串函数string.h这类函数的共同特点是**以 \0 作为结束标志**。如果字符串没有正确以 \0 结尾这些函数会越界访问导致未定义行为。### 1. strlen —— 求字符串长度* **功能**计算字符串中 \0 之前的字符个数不包括 \0。* **模拟实现指针方式**csize_t my_strlen(const char* str) {const char* start str;while (*str) {str;}return str - start;}### 2. strcpy —— 字符串拷贝* **功能**将源字符串包括 \0复制到目标空间。* **模拟实现**cchar* my_strcpy(char* dest, const char* src) {char* ret dest;while (*dest *src) {;}return ret;}### 3. strcat —— 字符串追加* **功能**将源字符串追加到目标字符串的末尾。* **模拟实现**cchar* my_strcat(char* dest, const char* src) {char* ret dest;while (*dest) {dest;}while (*dest *src) {;}return ret;}### 4. strcmp —— 字符串比较* **功能**逐字符比较两个字符串的 ASCII 值。* 返回值 0 表示 str1 str2。* 返回值 0 表示 str1 str2。* 返回值 0 表示 str1 str2。* **模拟实现**cint my_strcmp(const char* str1, const char* str2) {while (*str1 *str2 *str1 *str2) {str1;str2;}return *str1 - *str2;}### 5. 带 n 的版本strncpy, strncat, strncmp这些函数比不带 n 的版本更安全因为它们**限制了操作的字符个数**可以防止缓冲区溢出。#### strncpy 模拟实现cchar* my_strncpy(char* dest, const char* src, size_t n) {char* ret dest;size_t i;for (i 0; i n src[i] ! \0; i) {dest[i] src[i];}for (; i n; i) {dest[i] \0;}return ret;}#### strncat 模拟实现cchar* my_strncat(char* dest, const char* src, size_t n) {char* ret dest;while (*dest) {dest;}while (n-- (*dest *src)) {;}*dest \0;return ret;}#### strncmp 模拟实现cint my_strncmp(const char* str1, const char* str2, size_t n) {for (size_t i 0; i n; i) {if (str1[i] ! str2[i]) {return str1[i] - str2[i];}if (str1[i] \0) {return 0;}}return 0;}---## 三、内存函数string.h内存函数与字符串函数最大的不同在于**它们操作的是内存块不关心 \0只关心要操作的字节数**。### 1. memcpy —— 内存拷贝不重叠* **功能**从 src 拷贝 num 个字节到 dest。要求 src 和 dest 不重叠否则行为是未定义的可能会覆盖。* **模拟实现**cvoid* my_memcpy(void* dest, const void* src, size_t num) {char* d (char*)dest;const char* s (const char*)src;for (size_t i 0; i num; i) {d[i] s[i];}return dest;}### 2. memmove —— 内存拷贝可重叠* **功能**从 src 拷贝 num 个字节到 dest。与 memcpy 不同它可以正确处理 src 和 dest 重叠的情况。* **模拟实现**cvoid* my_memmove(void* dest, const void* src, size_t num) {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;}#### 核心思想为什么 memmove 能处理重叠因为它判断了 dest 和 src 的位置* **dest src**目标在前从前往后拷贝是安全的。* **dest src**目标在后从后往前拷贝避免覆盖未拷贝的数据。### 3. memset —— 内存设置* **功能**将 num 个字节的值设置为指定的 value以无符号字符形式。* **模拟实现**cvoid* my_memset(void* ptr, int value, size_t num) {unsigned char* p (unsigned char*)ptr;for (size_t i 0; i num; i) {p[i] (unsigned char)value;}return ptr;}---## 四、总结字符串函数 vs 内存函数| 分类 | 函数系列 | 结束标志 | 核心区别 || :--- | :--- | :--- | :--- || **字符串函数** | strlen, strcpy, strcat, strcmp 等 | **\0** | 遇到 \0 就停止不关心后面的数据 || **内存函数** | memcpy, memmove, memset 等 | **无** | 按字节数操作完全由 num 参数控制 |**关键记忆点*** 使用 str 系列函数时必须确保字符串有 \0 结尾。* 使用 mem 系列函数时必须确保传入的 num 大小正确不要越界。* memmove 比 memcpy 更安全但可能会有轻微的性能开销因为多了一步判断。---## 五、写在最后模拟实现这些函数不是为了在新项目中重新造轮子我们应该优先使用标准库而是为了1. **吃透指针和内存**C语言的核心就是内存操作。2. **理解标准库的行为**只有知道函数内部可能做什么才能更好地使用它们避免踩坑。3. **锻炼代码逻辑**尤其是处理边界条件如 \0、指针重叠的能力。希望这篇总结对你有帮助也欢迎在评论区交流讨论