C语言字符串与内存操作函数完全指南

引言

在C语言编程中,字符串和内存操作是日常开发中最常见的任务之一。C标准库提供了一系列强大的函数来处理这些操作,但理解它们的原理和正确使用方法至关重要。本文将详细介绍常用的字符串和内存操作函数,包括它们的使用方法、模拟实现以及实际示例。

目录

引言

正文

[1. 字符分类函数](#1. 字符分类函数)

[2. 字符转换函数](#2. 字符转换函数)

[3. strlen的使用和模拟实现](#3. strlen的使用和模拟实现)

[4. strcpy的使用和模拟实现](#4. strcpy的使用和模拟实现)

[5. strcat的使用和模拟实现](#5. strcat的使用和模拟实现)

[6. strcmp的使用和模拟实现](#6. strcmp的使用和模拟实现)

[7. strncpy函数的使用](#7. strncpy函数的使用)

[8. strncat函数的使用](#8. strncat函数的使用)

[9. strncmp函数的使用](#9. strncmp函数的使用)

[10. strstr的使用和模拟实现](#10. strstr的使用和模拟实现)

[11. strtok函数的使用](#11. strtok函数的使用)

[12. strerror函数的使用](#12. strerror函数的使用)

[13. memcpy使用和模拟实现](#13. memcpy使用和模拟实现)

[14. memmove使用和模拟实现](#14. memmove使用和模拟实现)

[15. memset函数的使用](#15. memset函数的使用)

[16. memcmp函数的使用](#16. memcmp函数的使用)

总结


正文

1. 字符分类函数

字符分类函数用于判断字符的类型,都在<ctype.h>头文件中定义。

示例:

cpp 复制代码
#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. 字符转换函数

cpp 复制代码
#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的使用和模拟实现

使用示例:

cpp 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello, World!";
    size_t len = strlen(str);
    printf("字符串长度: %zu\n", len);  // 输出: 13
    return 0;
}

模拟实现:

cpp 复制代码
#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的使用和模拟实现

使用示例:

cpp 复制代码
#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;
}

模拟实现:

cpp 复制代码
#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的使用和模拟实现

使用示例:

cpp 复制代码
#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;
}

模拟实现:

cpp 复制代码
#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的使用和模拟实现

使用示例:

cpp 复制代码
#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;
}

模拟实现:

cpp 复制代码
#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函数的使用

cpp 复制代码
#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函数的使用

cpp 复制代码
#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函数的使用

cpp 复制代码
#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的使用和模拟实现

使用示例:

cpp 复制代码
#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;
}

模拟实现:

cpp 复制代码
#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函数的使用

cpp 复制代码
#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函数的使用

cpp 复制代码
#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使用和模拟实现

使用示例:

cpp 复制代码
#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;
}

模拟实现:

cpp 复制代码
#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使用和模拟实现

使用示例:

cpp 复制代码
#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;
}

模拟实现:

cpp 复制代码
#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函数的使用

cpp 复制代码
#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函数的使用

cpp 复制代码
#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程序员的必备技能,希望本文能为你的学习之路提供帮助!

相关推荐
rengang666 小时前
07-逻辑回归:分析用于分类问题的逻辑回归模型及其数学原理
人工智能·算法·机器学习·分类·逻辑回归
Zzzzmo_6 小时前
【Java】杨辉三角、洗牌算法
java·数据结构·算法
闻缺陷则喜何志丹6 小时前
【C++贪心】P10537 [APIO2024] 九月|普及+
c++·算法·贪心·洛谷
QiZhang | UESTC6 小时前
JAVA算法练习题day27
java·开发语言·c++·算法·leetcode·hot100
坚持就完事了6 小时前
2-C语言中的数据类型
c语言·开发语言
饼干吖6 小时前
记一次滑动数组解题
java·算法
小马爱打代码7 小时前
分布式锁:原理算法和使用建议
分布式·算法
Stanford_11067 小时前
关于嵌入式硬件需要了解的基础知识
开发语言·c++·嵌入式硬件·微信小程序·微信公众平台·twitter·微信开放平台
uhakadotcom7 小时前
NVIDIA CUDA Python 常用 API 及详细教程
算法·面试·github