文章目录
一、字符串操作函数
在C语言程序库中为我们提供了多个字符串操作函数,这些函数的原型包含在
string.h
头文件中。其中最常用的有:strlen() 、strcat()、strcmp()、strcpy()、等。
长度受限制的字符串操作函数
1、strlen()函数说明与模拟实现
函数原型:
size_t strlen( const char *string );
功能:
strlen( )函数用于统计字符串的长度,
‘\0’
作为结束标志,返回值返回的是字符串中的长度(返回的长度不包括
‘\0’
)
例:
char str1[]="hello";
char str2[5]={'h','e','l','l','o'};
printf("str1 = %d\n", strlen(str1));
printf("str2 = %d\n", strlen(str2));
由运行结果可知:str1的字符串长度为5,str2的长度不是5,而是21(随机值),对结果进行分析:
str1
在内存中的存储方式,strlen()函数读取到
‘\0’
时读取结束,返回值为
‘\0’
前面出现的字符个数(不包含
‘\0’
)。
str2
在内存中存放的方式,strlen()函数读取的是
‘\0’
之前的字符个数,所以当读取到最后一个字符 o 时并不会停止,而是会继续向后读取,直至遇到
‘\0’
为止;str2最后一个字符 ’o‘与 **’\0’**之间的个数是不确定的,所以字符串str2的长度是一个大于5的随机值;
strlen()函数的模拟实现
方法一:计数方式
size_t my_strlen(const char *string)
{
assert(string);
size_t count = 0;
while (*string++)
count++;
return count;
}
方法二:尾指针 — 头指针
size_t my_strlen(const char * string)
{
assert(string);
const char* start = string;//将字符串首地址赋值给start
while (*string) //当指针指向 '\0' 结束循环,此时指针指向的'\0'的首地址
string++;
return string - start;
}
示意图:
方法三:递归的方式实现
size_t my_strlen(const char * string)
{
assert(string);
if (!*string) //当字符串指向 '\0' 时,返回0
return 0;
else
return 1 + my_strlen(string + 1); //当字符串指向不为 '\0' 时,调用函数自身,实现递归调用
}
2、strcpy()函数说明与模拟实现
函数原型:
char *strcpy( char *strDestination, const char *strSource );
功能:
strcpy()将strSource为首地址的字符串拷贝到以strDestination为首地址的字符串中(包括
‘\0’
),并返回strDestination的地址。
使用案例:
int main()
{
char str1[]="hello china!";
char str2[100]={0};
strcpy(str2,str1);
printf("%s\n",str2); //打印的结果为 hello china!
return 0;
}
注:
1、在赋值和追加字符串时不会进行溢出检查,源字符串必须有明确的结束标志位
‘\0’
,在拷贝过程中结束标志位不可被修改;
2、拷贝过程中遇到
‘\0’
拷贝过程结束,连同 **’\0’**一同拷贝到目标字符串中;
3、目标字符串空间必须足够大且能够改变,以确保能够装下源字符串;
strcpy()函数的模拟实现
char* my_strcpy(char *dest, char * src)
{
assert(dest && src);
char* ret =dest;
while (*dest++ = *src++) //先将*src中的内容给*dest,再进行dest++,src++,
; //直至*src = '\0'时退出循环
return ret;
}
3、strcat()函数说明与模拟实现
函数原型:(用于拼接字符串)
char *strcat( char *strDestination, const char *strSource );
功能:
strcat()将strSource为首地址的字符串追加到以strDestination为首地址的字符串之后(包括
‘\0’
,strSource字符串保持不变),返回strDestination的地址。
使用案例:
int main()
{
char str1[20] = "hello ";
char * str2 = "china!";
my_strcat(str1,str2);
printf("%s\n",str1); //输出结果为 hello china!
return 0;
}
注:
1、源字符串一定要有结束标志
‘\0’
;
2、目标空间必须能够改变且足够大。
3、不能对字符串自身进行追加,结果是不可预知的(结束标志位
‘\0’
被覆盖);
strcat()函数的模拟实现
char* my_strcat(char *dest,const char * src)
{
assert(dest && src); //对参数进行断言,判断指针是否为NULL
char* ret = dest;
while (*dest) //定位dest字符串的结束位
dest++;
while (*dest++ = *src++) //将src字符串的值赋值给dest;
;
return ret;
}
4、strcmp( )函数说明与模拟实现
函数原型:(用于比较两个字符串的ASCII值的大小)
int strcmp( const char *string1, const char *string2 );
功能:
strcmp()比较string1 与string2两个字符串的大小,比较的是字符的ASCII,当:
string1
>
string2, 返回值
>0
;
string1
=
string2, 返回值
=0
;
string1
<
string2, 返回值
<0
;
使用案例:
int main()
{
char* str1 = "abcdef";
char* str2 = "abce";
char* str3 = "abce";
printf("%d\n",strcmp(str1,str2)); //str1 < str2 返回值 --> -1
printf("%d\n", strcmp(str2, str1)); //str1 > str2 返回值 --> 1
printf("%d\n", strcmp(str3, str2)); //str3 = str2 返回值 --> 0
return 0;
}
strcmp()函数的模拟实现
int my_strcmp(const char * str1,const char * str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (!*str1)
return 0;
str1++;
str2++;
}
return *str1 - *str2;
}
长度受限制的字符串操作函数
常用的长度受限制的字符串操作函数有:
- char *strncat(char *dest, const char *src, size_t n)
- char *strncpy(char *dest, const char *src, size_t n)
- int strncmp(const char *str1, const char *str2, size_t n)
以strncat()函数为例
strcat()函数无法检查第1个数组是否能容纳第2个字符串,如果分配给第1个数组的空间不够大,多出来的字符溢出到相邻的存储单元,就会出现不可预知的问题,要保证拼接后的字符串长度加1才有空间存放末尾的空字符;
strncat()函数的第三个参数指定了最大添加字符的个数,这样在一定程度避免了数组非法访问的问题;
char *strncat(char *dest, const char *src, size_t n)
参数说明:
- dest – 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串,包括额外的空字符。
- src – 要追加的字符串。
-
n – 要追加的最大字符数,如果src的字符数大于n,那么该函数只将src的前n个字符附加在dest末尾,如果src中的字符数小于n,该字符会将str2的所有字符附加在dest末尾。无论哪种情况,都会在新字符串的末尾添加空字符。必须为dest分配足够的空间以存储新的字符串。strncat()函数返回指向dest的指针
使用案例:
int main()
{
char dest[50], src[50];
strcpy(dest,"hello china!");
strcpy(src,"hello world!");
strncat(dest,src,strlen(src));
printf("%s\n",dest);
return 0;
}
字符串查找函数
strstr()
函数原型:(用于比较两个字符串的ASCII值的大小)
char *strstr( const char *str1, const char *str2);
功能:
在字符串 str1中查找第一次出现字符串 str2 的位置,不包含终止符 ‘\0’,如果str2是str1 的子串,则该函数返回str2在str1 中首次出现的地址;否则,返回NULL
使用案例:
int main()
{
char str1[] = "hello china!";
char* str2 = "china1";
char* result = strstr(str1,str2);
if (result)
printf("%s\n", result);
else
printf("not find!");
return 0;
}
strstr()函数的模拟实现
char* my_strstr(const char * str1,const char* str2)
{
assert(str1 && str2);
if (!*str2)
return (char *)str1;
const char* cp = str1;
while (*cp)
{
const char* p1 = cp;
const char* p2 = str2;
while ((*p1) && (*p2) &&(*p1 == *p2))
{
p1++;
p2++;
}
if (!*p2)
return (char *)cp;
cp++;
}
return NULL;
}
字符串分割函数
strtok()
函数原型:(字符串分割函数)
char *strtok(char *str, const char *delim);
功能:
strtok()用来将字符串分割成一个个片段。参数str指向欲分割的字符串,参数delim 则为分割字符串,当strtok()在参数str 的字符串中发现到参数delim 的分割字符时则会将该字符改为\0 字符。在第一次调用时,strtok()必需给予参数s 字符串,往后的调用则将参数s 设置成NULL。每次调用成功则返回下一个分割后的字符串指针。
返回值:返回下一个分割后的字符串指针,如果已无从分割则返回NULL
使用案例:
//方式一:
int main()
{
char str[] = "hello@china.123.world@456";
printf("%s\n", strtok(str, "@.")); //在第一次调用时,要给定分割字符串
printf("%s\n", strtok(NULL, "@.")); //在后面的调用中参数str设置为NULL
printf("%s\n", strtok(NULL, "@."));
printf("%s\n", strtok(NULL, "@."));
printf("%s\n", strtok(NULL, "@."));
printf("%s\n", strtok(NULL, "@."));
return 0;
//输出结果为
//hello
//china
//123
//world
//456
//null
}
//方式二:在上面的方法中,有多少个分割的字符,就需要多少个printf(),代码很多,也需要自己计算,很不方便
int main()
{
char str[] = "hello@china.123.world@456";
char* p;
printf("%s\n", strtok(str, "@."));
while (p = strtok(NULL, "@."))
printf("%s\n", p);
return 0;
}
//方式三:
```C
int main()
{
char str[] = "hello@china.123.world@456";
char* p;
char* delim = "@.";
for (p = strtok(str, delim); p; p = strtok(NULL, delim))
printf("%s\n",p);
return 0;
}
错误报告errno、perror() 和 strerror()
C 语言不提供对错误处理的直接支持,但是作为一种系统编程语言,它以返回值的形式允许您访问底层数据。在发生错误时,大多数的 C 或 UNIX 函数调用返回 1 或 NULL,同时会设置一个错误代码 errno,该错误代码是全局变量,表示在函数调用期间发生了错误。可以在 errno.h 头文件中找到各种各样的错误代码。
-
void perror( const char *string ); 函数显示传给它的字符串,首先打印string,然后是一个冒号,然后是产生错误的最后一个库调用的系统错误消息,最后是一个换行字符。如果string是空指针或指向空字符串的指针,perror只打印系统错误消息。
-
char *strerror( int errnum ); 函数,函数将errnum映射到错误消息字符串,并返回指向该字符串的指针,指针指向当前 errno 值的文本表示形式,strerror不会打印消息所以需要调用一个输出函数,比如printf:
使用案例:(两种情况打印结果相同)
int main()
{
FILE* fp = fopen("test.txt","r");
if (fp == NULL)
printf("the error message is:%s\n",strerror(errno));
perror("the error message is");
return 0;
}