在 C 语言中,字符串本质上是以空字符 '\0' 结尾的字符数组。与一些高级语言不同,C 语言的标准库并没有提供一个类似 substring() 这样的函数来直接返回一个新的子字符串。
因此,在 C 语言中实现字符串截取,通常需要我们手动操作内存或者使用一些库函数来间接实现。主要有以下 3 种方式:
- 使用 strncpy() 函数。
- 使用指针操作。
- 复制到新字符串数组。
使用 strncpy() 截取字符串
在 C 语言中,我们可以使用 strncpy() 函数从 “原始字符串” 复制指定数量的字符到 “目标字符串” 。
语法:
strncpy(dest, src, n)说明:
strncpy() 函数接收以下 3 个参数。
dest(char *):指向目标字符串的指针。src(const char *):指向原始字符串的指针。n(size_t):要复制的字符数量。
strncpy(dest, src, n) 表示复制 str 中的前 n 个字符到 dest 中去。
示例 1:
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[20];
char str2[] = "JavaScript";
// 截取字符串
strncpy(str1, str2, 4);
// 手动添加空字符
str1[4] = '\0';
puts(str1);
puts(str2);
return 0;
}运行结果如下。
Java
JavaScript分析:
strncpy(str1, str2, 4); 表示截取 str2 的前 4 个字符,然后复制到 str1 中去。由于源字符串 "JavaScript" 的长度大于 4,strncpy() 不会自动添加空字符,因此我们需要手动添加 str1[4] = '\0';,以确保 str1 是一个有效的 C 字符串。
需要注意的是,如果 str1 本身是有内容的字符串,此时复制过来的内容会直接替换原来的内容,请看下面例子。
示例 2:
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[] = "Go";
char str2[] = "Python";
strncpy(str1, str2, 2);
str1[2] = '\0';
puts(str1);
puts(str2);
printf("%d\n", strlen(str1));
printf("%d", strlen(str2));
return 0;
}运行结果如下。
Py
Python
2
6分析:
strncpy(str1, str2, 2); 表示截取 str2 的前 2 个字符("Py"),然后复制到 str1 中去。由于源字符串 "JavaScript" 的长度大于 4,strncpy() 不会自动添加空字符,因此我们需要手动添加 str1[4] = '\0';,以确保 str1 是一个有效的 C 字符串。
使用指针截取字符串
使用指针来截取字符串,这种方法最为简单,但需要注意它并没有创建新的字符串,而是让一个新的指针指向原始字符串的某个位置。
提示: 对于指针,我们在后续的 “C 指针” 这一节会详细介绍。
示例 3:
#include <stdio.h>
int main(void)
{
char str[] = "lvyenet";
char *subStr = &str[4]; // 从索引 4 开始截取
printf("原始字符串: %s\n", str);
printf("截取的子串: %s\n", subStr);
return 0;
}运行结果如下。
原始字符串: lvyenet
截取的子串: net分析:
在上面例子中,我们创建了一个指向 str 数组中索引为 4 的元素的指针 subStr。由于 C 语言中字符串是以空字符 '\0' 结尾的,当我们使用 “%s” 格式符打印 subStr 时,会从 subStr 指向的位置开始打印,直到遇到空字符为止。需要注意的是,这种方法并没有创建新的字符串,subStr 仍然指向原始字符串 str 的一部分。
复制到新的字符数组
这种方法会创建一个新的字符数组,并将原始字符串中需要截取的部分复制到这个新的数组中。
示例 4:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义函数
char *substring(const char *str, int start, int length)
{
// 错误处理
if (str == NULL || start < 0 || length <= 0)
{
return NULL;
}
int str_len = strlen(str);
// 如果起始索引超出范围
if (start >= str_len)
{
return NULL;
}
// 如果截取长度不能超过剩余长度
if (start + length > str_len)
{
length = str_len - start;
}
// 分配内存
char *sub = malloc(sizeof(char) * (length + 1));
// 如果内存分配失败
if (sub == NULL)
{
return NULL;
}
strncpy(sub, str + start, length);
// 添加空字符结尾
sub[length] = '\0';
return sub;
}
int main(void)
{
char str[] = "www.lvyenet.com";
// 从索引 4 开始截取长度为 7 的子字符串
char *sub_str = substring(str, 4, 7);
if (sub_str != NULL)
{
printf("原始字符串: %s\n", str);
printf("截取的子串: %s\n", sub_str);
// 释放动态分配的内存
free(sub_str);
}
else
{
printf("截取失败\n");
}
return 0;
}运行结果如下。
原始字符串: www.lvyenet.com
截取的子串: lvyenet分析:
在这个例子中,我们自定义实现了一个名为 “substring” 的函数,该函数用于实现字符串的截取。substring() 函数会返回一个指向新分配内存的指针,该内存存储着截取的子字符串。
substring(str, 4, 7) 表示从 str 中截取了从索引 4 开始,长度为 7 的子字符串。在 main 函数中,我们打印了这个子字符串,并在使用完之后使用 free() 函数释放了分配的内存,以避免内存泄漏。
