C 语言 <string.h> 常用函数详解:长度、拷贝、比较、查找与转换

何川
何川
发布时间:2026-08-22 | 182人浏览过
原创

前言

在 C 语言里,字符串处理看起来只是几组函数名,但真正决定代码是否稳妥的,往往是返回值含义、缓冲区大小和 \0 结束符这些细节。本文不按生硬的 API 列表来堆功能,而是按“求长度、做拷贝与拼接、比较与查找、文本转数字”几个常见任务来梳理,让你读完后能更快判断该用哪个函数,以及该重点检查哪里。

在 C 语言里,字符串并不是独立类型,而是以 \0 结尾的字符数组,这也是 <string.h> 为什么几乎绕不过去的原因。与其死记函数名,不如按常见任务来理解:什么时候该算长度,什么时候该拷贝或拼接,比较结果该怎么判断,查找和转换又该看哪些返回值。读完这篇,你能快速判断每个函数适合解决什么问题,以及哪些地方需要额外注意缓冲区和结束符。

先搞清长度:strlen

处理 C 字符串时,最基础的一步就是确认长度。strlen 用来计算字符串的实际长度,但不包含终止空字符 \0。

strlen 的作用与返回值

size_t strlen(const char *str);
  • str:指向要计算长度的 C 字符串。
  • 返回值:字符串长度,不包括 \0。

示例代码

// www.ja vascriptcn.com code example
#include <stdio.h>
#include <string.h>

int main() {
    const char *str = "Hello, World!";
    size_t length = strlen(str);
    printf("The length of the string is: %zun", length);
    return 0;
}
The length of the string is: 13

这里的结果是 13,因为 Hello, World! 一共 13 个可见字符,末尾的 \0 不计入长度。

展示 strcmp、strncmp、strstr、strchr 的返回方式与典型判断逻辑的信息图
比较与查找函数的判断方式比较函数看正负零,查找函数看指针或 NULL,这张图适合放在比较与查找两节之后。
展示 <string.h> 中拷贝与拼接函数差异、缓冲区要求和结束符处理重点的信息图
拷贝与拼接函数怎么选把 strcpy、strncpy、strcat、strncat 放在同一张图里。

需要复制或追加时,用对拷贝和拼接函数

这组函数最常见,也最容易因为缓冲区大小和结束符处理不当而出问题。阅读示例时,重点要看目标数组是否足够大,以及限定长度版本是否手动补上 \0。

strcpy:完整复制一个字符串

strcpy 会把源字符串连同终止符 \0 一起复制到目标缓冲区,因此目标空间必须足够大。

char *strcpy(char *dest, const char *src);
  • dest:目标缓冲区地址。
  • src:源字符串地址。
  • 返回值:指向目标缓冲区 dest 的指针。
// www.ja vascriptcn.com code example
#include <stdio.h>
#include <string.h>

int main() {
    char dest[50];
    const char *src = "Hello, World!";

    strcpy(dest, src);
    printf("Copied string: %sn", dest);

    return 0;
}
Copied string: Hello, World!

strncpy:按最大字符数复制

strncpy 允许限制复制的最大字符数,但它有一个很关键的特点:如果复制长度刚好用满,目标串不一定会自动补上 \0,所以很多场景都要手动处理结束符。

char *strncpy(char *dest, const char *src, size_t n);
  • dest:目标缓冲区地址。
  • src:源字符串地址。
  • n:最大复制字符数。
  • 返回值:指向目标缓冲区 dest 的指针。
// www.ja vascriptcn.com code example
#include <stdio.h>
#include <string.h>

int main() {
    char dest[50];
    const char *src = "Hello, World!";

    strncpy(dest, src, 5); // 只复制前五个字符
    dest[5] = '\0'; // 确保字符串以 \0 结尾
    printf("Copied string: %sn", dest);

    return 0;
}
Copied string: Hello

strcat:把字符串追加到末尾

strcat 会从目标字符串末尾开始,把源字符串接上去。前提同样是:dest 要预留足够空间。

char *strcat(char *dest, const char *src);
  • dest:目标字符串缓冲区地址。
  • src:源字符串地址。
  • 返回值:指向目标缓冲区 dest 的指针。
// www.ja vascriptcn.com code example
#include <stdio.h>
#include <string.h>

int main() {
    char dest[50] = "Hello, ";
    const char *src = "World!";

    strcat(dest, src);
    printf("Concatenated string: %sn", dest);

    return 0;
}
Concatenated string: Hello, World!

strncat:只追加一部分内容

strncat 用于限制追加字符数,适合只拼接源字符串前面的一段内容。

char *strncat(char *dest, const char *src, size_t n);
  • dest:目标字符串缓冲区地址。
  • src:源字符串地址。
  • n:最大追加字符数。
  • 返回值:指向目标缓冲区 dest 的指针。
// www.ja vascriptcn.com code example
#include <stdio.h>
#include <string.h>

int main() {
    char dest[50] = "Hello, ";
    const char *src = "World!";

    strncat(dest, src, 3); // 只追加前三个字符
    printf("Concatenated string: %sn", dest);

    return 0;
}
Concatenated string: Hello, Worl

按给出的示例,strncat(dest, src, 3) 只会追加 Wor,因此结果应体现“只拼接前三个字符”这一点。阅读这类代码时,建议始终同时核对“源串截取长度”和“目标缓冲区剩余空间”。

比较两个字符串时,重点看返回值含义

字符串比较不能直接靠 == 判断内容是否相同,标准库提供的是按字典序比较的函数。它们的共同特点是:返回负数、零或正数,分别表示“小于、等于、大于”。

strcmp:比较完整字符串

int strcmp(const char *str1, const char *str2);
  • str1:第一个字符串地址。
  • str2:第二个字符串地址。
  • 返回值:负数、零或正数。
// www.ja vascriptcn.com code example
#include <stdio.h>
#include <string.h>

int main() {
    const char *str1 = "apple";
    const char *str2 = "banana";

    int result = strcmp(str1, str2);

    if (result < 0) {
        printf("%s is less than %sn", str1, str2);
    } else if (result == 0) {
        printf("%s is equal to %sn", str1, str2);
    } else {
        printf("%s is greater than %sn", str1, str2);
    }

    return 0;
}
apple is less than banana

strncmp:只比较前 n 个字符

如果只关心前缀是否一致,就可以使用 strncmp。

int strncmp(const char *str1, const char *str2, size_t n);
  • str1:第一个字符串地址。
  • str2:第二个字符串地址。
  • n:最大比较字符数。
  • 返回值:负数、零或正数。
// www.ja vascriptcn.com code example
#include <stdio.h>
#include <string.h>

int main() {
    const char *str1 = "apple";
    const char *str2 = "appetizer";

    int result = strncmp(str1, str2, 3);

    if (result < 0) {
        printf("%s is less than %sn", str1, str2);
    } else if (result == 0) {
        printf("%s is equal to %sn", str1, str2);
    } else {
        printf("%s is greater than %sn", str1, str2);
    }

    return 0;
}
apple is equal to appetizer

这个例子里只比较前 3 个字符,app 与 app 相同,所以结果为 0。

查找子串或字符,用返回指针判断是否命中

查找类函数的返回值通常不是长度或布尔值,而是“指向找到位置的指针”。如果没有找到,则返回 NULL。

strstr:查找子字符串首次出现位置

char *strstr(const char *haystack, const char *needle);
  • haystack:主字符串地址。
  • needle:要查找的子字符串地址。
  • 返回值:找到时返回首次出现位置的指针,未找到返回 NULL。
// www.ja vascriptcn.com code example
#include <stdio.h>
#include <string.h>

int main() {
    const char *haystack = "Hello, World!";
    const char *needle = "World";

    char *result = strstr(haystack, needle);

    if (result != NULL) {
        printf("Substring found at position: %ldn", result - haystack);
    } else {
        printf("Substring not found.n");
    }

    return 0;
}
Substring found at position: 7

strchr:查找字符首次出现位置

char *strchr(const char *str, int c);
  • str:要搜索的字符串地址。
  • c:要查找的字符。
  • 返回值:找到时返回该字符首次出现位置的指针,未找到返回 NULL。
// www.ja vascriptcn.com code example
#include <stdio.h>
#include <string.h>

int main() {
    const char *str = "Hello, World!";

    char *result = strchr(str, 'W');

    if (result != NULL) {
        printf("Character found at position: %ldn", result - str);
    } else {
        printf("Character not found.n");
    }

    return 0;
}
Character found at position: 7

这类函数的一个常见用法是通过“结果指针减去原始指针”来计算偏移位置,示例中的 7 就是这么得出的。

把文本转成数字:strtol 和 strtoul

当输入来自命令行、配置文件或文本内容时,常常需要把字符串解析为数值。这里除了看转换结果,更重要的是检查 endptr,确认字符串是否被完整解析。

展示 strtol 与 strtoul 的转换流程、base 参数和 endptr 校验逻辑的信息图
字符串转数字时要看什么字符串转数字的关键不只是拿到结果,而是确认有没有完整解析;这张图把 base、endptr。

strtol:转换为长整型

long int strtol(const char *str, char **endptr, int base);
  • str:要转换的字符串地址。
  • endptr:指向未被转换部分第一个字符的指针。
  • base:数字基数,通常为 10 或 16。
  • 返回值:转换后的长整型数值。
// www.ja vascriptcn.com code example
#include <stdio.h>
#include <stdlib.h>

int main() {
    const char *str = "12345";
    char *endptr;

    long int num = strtol(str, &endptr, 10);

    if (*endptr == '\0') {
        printf("Converted number: %ldn", num);
    } else {
        printf("Invalid input.n");
    }

    return 0;
}
Converted number: 12345

strtoul:转换为无符号长整型

unsigned long int strtoul(const char *str, char **endptr, int base);
  • str:要转换的字符串地址。
  • endptr:指向未被转换部分第一个字符的指针。
  • base:数字基数,通常为 10 或 16。
  • 返回值:转换后的无符号长整型数值。
// www.ja vascriptcn.com code example
#include <stdio.h>
#include <stdlib.h>

int main() {
    const char *str = "12345";
    char *endptr;

    unsigned long int num = strtoul(str, &endptr, 10);

    if (*endptr == '\0') {
        printf("Converted number: %lun", num);
    } else {
        printf("Invalid input.n");
    }

    return 0;
}
Converted number: 12345

相比直接使用更简单的转换方式,strtol 和 strtoul 的优势在于:你可以明确知道解析停在什么位置,这对输入校验尤其重要。

怎么快速记住 <string.h> 的常用函数

如果按用途来记,<string.h> 这批函数其实并不难:strlen 负责测长度,strcpy/strncpy 负责拷贝,strcat/strncat 负责拼接,strcmp/strncmp 负责比较,strstr/strchr 负责查找,而 strtol/strtoul 则负责把文本转成数字。

实际编写 C 程序时,最值得反复检查的仍然是三件事:目标缓冲区是否足够大、字符串是否正确以 \0 结束、返回值是否按预期判断。把这三点养成习惯,字符串处理会稳很多。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表