C语言string函数有哪些常用功能?

99ANYc3cd6
预计阅读时长 28 分钟
位置: 首页 C语言 正文

在 C 语言中,字符串被表示为一个以空字符 '\0' 结尾的字符数组。string.h (或其旧称 strings.h) 头文件提供了大量用于操作这些字符串的函数。

c语言 string 函数
(图片来源网络,侵删)

核心概念:'\0' (空字符)

这是理解所有字符串函数的基石,字符串的长度由函数计算,直到遇到第一个 '\0' 为止,字符串 "hello" 在内存中实际存储的是 {'h', 'e', 'l', 'l', 'o', '\0'}


计算字符串长度

strlen

  • 函数原型: size_t strlen(const char *str);
  • 功能: 计算字符串的长度。
  • 参数: str - 指向字符串的指针。
  • 返回值: 返回字符串的长度,不包括结尾的 '\0',如果传入的指针是 NULL,会导致程序崩溃(未定义行为)。
  • 特点: 它会一直向后遍历字符,直到找到 '\0' 为止。

示例代码:

#include <stdio.h>
#include <string.h>
int main() {
    char str1[] = "Hello, World!";
    char str2[] = "C";
    printf("The length of '%s' is %zu\n", str1, strlen(str1)); // 输出 13
    printf("The length of '%s' is %zu\n", str2, strlen(str2)); // 输出 1
    // 注意 sizeof 和 strlen 的区别
    // sizeof 计算的是整个数组的大小(包括 '\0')
    printf("The size of str1 is %zu\n", sizeof(str1)); // 输出 14
    return 0;
}

字符串拷贝与拼接

strcpy

  • 函数原型: char *strcpy(char *dest, const char *src);
  • 功能: 将源字符串 src 拷贝到目标字符数组 dest 中。
  • 参数:
    • dest: 目标字符数组,必须有足够的空间来容纳 src 的内容(包括 '\0')。
    • src: 源字符串,用 const 修饰,表示不会修改它。
  • 返回值: 返回指向 dest 的指针。
  • ⚠️ 重要警告: strcpy 不检查 dest 的大小,srcdest 长,会导致缓冲区溢出,这是严重的安全漏洞。

示例代码:

#include <stdio.h>
#include <string.h>
int main() {
    char src[] = "Hello";
    // dest 必须足够大,至少是 strlen(src) + 1
    char dest[10]; // 6个字符 + '\0' = 7,10足够
    strcpy(dest, src);
    printf("Copied string: %s\n", dest); // 输出 Hello
    // 危险示例!
    // char small_dest[5];
    // strcpy(small_dest, src); // 这会导致缓冲区溢出,未定义行为
    return 0;
}

strncpy

  • 函数原型: char *strncpy(char *dest, const char *src, size_t n);
  • 功能: 拷贝最多 n 个字符从 srcdest
  • 参数:
    • dest: 目标字符数组。
    • src: 源字符串。
    • n: 要拷贝的最大字符数。
  • 返回值: 返回指向 dest 的指针。
  • 特点:
    1. strlen(src) < ndest 的剩余部分会用 '\0' 填充。
    2. strlen(src) >= ndest 不会自动添加 '\0',这可能导致 dest 不是一个合法的字符串。
  • 用途: 比 strcpy 安全,因为它限制了拷贝的字符数,但仍需谨慎使用。

示例代码:

c语言 string 函数
(图片来源网络,侵删)
#include <stdio.h>
#include <string.h>
int main() {
    char src[] = "Hello";
    char dest1[10];
    char dest2[5];
    // 情况1: n > strlen(src)
    strncpy(dest1, src, 8);
    // dest1 会是 "Hello\0\0\0" (后面的'\0'由strncpy填充)
    printf("strncpy with n > len: %s\n", dest1);
    // 情况2: n <= strlen(src)
    strncpy(dest2, src, 3);
    // dest2 会是 "Hel" (注意!没有'\0')
    // 为了安全,最好手动添加
    dest2[3] = '\0';
    printf("strncpy with n <= len: %s\n", dest2);
    return 0;
}

strcat

  • 函数原型: char *strcat(char *dest, const char *src);
  • 功能: 将源字符串 src 拼接到目标字符串 dest 的末尾。
  • 参数:
    • dest: 目标字符串,必须有足够的空间来容纳拼接后的新字符串(包括 '\0')。
    • src: 要拼接的源字符串。
  • 返回值: 返回指向 dest 的指针。
  • ⚠️ 重要警告: 和 strcpy 一样,strcat 不检查 dest 的剩余空间,容易导致缓冲区溢出。

示例代码:

#include <stdio.h>
#include <string.h>
int main() {
    char dest[20] = "Hello, ";
    char src[] = "World!";
    strcat(dest, src);
    printf("Concatenated string: %s\n", dest); // 输出 Hello, World!
    return 0;
}

strncat

  • 函数原型: char *strncat(char *dest, const char *src, size_t n);
  • 功能: 将 src 的前 n 个字符拼接到 dest 的末尾。
  • 参数:
    • dest: 目标字符串。
    • src: 源字符串。
    • n: 要拼接的最大字符数。
  • 返回值: 返回指向 dest 的指针。
  • 特点: 它会保证在拼接后的字符串末尾添加一个 '\0',这比 strncpy 更安全一些。
  • 注意: 目标数组 dest 的大小至少需要是 strlen(dest) + n + 1

示例代码:

#include <stdio.h>
#include <string.h>
int main() {
    char dest[15] = "Hello, "; // 长度为 7
    char src[] = "World!";    // 长度为 6
    // 最多拼接 3 个字符
    strncat(dest, src, 3);
    printf("Concatenated string: %s\n", dest); // 输出 Hello, Wor
    return 0;
}

字符串比较

