目录
前言:
本章重点介绍处理字符和字符串的库函数的使用和注意事项。
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。
字符串常量适用于那些对它不做修改的字符串函数。
函数介绍
strlen
函数原型:size_t strlen( const char * str);
• 字符串以'\0'作为结束标识,strlen函数返回的是在字符串中'\0'前面出现的字符个数(不包括'\0');
• 参数指向的字符串必须要以'\0'结束;
• 注意函数的返回值位size_t,是无符号的(易错);
• 学会strlen函数的模拟实现。
简单的用法:
接下来我们进行更深层的测试。
可以看到这次打印的数字为3,这是因为strlen只要遇到'\0'就会停止。
而这次打印了个19,这是因为我们没有向字符串arr中添加'\0',VS也给我们报了警告,这时候strlen会返回随机值。
注意看,按理说第一个字符串的长度应该小于第二个字符串的长度,但是最后却打印了>,这是因为strlen返回的值是size_t类型,也就是无符号的,这里应该算的结果是-3,但因为是无符号类型,所以-3直接被当成了原码,也就是被当成了正数,所以打印>。
模拟strlen
这里我们讲三种模拟实现strlen函数的方法:1.计数器。2.递归。3.指针。
计数器
#include<stdio.h>
#include<assert.h>
int my_strlen(const char* str)
{
assert(str);
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
//输出结果为6
递归
#include<stdio.h>
#include<assert.h>
int my_strlen(const char* str)
{
assert(str);
if (*str)
return 1 + my_strlen(++str);
else
return 0;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
//输出结果为6
指针 - 指针
#include<stdio.h>
#include<assert.h>
int my_strlen(const char* str)
{
assert(str);
char* dest = str;
while (*++str)
{
;
}
return str - dest;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
Strcpy
函数原型:char* strcpy ( char * destination , const char * source ) ;
• Copies the C string pointed by source into the array pointed by destination,including the terminating null character (and stopping at that point );
• 源字符串必须以'\0'结束;
• 会将源字符串中的'\0'拷贝到目标空间;
• 目标空间必须足够大,以确保能存放源字符串;
• 目标空间必须可变;
• 学会模拟实现
示例使用:
#include<string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[20] = { 0 };
strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}
//打印 abcdef
几个错误示范:
int main()
{
char arr1[] = "qwertyuiop";
//char arr2[20] = arr1;//err
char arr2[20] = { 0 };
//arr2 = arr1; //err
return 0;
}
int main()
{
//目标空间必须足够大
char arr1[20] = "abcdefghi";
char arr2[3] = "";//3
strcpy(arr2, arr1);
printf("%s\n", arr2);retrun 0;
}
int main()
{//目标空间必须可以修改
char* p = "abcdefghi";
char arr2[20] = "hehe";
strcpy(p, arr2);
printf("%s\n", p);return 0;
}
模拟实现strcpy
Strcat
函数原型:char * strcat ( char* ddestination , const char * source );
• Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
• 源字符串必须以'\0'结束
• 目标空间必须足够大,能容纳下源字符串的内容。
• 目标空间必须可修改。
• 字符串自己给自己追加,如何?
一些简单用法:
模拟实现strcat
#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*dest)
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
my_strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
strcmp
函数原型:int strcmp ( const char* str1 , sont char* str2 ) ;
• This function strarts comparing the first character of each string.If the are queal to each other,it continues with the following pairs until the characters differ or until a terminating null-character is reached.
• 标准规定
第一个字符串大于第二个字符串,则返回大于0的数字;
第一个字符串等于第二个字符串,则返回0;
第一个字符串小于第二个字符串,则返回小于0的数字。
模拟实现strcmp
#include<stdio.h>
#include<assert.h>
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[] = "abcdef";
char arr2[] = "abc";
int ret = my_strcmp(arr1, arr2);
printf("%d\n", ret);
return 0;
}
strncpy
函数原型:char* strncpy ( char * destination , const char* source , size_t num ) ;
• Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
• 拷贝num个字符从源字符串到目标空间。
• 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
简单使用:
长度不够自动追加0.
模拟实现strncpy
#include<stdio.h>
#include<assert.h>
char* my_strncpy(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*src)
{
*dest++ = *src++;
}
*dest = '\0';
return ret;
}
int main()
{
char arr1[] = "abcdef";
char arr2[20] ="xxxxxxxxxxx";
my_strncpy(arr2, arr1,8);
printf("%s\n", arr2);
return 0;
}
strncat
函数原型:char* strncat ( char * destination , const chra* source , size_t num ) ;
• Appends the first num characters of source to destination , plus a terminating null-character.
• If the length of the C string in source is less than num , only the content up to the terminating null-character is copied.
简单使用:
从源字符串的第一个\0开始 追加n个字符,追加完后添加\0。
模拟实现strncat
#include<stdio.h>
#include<assert.h>
char* my_strncat(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*dest)
{
dest++;
}
while (*src)
{
*dest++ = *src++;
}
*dest = '\0';
return ret;
}
int main()
{
char arr1[20] = "hello \0xxxxxxxxx";
char arr2[] = "abcdef";
my_strncat(arr1, arr2, 4);
printf("%s\n", arr1);
return 0;
}
strncmp
函数与原型:int strncmp ( const char* str1 , const char* str2 ,size_t num ) ;
• 比较到出现有一个字符不一样或者其中一个字符串结束或者num个字符全部比较完。
简单使用:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "bed";
int ret = strncmp(arr1, arr2, 2);
printf("%d\n", ret);
return 0;
}
模拟实现strncmp
#include<stdio.h>
#include<assert.h>
int my_strncmp(const char* str1, const char* str2, size_t num)
{
assert(str1 && str2);
while (num)
{
if (*str1 == *str2)
{
str1++;
str2++;
}
else
{
return *str1 - *str2;
}
}
return 1;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "bed";
int ret = my_strncmp(arr1, arr2, 2);
printf("%d\n", ret);
return 0;
}
strstr
函数原型:char* strstr ( const char * str1 , const char * str2 ) ;
• Returns a pointer to the first occurrence of str2 in str1 ,or a null pointer if str2 is not part of str1;
使用示例:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "bcd";
char* p = strstr(arr1, arr2);
if (p == NULL)
printf("没找到\n");
else
printf("%s\n", p);
return 0;
}
模拟strstr
#include<stdio.h>
#include<assert.h>
char* my_strstr(const char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
char* beg = src;
while (*ret)
{
dest = ret;
src = beg;
while (*dest && *src &&(*dest == *src))
{
dest++;
src++;
}
if (*src == '\0')
return ret;
ret++;
}
return NULL;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "bcd";
char* p = my_strstr(arr1, arr2);
if (p == NULL)
printf("没找到\n");
else
printf("%s\n", p);
return 0;
}
strtok
函数原型:char * strtok ( char* str,const char * sep ) ;
• sep参数是个字符串,定义了用作分隔符的字符集合;
• 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
• strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改)
• strtok函数的第一个参数不为NULL,函数将找到str中的第一个标记,strtok将保存它在字符串中的位置。
• strtok函数的第一个参数为NULL。函数将在同一个字符串中被保存的位置开始,查找下一个标记。
• 如果字符串不存在更多的标记,则返回NULL指针。
示例:
strerror
函数原型:char * strerror ( int errnum ) ;
返回错误码所对应的错误信息。
#include<stdio.h>
#include<string.h>
int main()
{
FILE* pf = fopen("unexist.ent", "r");
if (pf == NULL)
{
printf("Error opening file unexist.ent:%s\n", strerror(errno));
return 0;
}
//....
return 0;
}
字符分类函数: