C 语言字符串函数大全
字符串基础与函数概述
在C语言中,字符串是一种非常重要的数据类型,虽然C语言没有专门的字符串类型,但通过字符数组以及一些相关的库函数来实现对字符串的操作。字符串函数在处理文本、文件输入输出、数据解析等众多场景中都扮演着关键角色。这些函数主要定义在<string.h>
头文件中,下面将详细介绍各类字符串函数。
strlen函数 - 计算字符串长度
strlen
函数用于计算字符串的长度,不包括字符串结束符'\0'
。其函数原型为:
size_t strlen(const char *str);
这里str
是要计算长度的字符串指针,返回值类型size_t
是在<stddef.h>
中定义的无符号整数类型,用于表示对象的大小或长度。
示例代码:
#include <stdio.h>
#include <string.h>
int main() {
const char *str = "Hello, World!";
size_t length = strlen(str);
printf("字符串 %s 的长度是 %zu\n", str, length);
return 0;
}
在上述代码中,定义了字符串"Hello, World!"
,通过strlen
函数获取其长度并打印。这里需要注意的是,strlen
函数是通过逐个检查字符,直到遇到'\0'
为止来计算长度的。如果字符串没有正确以'\0'
结尾,strlen
函数的行为是未定义的,可能会导致程序崩溃或得到错误的结果。
strcpy函数 - 字符串复制
strcpy
函数用于将一个字符串复制到另一个字符数组中。其函数原型为:
char *strcpy(char *dest, const char *src);
其中dest
是目标字符数组的指针,src
是源字符串的指针。函数返回值是指向目标字符串dest
的指针。
示例代码:
#include <stdio.h>
#include <string.h>
int main() {
char source[] = "Hello";
char destination[20];
strcpy(destination, source);
printf("复制后的字符串: %s\n", destination);
return 0;
}
在这个例子中,将source
字符串复制到destination
数组中。需要特别注意的是,目标数组destination
必须有足够的空间来容纳源字符串及其结束符'\0'
,否则会导致缓冲区溢出错误,这是一种严重的安全漏洞,可能会被恶意利用来执行任意代码。
strncpy函数 - 安全的字符串复制
为了避免strcpy
可能导致的缓冲区溢出问题,strncpy
函数提供了一种更安全的字符串复制方式。其函数原型为:
char *strncpy(char *dest, const char *src, size_t n);
dest
是目标字符数组,src
是源字符串,n
指定要从源字符串复制的最大字符数。如果源字符串的长度小于n
,strncpy
会在复制完源字符串后,在目标数组中填充'\0'
直到n
个字符。如果源字符串长度大于等于n
,目标数组将不会以'\0'
结尾,除非在复制n
个字符之前遇到了'\0'
。
示例代码:
#include <stdio.h>
#include <string.h>
int main() {
char source[] = "Hello, World!";
char destination[5];
strncpy(destination, source, 4);
destination[4] = '\0'; // 手动添加字符串结束符
printf("复制后的字符串: %s\n", destination);
return 0;
}
在上述代码中,由于目标数组destination
的大小为5,strncpy
只复制4个字符,此时需要手动添加'\0'
以确保目标数组是一个合法的字符串。虽然strncpy
相对安全,但使用不当仍可能导致问题,例如忘记手动添加'\0'
可能会在后续操作中引发未定义行为。
strcat函数 - 字符串拼接
strcat
函数用于将一个字符串追加到另一个字符串的末尾。其函数原型为:
char *strcat(char *dest, const char *src);
dest
是目标字符串,src
是要追加的源字符串。函数返回指向目标字符串dest
的指针。目标字符串dest
必须有足够的空间来容纳源字符串和自身,否则会导致缓冲区溢出。
示例代码:
#include <stdio.h>
#include <string.h>
int main() {
char dest[20] = "Hello, ";
const char *src = "World!";
strcat(dest, src);
printf("拼接后的字符串: %s\n", dest);
return 0;
}
在这个例子中,将src
字符串追加到dest
字符串的末尾。同样,在使用strcat
时要确保dest
有足够的空间,否则可能会覆盖内存中的其他数据,引发程序错误或安全问题。
strncat函数 - 安全的字符串拼接
类似于strncpy
,strncat
提供了一种更安全的字符串拼接方式。其函数原型为:
char *strncat(char *dest, const char *src, size_t n);
dest
是目标字符串,src
是源字符串,n
是要从源字符串追加的最大字符数。strncat
会在目标字符串的'\0'
处开始追加源字符串,并且保证目标字符串以'\0'
结尾。
示例代码:
#include <stdio.h>
#include <string.h>
int main() {
char dest[20] = "Hello, ";
const char *src = "World! This is a long string.";
strncat(dest, src, 5);
printf("拼接后的字符串: %s\n", dest);
return 0;
}
在这个例子中,只从src
字符串中追加5个字符到dest
字符串。strncat
通过限制追加字符数,减少了缓冲区溢出的风险,但在使用时仍需合理分配目标字符串的空间,以确保拼接操作的正确性。
strcmp函数 - 字符串比较
strcmp
函数用于比较两个字符串。其函数原型为:
int strcmp(const char *str1, const char *str2);
str1
和str2
是要比较的两个字符串。函数返回值遵循以下规则:
- 如果
str1
小于str2
,返回一个负整数。 - 如果
str1
等于str2
,返回0。 - 如果
str1
大于str2
,返回一个正整数。
字符串比较是按字符的ASCII码值逐个进行的,直到遇到不同的字符或到达字符串结束符'\0'
。
示例代码:
#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 小于 %s\n", str1, str2);
} else if (result == 0) {
printf("%s 等于 %s\n", str1, str2);
} else {
printf("%s 大于 %s\n", str1, str2);
}
return 0;
}
在上述代码中,比较str1
和str2
两个字符串,并根据返回结果输出相应的信息。需要注意的是,strcmp
区分大小写,如果需要不区分大小写的比较,可以使用stricmp
(在某些系统中)或strcasecmp
(POSIX系统)函数。
strncmp函数 - 比较指定长度的字符串
strncmp
函数用于比较两个字符串的前n
个字符。其函数原型为:
int strncmp(const char *str1, const char *str2, size_t n);
str1
和str2
是要比较的字符串,n
是比较的最大字符数。返回值规则与strcmp
类似。
示例代码:
#include <stdio.h>
#include <string.h>
int main() {
const char *str1 = "apple";
const char *str2 = "applet";
int result = strncmp(str1, str2, 3);
if (result < 0) {
printf("前3个字符中,%s 小于 %s\n", str1, str2);
} else if (result == 0) {
printf("前3个字符中,%s 等于 %s\n", str1, str2);
} else {
printf("前3个字符中,%s 大于 %s\n", str1, str2);
}
return 0;
}
在这个例子中,只比较str1
和str2
的前3个字符。strncmp
在需要控制比较长度的场景中非常有用,比如在搜索部分匹配的字符串时。
strchr函数 - 查找字符在字符串中的首次出现位置
strchr
函数用于在字符串中查找一个字符的首次出现位置。其函数原型为:
char *strchr(const char *str, int c);
str
是要查找的字符串,c
是要查找的字符(会被自动转换为char
类型)。函数返回一个指针,指向字符c
在字符串str
中首次出现的位置,如果未找到则返回NULL
。
示例代码:
#include <stdio.h>
#include <string.h>
int main() {
const char *str = "Hello, World!";
char *result = strchr(str, 'o');
if (result != NULL) {
printf("字符 'o' 首次出现在位置: %ld\n", result - str);
} else {
printf("未找到字符 'o'\n");
}
return 0;
}
在上述代码中,查找字符'o'
在字符串str
中的位置,并输出其相对于字符串起始位置的偏移量。如果未找到,输出相应提示信息。
strrchr函数 - 查找字符在字符串中的最后出现位置
strrchr
函数与strchr
类似,但它查找的是字符在字符串中最后出现的位置。其函数原型为:
char *strrchr(const char *str, int c);
str
是字符串,c
是要查找的字符。返回一个指针,指向字符c
在字符串str
中最后出现的位置,如果未找到则返回NULL
。
示例代码:
#include <stdio.h>
#include <string.h>
int main() {
const char *str = "Hello, World!";
char *result = strrchr(str, 'o');
if (result != NULL) {
printf("字符 'o' 最后出现在位置: %ld\n", result - str);
} else {
printf("未找到字符 'o'\n");
}
return 0;
}
在这个例子中,查找字符'o'
在字符串str
中最后出现的位置,并输出其位置信息。与strchr
不同,strrchr
是从字符串的末尾开始向前查找。
strstr函数 - 查找子字符串在字符串中的首次出现位置
strstr
函数用于在一个字符串中查找另一个子字符串的首次出现位置。其函数原型为:
char *strstr(const char *haystack, const char *needle);
haystack
是要搜索的主字符串,needle
是要查找的子字符串。函数返回一个指针,指向子字符串needle
在主字符串haystack
中首次出现的位置,如果未找到则返回NULL
。
示例代码:
#include <stdio.h>
#include <string.h>
int main() {
const char *haystack = "Hello, World! This is a test.";
const char *needle = "is";
char *result = strstr(haystack, needle);
if (result != NULL) {
printf("子字符串 '%s' 首次出现在位置: %ld\n", needle, result - haystack);
} else {
printf("未找到子字符串 '%s'\n", needle);
}
return 0;
}
在上述代码中,查找子字符串"is"
在主字符串haystack
中的位置,并输出其相对于主字符串起始位置的偏移量。如果未找到,输出相应提示信息。
strtok函数 - 字符串分割
strtok
函数用于将字符串按照指定的分隔符进行分割。其函数原型为:
char *strtok(char *str, const char *delim);
str
是要分割的字符串,delim
是包含分隔符的字符串。该函数的使用较为特殊,第一次调用时,str
参数传入要分割的字符串,后续调用时,str
参数传入NULL
,函数会记住上次分割的位置并继续分割。当没有更多的分隔符时,函数返回NULL
。
示例代码:
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello,World;This is a test";
const char *delim = ",; ";
char *token = strtok(str, delim);
while (token != NULL) {
printf("分割后的子字符串: %s\n", token);
token = strtok(NULL, delim);
}
return 0;
}
在这个例子中,字符串str
按照","
、";"
和" "
进行分割,通过循环不断调用strtok
获取分割后的子字符串并打印。需要注意的是,strtok
会修改原始字符串,将分隔符替换为'\0'
,并且在多线程环境下使用时需要特别小心,因为它不是线程安全的。
sprintf函数 - 格式化字符串输出到字符数组
sprintf
函数用于将格式化的数据输出到一个字符数组中。其函数原型为:
int sprintf(char *str, const char *format, ...);
str
是目标字符数组,format
是格式化字符串,与printf
函数的格式化字符串类似,后面的...
表示可变参数列表,根据格式化字符串的要求提供相应的参数。函数返回成功写入的字符数(不包括'\0'
)。
示例代码:
#include <stdio.h>
int main() {
char buffer[50];
int num = 123;
const char *text = "Hello";
int result = sprintf(buffer, "The number is %d and the text is %s", num, text);
printf("写入的字符数: %d\n", result);
printf("格式化后的字符串: %s\n", buffer);
return 0;
}
在上述代码中,将整数num
和字符串text
按照指定的格式输出到字符数组buffer
中,并打印写入的字符数和格式化后的字符串。使用sprintf
时要确保目标数组有足够的空间,否则会导致缓冲区溢出。
sscanf函数 - 从字符串中按格式读取数据
sscanf
函数用于从字符串中按照指定的格式读取数据。其函数原型为:
int sscanf(const char *str, const char *format, ...);
str
是要读取的字符串,format
是格式化字符串,与scanf
函数的格式化字符串类似,后面的...
表示可变参数列表,用于存储读取的数据。函数返回成功匹配和赋值的输入项数,如果到达输入字符串末尾或匹配失败则返回一个小于预期值的数。
示例代码:
#include <stdio.h>
int main() {
const char *str = "123 Hello";
int num;
char text[20];
int result = sscanf(str, "%d %s", &num, text);
if (result == 2) {
printf("读取的整数: %d\n", num);
printf("读取的字符串: %s\n", text);
} else {
printf("读取失败\n");
}
return 0;
}
在这个例子中,从字符串str
中按照"%d %s"
的格式读取一个整数和一个字符串,并根据返回值判断读取是否成功。sscanf
在解析包含特定格式数据的字符串时非常有用,但同样要注意参数的正确性和目标变量的空间足够。
memset函数 - 填充内存区域
虽然memset
函数不完全是字符串函数,但常用于初始化字符串相关的内存区域。其函数原型为:
void *memset(void *ptr, int value, size_t num);
ptr
是指向要填充的内存区域的指针,value
是要填充的值(会被转换为unsigned char
类型),num
是要填充的字节数。函数返回指向ptr
的指针。
示例代码:
#include <stdio.h>
#include <string.h>
int main() {
char buffer[10];
memset(buffer, 'A', 5);
buffer[5] = '\0';
printf("填充后的字符串: %s\n", buffer);
return 0;
}
在上述代码中,将字符数组buffer
的前5个字节填充为字符'A'
,并手动添加字符串结束符'\0'
,然后打印填充后的字符串。memset
常用于初始化数组、结构体等内存区域,确保数据的一致性。
memcpy函数 - 内存块复制
memcpy
函数用于将一块内存区域的内容复制到另一块内存区域。其函数原型为:
void *memcpy(void *dest, const void *src, size_t n);
dest
是目标内存区域的指针,src
是源内存区域的指针,n
是要复制的字节数。函数返回指向dest
的指针。
示例代码:
#include <stdio.h>
#include <string.h>
int main() {
char source[] = "Hello";
char destination[20];
memcpy(destination, source, strlen(source) + 1);
printf("复制后的字符串: %s\n", destination);
return 0;
}
在这个例子中,将source
字符串复制到destination
数组中,通过strlen(source) + 1
确保包括字符串结束符'\0'
。memcpy
可以用于复制任何类型的内存数据,不限于字符串,但在复制字符串时要注意处理好结束符。与strcpy
不同,memcpy
不会检查目标内存区域是否以'\0'
结尾,也不会自动添加'\0'
,这在处理非字符串数据时很有用,但在处理字符串时需要额外注意。
memcmp函数 - 比较内存块
memcmp
函数用于比较两个内存块的内容。其函数原型为:
int memcmp(const void *ptr1, const void *ptr2, size_t n);
ptr1
和ptr2
是要比较的两个内存块的指针,n
是要比较的字节数。返回值规则与strcmp
类似:
- 如果
ptr1
小于ptr2
,返回一个负整数。 - 如果
ptr1
等于ptr2
,返回0。 - 如果
ptr1
大于ptr2
,返回一个正整数。
示例代码:
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "Hello";
char str2[] = "Hello";
int result = memcmp(str1, str2, strlen(str1));
if (result < 0) {
printf("str1 小于 str2\n");
} else if (result == 0) {
printf("str1 等于 str2\n");
} else {
printf("str1 大于 str2\n");
}
return 0;
}
在上述代码中,比较str1
和str2
两个字符串的前strlen(str1)
个字节。memcmp
在需要精确比较内存内容而不仅仅是字符串时非常有用,它不依赖于字符串结束符'\0'
,而是按照指定的字节数进行比较。
通过对这些C语言字符串函数的深入理解和熟练运用,开发者可以更加高效地处理字符串相关的操作,无论是文本处理、数据解析还是文件操作等场景,都能游刃有余。同时,在使用这些函数时,要始终注意内存管理和边界条件,避免出现缓冲区溢出等安全问题和程序错误。