HOWTO · C

使用 C 语言中的 strdup 函数

了解 strdup 如何在 C 语言中复制字符串、如何检查并释放其分配的副本,以及何时使用 strndup 或 GNU 的 strdupa。

本页内容

strdup 会创建以空字符结尾的 C 字符串副本,并返回单独分配的内存。使用返回的指针前先检查它;成功复制后,用 free 释放内存。需要限制复制的字节数时可使用 strndup;strdupa 是 GNU 专用的替代方案,其存储生命周期不同。

strdup 的作用与可用范围

strdup 的声明为 char *strdup(const char *s);,位于 <string.h> 中。它会将以空字符结尾的字符串 s 的字节(包括结尾的空字节)复制到新分配的存储空间中。返回的指针指向该存储空间;如果内存分配失败,函数会返回 NULL。

strdup 不属于 C 标准库。它由 POSIX 规范定义,常见的 C 库(例如 GNU C 库)也提供此函数。在严格语言模式下编译时,某些平台可能需要特性测试宏才能提供该函数的声明。如果需要在 POSIX 系统之外保持可移植性,请查阅目标平台的文档。

使用 strdup 复制字符串

如果目标平台使用 _POSIX_C_SOURCE 来提供 POSIX 声明,请在包含头文件前定义它。示例会先检查返回值,再读取字符串,并在使用完副本后释放它。成功运行时,程序会打印源字符串及其副本。

运行此示例:

#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    const char *source = "C strings";
    char *copy = strdup(source);

    if (copy == NULL) {
        puts("Could not duplicate the string.");
        return EXIT_FAILURE;
    }

    printf("Source: %s\nCopy: %s\n", source, copy);
    free(copy);
    return 0;
}
Source: C strings
Copy: C strings

如果 strdup 返回 NULL,请勿将该指针传给字符串函数,也不要对它调用 free。上面的失败分支会报告问题并正常退出。不再需要副本时,调用一次 free 即可;释放源字符串字面量,或在释放副本后继续使用它,都是无效操作。

使用 strndup 最多复制 n 个字节

strndup 同样由 POSIX 规范定义,并在 <string.h> 中声明。其声明为 char *strndup(const char *s, size_t n);。它从 s 复制不超过 n 个字节,并始终在分配所得的结果末尾添加空字节。这里的限制按字节计算,而不是按字符计算;如果限制落在多字节编码字符的中间,该字符可能会被截断。

例如,strndup("C strings", 3) 会生成字符串 "C s"。返回的存储空间是动态分配的,因此要检查是否为 NULL,并像使用 strdup 一样,用 free 释放成功返回的结果。该限制只控制复制量,不会改变结果的生命周期或所有权。

了解 GNU 专用的 strdupa 替代方案

strdupa 是 GNU C 库扩展,不属于 POSIX 或 C 标准函数。需要提供其声明时,请在系统头文件之前定义 _GNU_SOURCE。与 strdup 一样,它接受以空字符结尾的字符串并创建副本,但使用的是与当前函数相关联的自动存储,而不是返回堆分配的内存。

这种存储只在包含它的函数执行期间有效。不要返回该指针并在函数结束后继续使用,也不要将它传给 free。strdupa 的可用性和实现取决于 GNU 环境;如果需要 POSIX 接口,或需要通过 free 控制副本的生命周期,请使用 strdup。这里没有提供可运行的 strdupa 示例,因为它仅适用于 GNU 环境。