本章重点介绍字符和字符串的库函数使用,C语言本身是没有字符串类型的,字符串通常存放在常量字符串或字符数组中。字符串常量适用于那些对它不做修改的字符串函数。
1.strlen:求字符串的长度(不包括 '\0' )
size_t strlen(const char * str);
>>字符串已经 '\0' 作为结束标识符,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )。
>>参数指向的字符串必须要以 '\0' 结束。
>>注意函数返回值是size_t 是无符号的(重点)。
>>学会模拟实现strlen.
程序如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char* str1 = "hello world"; char* str2 = "world"; if (strlen(str1) > strlen(str2)) printf("str1>str2\n"); else printf("str1<str2\n"); system("pause"); return 0; }
结果:str1字符要比str2字符多,所以if判断语句为真;
现在我们来模拟实现这个strlen这个函数:
方式1:
int My_strlen(const char* str) { assert(str); size_t count = 0; while (*str) { count++; str++; } return count; }
这个方法创建了一个count变量来计数大小;
2.strcpy:这个函数是拷贝字符串
char* strcpy(char* destination ,const char * source);
>>字符串必须以'\0'结束。
>>会将源字符串中的'\0'拷贝到目标空间。
>>目标空间必须足够大,以确保能存放源字符串。
>>目标空间必须可变。
>>学会模拟实现strcpy
模拟实现:
char* my_strcpy(char* dest, const char* str) { assert(dest); assert(str); char* ret = dest; while (*str) { *dest++ = *str; } *dest = *str; return ret; }
3.strcat:将source所指向的字符串追加到destination所指向的字符串后,简称:追加!
char* strcat(char* destination,const char* source);
>>源字符必须以'\0'结束。
>>目标空间必须足够大,能容纳下源字符串的内容。
>>目标空间必须可修改。
>>字符串自己给自己追加,如何?
模拟实现strcat:
char* my_strcat(char* dest, const char* str) { assert(dest); assert(str); char* ret = dest; while (*dest!='\0') { dest++; } while (*dest++ = *str++) { ; } return ret; }
//如果自己给自己追加,会陷入死循环,会报错!
4.strcmp:比较两个字符串是否相等,如果相等则返回0
int strcmp(const char* str1,const char* str2);
>>标准规定:
>>第一个字符串大于第二个字符串,则返回大于0的数字;
>>第一个字符串等于第二个字符串,则返回0;
>>第一个字符串小于第二个字符串,则返回小于0的数字;
>>那么如何判断两个字符串?
模拟实现strcmp:
int my_strcmp(char* str1, const char* str2) { assert(str1&&str2); while (*str1 == *str2) { if (*str1 == '\0') return 0;//相等 str1++; str2++; } return (*str1 - *str2); }
长度不受限制的字符串函数:strcpy、strcat、strcmp;
长度受限制的字符串函数(相对于安全一些):strncpy、strncat、strncmp;
5.strncpy:将source所指向的字符串中num个字符拷贝到destination所指向的字符串中
char* strncpy(char* destination,const char* source,size_t num);
>>拷贝num个字符从源字符串到目标空间;
>>如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,自到num个;
模拟实现strncpy:
char* my_strncpy(char* dest, const char* str, size_t num) { assert(dest && str); char* ret = dest; while (num && (*dest++ = *str++))//将src字符串中的num个字符拷贝到cp中 { num--; } while (num)//若num人大于0,则将cp中接下来的num个字符置为'\0' { *dest++ = '\0'; num--; } return ret; }
6.strncat:在destination所指向的字符串末尾加上num个source所指向的字符串的字符
char* strncat(char* destination,const char* source,size_t num);
模拟实现strncat:
char* my_strncat(char* str1, const char* str2, size_t num) { assert(str1 && str2); char* ret = str1; while (*str1)//cp遍历str1至'\0' { str1++; } while (num--)//将str2中num个字符拷贝到str1中,若num大于str2字符串长度,则将str1之后的一个字符置为'\0' { *str1++ = *str2++; if (*str2 == '\0') return ret; } *str1 = '\0'; return ret; }
7.strncmp:比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完
模拟实现strncmp:
int my_strncmp(const char* str1, const char* str2, size_t num) { assert(str1 && str2); while (*str1 == *str2 && num)//str1与str2相等或num不为0是进入循环 { str1++; str2++; num--; if (*str2 == '\0' || num == 0)//num等于0或str2与str1已比较完成说明二者相同,返回0 return 0; } if (*str1 > *str2) return 1; else return -1; }
8.strstr :判断str2是否在str1中出现,即str2是否为str1的子串,若是,则返回str2在str1中首次出现的字符地址,否则返回NULL
模拟实现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; }
9.strtok:切割字符串
char* strtok(char* str,const char* sep);
>>sep参数是个字符串,定义了用作分隔的字符集合;
>>第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔分割的标记。
>>strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改)
>>strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
>>strtok函数第一个参数为NULL;函数将在同一个字符串中被保存的位置开始,查找下一个标记。
>>如果字符串中不存在更多的标记,则返回NULL指针;
#include <stdio.h> #include <stdlib.h> #include<string.h> int main() { char str[] = "3414597751@qq.com"; char* sep = "@."; char tmp[30]; char* cp = NULL; strcpy(tmp, str);//将str拷贝一份到tmp中,避免strtok将str中的数据修改 for (cp = strtok(tmp, sep); cp; cp = strtok(NULL, sep)) { printf("%s\n", cp); } system("pause"); return 0; }
运行结果:
10.strerror:返回错误码所对应的错误信息
char* strerror(int errnum); 返回错误码,所对应的错误信息!
>> strerror函数的应用在判断一些操作的错误类型时能起到很好的效果,比如在程序未达到预期的效果时,可以通过strerror来判断错误的原因,比如:想打开text.txt文件时,没有达到预期效果,可以调用该函数来查找原因。
C语言的库函数,在执行失败的时候,都会设置错误码!
//0 1 2 3 4 5 6 7 8
#include <stdio.h> #include <stdlib.h> #include<string.h> int main() { printf("%s\n", strerror(0)); printf("%s\n", strerror(1)); printf("%s\n", strerror(2)); printf("%s\n", strerror(3)); system("pause"); return 0; }
运行结果:
看看strerror函数如何使用的:
#include <stdio.h> #include <stdlib.h> #include<string.h> int main() { FILE* pf = fopen("test.txt", "r"); if (pf == NULL) { printf("文件打开失败:%s\n", strerror(errno));//errno->是C语言设置的一个全局的错误码存放的变量 system("pause"); return 1; } system("pause"); return 0; }
运行结果:
11.memcpy:
void* memcpy(void* destination,const void*source,size_t num);
>>函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
>>这个函数在遇到'\0'的时候并不会停下来。
>>如果source和destination有任何的重叠,复制的结果都是未定义的。
模拟实现memcpy:
void* My_memcpy(void* dest, const void* str, size_t num) { assert(dest&&str); void* ret = dest; while (num--) { *(char*)dest = *(char*)str; dest = (char*)dest + 1; str = (char*)str + 1; } return ret; }
memcpy函数是不用来处理重叠的内存之间的数据拷贝的
使用memmove函数来实现,重叠内存之间的数据拷贝
12.memmove:
void* memmove(void* destination,const void* source,size_t num);
>>和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
>>如果源空间和目标空间出现重叠,就得使用memmove函数处理。
memmove的原理实现过程,如何做到不重叠的方式!
模拟实现memmove:
void* my_memmove(void* dest, const void*src, size_t num) { void* ret = dest; assert(dest && src); if (dest < src) { //前->后 while (num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } } else { //后->前 while (num--) { *((char*)dest + num) = *((char*)src + num); } } return ret; }
注意:memmove函数的模拟实现要小心指针所指向内容(数组)被覆盖的问题。
12.memcmp:
int memcmp(const void* ptr1,const void* ptr2,size_t num);
>>比较从ptr1和ptr2指针开始的num个字节
>>返回值如下:
12.memset:——memory set 内存设置
总结:
字符和字符串的库函数的模拟实现部分到此结束了,感谢您的阅读!!!如果这部内容对你有所帮助的话,记得給我(点赞、收藏、关注)谢谢!后续会持续更新!!!