目录
字符函数和字符串函数
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在 常量字符串中或者字符数组 中。 字符串常量 适用于那些对它不做修改的字符串函数
1.strlen函数
size_t strlen ( const char * str );
字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )。
参数指向的字符串必须要以 '\0' 结束。
注意函数的返回值为size_t,是无符号的( 易错 )
如果想要了解strlen函数的模拟实现可以点击下方链接:
2.strcpy函数
在C语言中,strcpy
函数是一个非常常用的字符串操作函数,用于复制一个字符串到另一个字符串中。这个函数位于string.h
头文件中,其标准声明如下:
char* strcpy(char * destination, const char * source );
参数说明:
destination
: 这是指向目标字符串的指针,即你希望复制源字符串内容存放的位置。这个区域必须足够大,以便容纳源字符串以及结尾的空字符\0
。source
: 这是指向源字符串的指针,即你要复制的字符串内容。
功能:
strcpy
函数会将source指向的字符串(包括结束的空字符\0
)完整地复制到destination
指向的内存区域中。如果destination
之前已经存储有字符串,那么这些内容会被覆盖。
注意事项:
- 安全性:
strcpy
函数不会检查目标缓冲区的大小,如果源字符串过长可能会导致缓冲区溢出,引发运行时错误或安全漏洞。因此,在实际开发中,推荐使用更安全的替代函数,如strncpy
或strcpy_s
(某些编译器或库中提供)。 - 空字符:
strcpy
会复制源字符串中的所有字符,直到遇到空字符\0
为止,因此,源字符串必须是有效的C字符串(以\0
结尾)。 - 内存重叠:如果
destination
和source
指向的内存区域有重叠,strcpy
的行为是未定义的,可能会导致数据损坏或程序崩溃。
#include <stdio.h>
#include <string.h>
int main()
{
char destination[50];
const char source[] = "Hello, World!";
strcpy(destination, source);
printf("%s\n", destination);
return 0;
}
3.strncat函数
strncat
函数用于将一个字符串添加到另一个字符串的末尾。
char *strncat(char *dest, const char *src, size_t n);
dest
: 是目标字符串,需要有足够的空间来存储源字符串和它自己原有的内容。src
: 是要追加的源字符串。n
: 指定从源字符串中拷贝的最大字符数(不包括结束的空字符\0
)。
#include <stdio.h>
#include <string.h>
int main()
{
char str1[50] = "Hello, ";
char str2[] = "World!";
strncat(str1, str2, strlen(str2)); // 注意:strlen(str2)防止了越界
printf("%s\n", str1); // 输出: Hello, World!
return 0;
}
4.strcmp
strcmp
函数用于比较两个字符串是否相等。它返回一个整数值来表示两个字符串的比较结果,原型也在string.h
中定义。
int strcmp(const char *s1, const char *s2);
s1
和s2
: 分别是要比较的两个字符串。- 如果
s1
小于s2
(按照字典序),函数返回负值。 - 如果
s1
等于s2
,返回0。 - 如果
s1
大于s2
,返回正值。
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "apple";
char str2[] = "banana";
char str3[] = "Apple";
if(strcmp(str1, str2) < 0)
printf("%s comes before %s.\n", str1, str2); // apple comes before banana.
if(strcmp(str1, str3) == 0)
printf("%s equals to %s.\n", str3); // 不执行,因为不相等。
return 0;
}
strcmp函数的模拟实现:
/*int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1==*str2)
{
if (*str1 == '\0')
return 0;//相等
str1++;
str2++;
}
if (*str1 > *str2)
return 1;
else
return -1;
}*/
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;//相等
str1++;
str2++;
}
return (*str1 - *str2);
}
int main()
{
//char arr1[20] = "zhangsan";
//char arr2[] = "zhangsanfeng";
char arr1[] = "abcq";
char arr2[] = "abcq";
//abcdef
//abq
//
//两个字符串比较相等,应该使用strcmp
int ret = my_strcmp(arr1, arr2);
if (ret < 0)
printf("<\n");
else if (ret == 0)
printf("==\n");
else
printf(">\n");
//比较一下两个字符串是否相等
//arr1是数组名,数组名是数组首元素的地址
//arr2是数组名,数组名是数组首元素的地址
/*if (arr1 == arr2)
{
printf("==\n");
}
else
{
printf("!=\n");
}*/
return 0;
}
5.strstr函数
strstr()
函数是C语言标准库中的一个非常实用的字符串处理函数,位于string.h
头文件中。它的主要功能是在一个较大的字符串(haystack)中查找一个较小的子字符串(needle),并返回子字符串第一次出现的位置的指针。如果没有找到子字符串,则返回NULL
。
char *strstr(const char *haystack, const char *needle);
参数说明
haystack
: 这是一个指向源字符串(被搜索的字符串)的指针,即要在其中查找子字符串的大字符串。needle
: 这是一个指向子字符串的指针,即想要在haystack
中查找的字符串。
返回值
- 如果
needle
在haystack
中被找到,函数返回一个指向haystack
中needle
首次出现位置的指针。 - 如果没有找到
needle
,函数返回NULL
。
注意事项
strstr()
不区分大小写,若需要区分大小写查找,需自行实现或先转换字符串。- 搜索时,
haystack
可以包含空字符,needle
也可以为空字符串,但haystack
不能是NULL
。 - 返回的指针指向
haystack
内部,因此修改haystack
内容会影响返回的指针的有效性。
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "Hello, this is a simple example.";
const char target[] = "simple";
char *result = strstr(str, target);
if(result != NULL)
{
printf("Substring found at position: %td\n", result - str);
}
else
{
printf("Substring not found.\n");
}
return 0;
}
在这个例子中,strstr()
函数查找字符串"simple"`在"Hello, this is a simple example."中的位置,并打印出子字符串首次出现的偏移位。
strstr函数的模拟实现:
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* s1 = str1;
const char* s2 = str2;
const char* p = str1;
while (*p)
{
s1 = p;
s2 = str2;
while (*s1!='\0' && *s2!='\0' && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return (char*)p;
}
p++;
}
return NULL;
}
int main()
{
//char email[] = "[email protected]";
//char substr[] = "bitejiuyeke";
//char* ret = my_strstr(email, substr);
char arr1[] = "abcdef";
char arr2[] = "def";
char* ret = my_strstr(arr1, arr2);
if (ret == NULL)
{
printf("子串不存在\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
对于这个函数我们还可以通过数据结构中的KMP算法来实现:
该算法是一种改进的字符串搜索算法,目的是在文本串(常称为S)中查找模式串(常称为P)是否存在,如果存在则返回模式串在文本串中的起始位置,否则返回未找到。KMP算法的核心思想是利用已知的匹配信息,避免重复比较,从而减少不必要的回溯操作,提高搜索效率。
6.KMP算法:
KMP算法的基本步骤:
-
前缀表(Next数组)的构建:
- 为了实现高效搜索,KMP算法首先预处理模式串P,构造一个辅助数组
next[]
(也称为部分匹配表或失配表),该数组记录了模式串中各位置前缀与后缀的最长公共长度。具体构建方法如下:next[0] = -1
初始化。- 当模式串中第i位置的字符与第j位置的字符相同时,
next[i] = next[j] + 1
,否则尝试j回溯。 - 直到找到一个合适的j使得P[0...j]与P[i-j]相同或j=-1为止。
next[i]
的含义是当P[0...i-1]与S的某段匹配失败时,P应跳过的字符数,即P中最大公共前后缀长度。
- 为了实现高效搜索,KMP算法首先预处理模式串P,构造一个辅助数组
-
匹配过程:
- 初始化文本串指针i指向第一个字符,模式串指针j指向第一个字符。
- 当i<s且j<s且字符匹配时,i++, j++。
- 如果j到达P末尾,匹配成功,返回i-j。
- 若不匹配,j回溯,根据next[j]值更新j。
- 如果next[j]=-1,i++, j=0(模式串从头开始比较)
- 否则j=next[j],i不动(模式串向后跳到最长公共前后缀处)
#include <stdio.h>
#include<string.h>
// 构建Next数组
void getNext(const char p[], int next[])
{
int i = 0, j = -1;
next[0] = -1;
while (i < strlen(p))
{
if (j == -1 || p[i] == p[j])
{
i++;
j++;
next[i] = j;
}
else
{
j = next[j];
}
}
}
// KMP匹配函数
int KMPMatch(const char s[], const char p[])
{
int i = 0, j = 0;
int slen = strlen(s), plen = strlen(p);
int next[plen + 1]; // 存储Next数组
getNext(p, next); // 根据模式串p构建Next数组
while (i < slen && j < plen)
{
if (j == -1 || s[i] == p[j])
{ // 当字符匹配或j为-1时
i++;
j++;
}
else
{
j = next[j]; // 失配时,根据Next数组调整j
}
}
if (j == plen)
{
return i - j; // 匹配成功,返回起始位置
}
else
{
return -1; // 匹配失败
}
}
int main()
{
char text[] = "hello world, welcome to the world of programming";
char pattern[] = "world";
int index = KMPMatch(text, pattern);
if (index != -1)
{
printf("语句所在位置: %d\n", index);
}
else
{
printf("没有找到语句\n");
}
return 0;
}
这段代码首先定义了两个函数:getNext
用于生成模式串P的Next数组,KMPMatch
用于进行KMP匹配。在main
函数中,定义了文本串s
和模式串p
,调用KMPMatch
函数进行匹配,并输出匹配结果。如果找到模式串,则输出其在文本串中的起始位置,否则输出“Pattern not found.”。