引言

        在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));  // 输出: 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;
}

总结

通过本文的学习,我们掌握了:

  1. 安全性原则:所有模拟函数都使用assert进行参数校验,确保程序的健壮性

  2. 返回值规范:对于原本返回指针的库函数,模拟实现返回void*类型,保持接口一致性

  3. 内存管理:理解了不同函数在处理内存重叠时的行为差异

  4. 实用技巧:学会了如何正确使用这些函数并理解其内部原理

关键要点:

  • memmove能够正确处理内存重叠,而memcpy不保证

  • strncpy不会自动添加终止符,需要手动处理

  • strtok会修改原字符串,使用时需要注意

  • 字符分类和转换函数使用int类型参数,支持EOF处理

掌握这些字符串和内存操作函数是成为优秀C程序员的必备技能,希望本文能为你的学习之路提供帮助!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