盘点C语言中的字符串操作函数

1、字符串复制和连接

#include <stdio.h>
#include <string.h>

int main() {
    // strcpy
    char src1[] = "Hello";
    char dest1[20];
    strcpy(dest1, src1);
    printf("strcpy: %s\n", dest1);

    // strncpy
    char src2[] = "World";
    char dest2[20];
    strncpy(dest2, src2, 3);
    dest2[3] = '\0'; // 确保字符串以 null 结尾
    printf("strncpy: %s\n", dest2);

    // strcat
    char dest3[20] = "Hello";
    strcat(dest3, " World");
    printf("strcat: %s\n", dest3);

    // strncat
    char dest4[20] = "Hello";
    strncat(dest4, " World", 3);
    printf("strncat: %s\n", dest4);

    return 0;
}

输出:

strcpy: Hello
strncpy: Wor
strcat: Hello World
strncat: Hello Wo

注意项:

  • 在使用strcat时,需要确保拼接的字符串后方有足够的内存

2、字符串比较

#include <stdio.h>
#include <string.h>

int main() {
    // strcmp
    char str1[] = "Hello";
    char str2[] = "World";
    printf("strcmp: %d\n", strcmp(str1, str2));

    // strncmp
    char str3[] = "Hello";
    char str4[] = "Helium";
    printf("strncmp: %d\n", strncmp(str3, str4, 3));

    return 0;
}

输出:

strcmp: -15
strncmp: 0

strcmp 函数用于比较两个字符串,并返回一个整数值来表示它们的相对顺序。strcmp 的返回值有以下三种情况:

  • 负数:如果第一个字符串小于第二个字符串,strcmp 返回一个负数。这通常是因为在比较时,第一个字符串中第一个不同的字符的 ASCII 值小于第二个字符串中对应字符的 ASCII 值。
  • 零:如果两个字符串相等,strcmp 返回 0。这意味着两个字符串的长度相同,并且每个对应位置的字符都相同。
  • 正数:如果第一个字符串大于第二个字符串,strcmp 返回一个正数。这通常是因为在比较时,第一个字符串中第一个不同的字符的 ASCII 值大于第二个字符串中对应字符的 ASCII 值。

3、字符串长度

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello World";
    printf("strlen: %zu\n", strlen(str));
    return 0;
}

输出:

strlen: 11

注意项:

  • strlen是一个函数,用来查找一段内存最近的\0
  • sizeof是宏定义,在预处理阶段被替换为真值

4、字符串查找

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello World";

    // strchr
    char *result1 = strchr(str, 'o');
    if (result1) printf("strchr: %s\n", result1);

    // strrchr
    char *result2 = strrchr(str, 'o');
    if (result2) printf("strrchr: %s\n", result2);

    // strstr
    char *result3 = strstr(str, "World");
    if (result3) printf("strstr: %s\n", result3);

    // strpbrk
    char *result4 = strpbrk(str, "aeiou");
    if (result4) printf("strpbrk: %s\n", result4);

    // strspn
    size_t len1 = strspn(str, "Helo ");
    printf("strspn: %zu\n", len1);

    // strcspn
    size_t len2 = strcspn(str, "W");
    printf("strcspn: %zu\n", len2);

    return 0;
}

输出:

strchr: o World
strrchr: orld
strstr: World
strpbrk: ello World
strspn: 6
strcspn: 6

说明:

  • strchr:查找字符在字符串中的第一次出现。
  • strrchr:查找字符在字符串中的最后一次出现。
  • strstr:查找子字符串在字符串中的第一次出现。
  • strpbrk:查找字符串中任意字符集合的第一次出现。
  • strspn:计算字符串前缀中包含指定字符集合的长度。
  • strcspn:计算字符串前缀中不包含指定字符集合的长度。

5、字符串分割

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello,World,Test";
    char *token = strtok(str, ",");
    while (token != NULL) {
        printf("strtok: %s\n", token);
        token = strtok(NULL, ",");
    }
    return 0;
}

输出:

strtok: Hello
strtok: World
strtok: Test

说明:
strtok 函数在内部维护了一个静态指针,用于跟踪当前字符串分割的位置。这意味着第一次调用 strtok 时,它会保存字符串的起始位置,并在后续调用中继续从上次停止的位置开始处理。
strtok 的工作机制如下:

  • 第一次调用:当你第一次调用 strtok(str, ",") 时,strtok 会扫描 str 直到找到第一个分隔符(在这个例子中是逗号 ,)。然后,它会用 \0 替换这个分隔符,并返回第一个标记的指针。
  • 后续调用:在后续调用中,你传入 NULL 作为第一个参数,strtok 会从上次停止的位置继续扫描,寻找下一个分隔符。它会用 \0 替换找到的分隔符,并返回下一个标记的指针。
  • 结束条件:当没有更多的标记可提取时,strtok 返回 NULL。
    需要注意的是,由于 strtok 使用静态存储来保存状态,因此它不是线程安全的。如果你需要在多线程环境中使用类似的功能,可以考虑使用 strtok_r(POSIX 标准)或其他线程安全的字符串分割函数。
  • strtok 会修改原始字符串,因此如果需要保留原始字符串不变,应该先复制一份再进行分割。

6、内存操作

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main() {
    char src[] = "Hello World";
    char dest[20];

    // memcpy
    memcpy(dest, src, strlen(src) + 1);
    printf("memcpy: %s\n", dest);

    // memmove (overlapping memory regions)
    memmove(dest + 6, dest, strlen(dest) + 1);
    printf("memmove: %s\n", dest);

    // memset
    memset(dest, '*', 5);
    dest[5] = '\0';
    printf("memset: %s\n", dest);

    // memcmp
    char str1[] = "abc";
    char str2[] = "abd";
    printf("memcmp: %d\n", memcmp(str1, str2, 3));

    // memchr
    char *result = memchr(src, 'W', strlen(src));
    if (result) {
        printf("memchr: %s\n", result);
    }

    // strdup
    char *duplicate = strdup(src);
    if (duplicate) {
        printf("strdup: %s\n", duplicate);
        free(duplicate); // Don't forget to free the allocated memory
    } else {
        printf("Failed to duplicate string.\n");
    }

    return 0;
}

输出:

memcpy: Hello World
memmove: Hello Hello World
memset: *****
memcmp: -1
memchr: World
strdup: Hello World

说明:
memcpy 和 memmove 都是用于在内存中复制数据的函数,但它们在处理重叠内存区域时有重要区别:

  • memcpy

    • 用途:用于复制一个内存块的数据到另一个内存块。
    • 重叠区域:memcpy 不安全用于重叠的内存区域。如果源和目标区域重叠,memcpy 的行为是未定义的。这意味着在这种情况下,memcpy 可能会导致数据损坏或其他不可预测的结果。
    • 性能:通常比 memmove 更快,因为它不需要处理重叠的情况。
  • memmove

    • 用途:同样用于复制一个内存块的数据到另一个内存块。
    • 重叠区域:memmove 安全用于重叠的内存区域。它会确保在复制过程中,源数据不会被覆盖,从而保证数据的正确性。
    • 性能:可能比 memcpy 稍慢,因为它需要处理重叠的情况以确保安全。
  • strdup

    • strdup会使用malloc申请内存块,使用完成后需要释放
文章目录