strcmp

  • 函数原型: int strcmp(const char *str1, const char *str2);
  • 功能: 比较两个字符串的字典顺序。
  • 参数: str1, str2 - 要比较的两个字符串。
  • 返回值:
    • 小于 0: 表示 str1 小于 str2
    • 等于 0: 表示 str1 等于 str2
    • 大于 0: 表示 str1 大于 str2
  • 比较规则: 逐个字符比较其 ASCII 码值,直到遇到不同的字符或 '\0'

示例代码:

#include <stdio.h>
#include <string.h>
int main() {
    char str1[] = "apple";
    char str2[] = "banana";
    char str3[] = "apple";
    printf("strcmp(str1, str2): %d\n", strcmp(str1, str2)); // 输出负数
    printf("strcmp(str2, str1): %d\n", strcmp(str2, str1)); // 输出正数
    printf("strcmp(str1, str3): %d\n", strcmp(str1, str3)); // 输出 0
    return 0;
}

strncmp

  • 函数原型: int strncmp(const char *str1, const char *str2, size_t n);
  • 功能: 比较两个字符串的前 n 个字符。
  • 参数: str1, str2 - 要比较的字符串,n - 比较的最大字符数。
  • 返回值: 与 strcmp 相同。

示例代码:

c语言 string 函数
(图片来源网络,侵删)
#include <stdio.h>
#include <string.h>
int main() {
    char str1[] = "apple pie";
    char str2[] = "apple juice";
    // 只比较前 5 个字符
    printf("strncmp(str1, str2, 5): %d\n", strncmp(str1, str2, 5)); // 输出 0
    // 比较 6 个字符
    printf("strncmp(str1, str2, 6): %d\n", strncmp(str1, str2, 6)); // 输出负数 ('p' < 'j' 是错误的,应该是 ' ' < 'j',所以是负数)
                                                                   // ' ' (空格) 的 ASCII 是 32, 'j' 是 106,str1 < str2, 返回负数。
    return 0;
}

字符串查找

strchr

  • 函数原型: char *strchr(const char *str, int c);
  • 功能: 在字符串 str 中查找字符 cc 会被转换为 char)的第一次出现。
  • 参数:
    • str: 要搜索的字符串。
    • c: 要查找的字符。
  • 返回值:
    • 如果找到,返回指向该字符的指针。
    • 如果未找到,返回 NULL
  • 注意: 查找包括 '\0' 本身。

示例代码:

#include <stdio.h>
#include <string.h>
int main() {
    char str[] = "Hello, World!";
    char *ptr;
    ptr = strchr(str, 'W');
    if (ptr != NULL) {
        printf("Found 'W' at position: %ld\n", ptr - str); // 输出 7
    }
    ptr = strchr(str, 'x');
    if (ptr == NULL) {
        printf("'x' not found in the string.\n");
    }
    return 0;
}

strstr

  • 函数原型: char *strstr(const char *haystack, const char *needle);
  • 功能: 在字符串 haystack(草堆)中查找子字符串 needle(针)的第一次出现。
  • 参数:
    • haystack: 要搜索的主字符串。
    • needle: 要查找的子字符串。
  • 返回值:
    • 如果找到,返回指向子字符串在 haystack 中起始位置的指针。
    • 如果未找到,返回 NULL

示例代码:

#include <stdio.h>
#include <string.h>
int main() {
    char haystack[] = "This is a simple string";
    char *ptr;
    ptr = strstr(haystack, "simple");
    if (ptr != NULL) {
        printf("Found 'simple' starting at: %ld\n", ptr - haystack); // 输出 10
        printf("The rest of the string is: %s\n", ptr); // 输出 simple string
    }
    return 0;
}

其他常用函数

strtok

  • 函数原型: char *strtok(char *str, const char *delim);
  • 功能: 将字符串分割成一个个的“标记”(tokens)。
  • 参数:
    • str: 要被分割的字符串。第一次调用时传入该字符串,之后调用时传入 NULL
    • delim: 包含所有分隔符的字符串。
  • 返回值: 返回指向下一个标记的指针,当没有更多标记时返回 NULL
  • ⚠️ 重要警告: strtok修改原始字符串,用 '\0' 替换分隔符,它是非线程安全的,并且会记住上次调用的状态(通过静态变量)。

示例代码:

#include <stdio.h>
#include <string.h>
int main() {
    char str[] = "This,is,a,test,string";
    char *token;
    // 第一次调用,传入字符串
    token = strtok(str, ",");
    while (token != NULL) {
        printf("%s\n", token);
        // 后续调用,传入 NULL
        token = strtok(NULL, ",");
    }
    // str 现在被修改了: "This\0is\0a\0test\0string"
    // printf("Original str after strtok: %s\n", str);
    return 0;
}

总结与现代替代方案

函数 功能 安全性 现代替代方案 (C99)
strcpy 字符串拷贝 不安全 (缓冲区溢出) strncpy (需手动加 '\0')
strcat 字符串拼接 不安全 (缓冲区溢出) strncat
strlen 计算长度 安全
strcmp 字符串比较 安全
strchr 查找字符 安全
strstr 查找子串 安全
strtok 分割字符串 不安全 (修改原串, 非线程安全) strtok_r (POSIX, 线程安全) 或 C++ 的 std::stringstream

对于现代 C 开发,强烈推荐使用更安全的函数,如 strncpy, strncat,并始终确保目标缓冲区足够大,在编写新代码时,考虑使用长度限制的函数或 C++ 的 std::string 等更高级的抽象可以大大提高程序的健壮性和安全性。

-- 展开阅读全文 --
头像
extern变量声明与定义的区别是什么?
« 上一篇 今天
织梦发布分类信息,步骤是什么?
下一篇 » 今天
取消
微信二维码
支付宝二维码

目录[+]