【C语言】一些字符串函数的介绍和实现
C语言中对字符和字符串的处理很是频繁,但是C语言本身是 没有字符串类型的,字符串通常放在 常量字符串 中或者 字符数组 中。
字符串常量适用于那些对它不做修改的 字符串函数。
注: 本文提到的函数基本都在 #include <string.h> 头文件下。
求字符串长度的函数
strlen
size_t strlen ( const char * str );
- 字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
- 参数指向的字符串必须要以 ‘\0’ 结束。
- 注:strlen函数的返回值为size_t,是无符号的
关于strlen的返回值测试:
#include <stdio.h>
#include <string.h>
int main()
{
const char*str1 = "abcdef";
const char*str2 = "bbb";
if(strlen(str2)-strlen(str1)>0)
{
printf("str2>str1\n");
}
else
{
printf("srt1>str2\n");
}
return 0;
}
结果恒为str2>str1,因为strlen返回值为无符号数,故相减结果也为无符号数,自然大于0。
strlen函数的实现:
方法一(计数器):
#include <stdio.h>
#include <assert.h>
int MyStrlen(const char *pstr)
{
assert(pstr != NULL);
int count = 0;
while(*pstr)
{
count++;
pstr++;
}
return count;
}
int main()
{
char str[] = "abcdef";
char *pstr = str;
//printf("%d\n",MyStrlen(NULL));
printf("%d\n",MyStrlen(pstr));
return 0;
}
方法二:
//不能创建临时变量计数器
int my_strlen(const char * str)
{
if(*str == '\0')
return 0;
else
return 1+my_strlen(str+1);
方法三:
//指针-指针的方式
int my_strlen(char *s)
{
char *p = s;
while(*p != ‘\0’ )
p++;
return p-s;
}
长度不受限制的字符串函数
strcpy
字符串复制函数
char* strcpy(char * destination, const char * source );
- 源字符串必须以 ‘\0’ 结束。
- strcpy会将源字符串中的 ‘\0’ 拷贝到目标空间。
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可变
strcpy函数的实现:
#include <stdio.h>
#include <assert.h>
char *MyStrcpy(char *dest,const char *src)
{//字符串复制
assert(dest != NULL && src != NULL);
char *p = dest;
while (*src != '\0')
{
*dest = *src;
src++;
dest++;
}
*dest = '\0';
return p;
}
int main()
{
char dest[10] = { 0 };
char *src = "abcdef";
MyStrcpy(dest, src);//返回值是目的地的地址,为了支持链式表达式
printf("%s\n", dest);
return 0;
}
strcat
字符串拼接函数
char * strcat ( char * destination, const char * source )
- 源字符串必须以 ‘\0’ 结束。
- 目标空间必须有足够的大,能容纳下源字符串的内容。
- 目标空间必须可修改
strcat函数的实现:
#include <stdio.h>
#include <assert.h>
char *MyStrcat(char *dest,const char *src)
{//字符串拼接函数
assert(dest);
if(src == NULL)
{
return dest;
}
char *p = dest;
while(*dest != '\0')
{
dest++;
}
while(*src != '\0')
{
*dest = *src;
dest++;
src++;
}
*dest = '\0';
return p;
}
int main()
{
char dest[20] = "abcdef";
char *src = "helloworld";
MyStrcat(dest,src);
printf("%s\n",dest);
return 0;
}
strcmp
字符串比较函数
int strcmp (const char * str1, const char * str2 );
标准规定:
- 第一个字符串大于第二个字符串,则返回大于0的数字
- 第一个字符串等于第二个字符串,则返回0
- 第一个字符串小于第二个字符串,则返回小于0的数字
strcmp函数的实现:
#include <stdio.h>
#include <assert.h>
char *MyStrcmp(char *str1,char *str2)
{//字符串比较函数
assert(str1 && str2);
if(str1 == NULL)
return -1;
if(str2 == NULL)
return 1;
while(*str1 == *str2)
{
if(*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
//两字符串不相等故进行比较
if(*str1 > *str2)
{
return 1;
}
else
{
return -1;
}
}
int main()
{
char *str1 = "abcdef";
char *str2 = "abfdef";
int ret = MyStrcmp(str1,str2);
/*返回值
>0 STR1 > STR2
=0 STR1 = STR2
<0 STR1 < STR2 */
printf("%d",ret);
return 0;
}
长度受限制的字符串函数
strncpy
拷贝n个字符
char * strncpy ( char * destination, const char * source, size_t num );
- 拷贝num个字符从源字符串到目标空间。
- 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个
strncat
拼接n个字符
char * strncat ( char * destination, const char * source, size_t num );
strncmp
比较n个字符
int strncmp ( const char * str1, const char * str2, size_t num );
比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完
字符串查找函数
strstr
在主串中查找子串第一次出现的位置
注:KMP算法实现了类似的功能,复杂,比较高效。
char * strstr ( const char *, const char * );
strstr函数的实现:
#include <stdio.h>
#include <assert.h>
char *MyStrstr(char *str1,char *str2)
{
char *start = str1;
while(*start != '\0')
{
char *s1 = start;
char *s2 = str2;
while(*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if(*s2 == '\0')
{
return start;
}
start++;
}
return NULL;
}
int main()
{
char *str1 = "heaabcdef";//主串
char *str2 = "abc";//子串
char *p = MyStrstr(str1,str2);
printf("%s\n",p);
return 0;
}
strtok
字符串分割函数
char * strtok( char * str, const char * sep );
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。
(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为 NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
函数使用的例子:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");//以‘ ,.-’进行分割
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
输出为:
错误信息报告函数
strerror
返回错误信息的函数
char * strerror(int errnum);
返回错误码,所对应的错误信息。
#include <errno.h>//必须包含的头文件
函数使用的例子:
#include <stdio.h>
#include <string.h>
#include <errno.h>//必须包含的头文件
int main ()
{
FILE * pFile;
pFile = fopen ("unexist.ent","r");
if (pFile == NULL)
printf ("Error opening file unexist.ent: %s\n",strerror(errno));
//errno: Last error number
return 0;
}
输出为:
内存操作函数
memcpy
void * memcpy ( void * destination, const void * source, size_t num );
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
- 这个函数在遇到 ‘\0’ 的时候并不会停下来。
- 如果source和destination有任何的重叠,复制的结果都是未定义的
memcpy函数的实现:
注意避免内存重叠
#include <stdio.h>
#include <assert.h>
void *MyMemcpy(void *dest,void *src,int count)
{
void *ret = dest;
assert(dest);
assert(src);
while (count != 0)
{
*(char *)dest = *(char *)src;
((char *)dest)++;
((char *)src)++;
count--;
}
return ret;
}
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
MyMemcpy(arr, arr + 2, 16);
for (int i = 0; i < 8; i++)
{
printf("%d", arr[i]);
}
printf("\n");
return 0;
}
memmove
void * memmove ( void * destination, const void * source, size_t num );
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
memmove函数的实现:
可以处理内存的重叠
#include <stdio.h>
#include <Windows.h>
void * MyMemmove(void *dest, void * src, int count)
{
void *ret = dest;
if (src > dest)
{
while (count != 0)
{
*(char *)dest = *(char *)src;
((char *)dest)++;
((char *)src)++;
count--;
}
}
else
{
count--;
while (count >= 0)
{
*((char *)dest + count) = *((char *)src + count);
count--;
}
}
return ret;
}
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
MyMemmove(arr+2, arr, 16);
for (int i = 0; i < 8; i++)
{
printf("%d", arr[i]);
}
printf("\n");
system("pause");
return 0;
}
memcmp
int memcmp ( const void * ptr1, const void * ptr2,size_t num );
比较从ptr1和ptr2指针开始的num个字节
(比较两份内存里面值的大小)
函数使用的例子:
#include <stdio.h>
#include <string.h>
int main ()
{
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
n=memcmp ( buffer1, buffer2, sizeof(buffer1) );
if (n>0) printf ("'%s' is greater than '%s'.\n",buffer1,buffer2);
else if (n<0) printf ("'%s' is less than '%s'.\n",buffer1,buffer2);
else printf ("'%s' is the same as '%s'.\n",buffer1,buffer2);
return 0;
}
输出为: