苦难是花开的伏笔,冬天在为春天作序。
目录
后记:●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教! ——By 作者:新晓·故知
本章重点
重点介绍处理字符和字符串的库函数的使用和注意事项
★求字符串长度 strlen
★长度不受限制的字符串函数 strcpy strcat strcmp
★长度受限制的字符串函数介绍 strncpy strncat strncmp
★字符串查找 strstr strtok
★错误信息报告 strerror
★字符操作
★内存操作函数 memcpy memmove memset memcmp
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在 常量字符串中或者 字符数组 中。 字符串常量 适用于那些对它不做修改的字符串函数.
1. 函数介绍
1.1 strlen
size_t strlen ( const char * str );
◆字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包 含 '\0' )。
◆参数指向的字符串必须要以 '\0' 结束。
◆注意函数的返回值为size_t,是无符号的( 易错 )
◆学会strlen函数的模拟实现
注:
#include <stdio.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; }
模拟实现strlen的三种方法:
1. 计数器的方法
2. 递归的方法
3. 指针-指针
#include <stdio.h> #include <string.h> #include <assert.h> int my_strlen(const char* str) { //使用my_strlen实现strlen,而传过去的是字符串中首字符的首地址 //const保护str不被修改,只单纯用于计算其字符大小 //遍历字符串时要通过str指针,为了保护指针有效性,使用assert,其头文件为#include <assert.h> assert(str); int count = 0; while (*str) //while(*str!='\0') { count++; str++; } return count; } int main() { int len = my_strlen("abcdef"); printf("%d\n", len); return 0; }
编辑编辑
编辑
size_t是专门为sizeof的返回值设计的,sizeof返回的类型是size_t,而size_t本质上是unsighted int.
而以上程序返回类型写成了int,产生差异。但各有各的好处,因为库里面的strlen是求字符串长度,其返回数值不会是负数,而unsighted int只能表示正数,不会表示负数,所以strlen的返回类型写成size_t。编辑
但也有其不顺手的地方,例如分析以下程序:
编辑
编辑 因为strlen返回的是无符号数3和6,而两个无符号数相减,3-6的结果是无符号数,将-3当成无符号数处理,将会是一个很大的正数,因此大于0,这样就会引起Bug。
将strlen的返回值设计成int类型,这种问题就不会存在。
strlen返回值的类型写成size_t(unsigned int)或int 都可以,根据具体使用情况:
如果要实现输出“<=”,可以强制转换类型:
编辑
优化代码:编辑
编辑
编辑 据资料:最初C语言包含了头文件,后来库函数和头文件分离,使用库函数就使用对应的头文件。相当于有两套头文件。最初的头文件在某些地方产生Bug,使得后来库函数和头文件分离。
1.2 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' 拷贝到目标空间。
◆目标空间必须足够大,以确保能存放源字符串。
◆目标空间必须可变。
◆学会模拟实现。
编辑
编辑
编辑
编辑
模拟实现strcpy:
编辑
编辑
编辑
编辑
编辑
注:
1.模拟实现就要像库函数,对应的参数、参数类型、参数个数等要对应。否则就是自定义函数,那不是模拟实现!
2.不为空的指针无法知道其是否为野指针!编辑
c语言要求变量必须创建在代码块的前面!
链式访问是将一个函数的返回值作为另外一个函数的参数!
尽量不要返回的是局部变量的地址!
编辑
编辑
编辑
#include <assert.h> char* my_strcpy(char* dest, const char* src) { char* ret = dest; //为了保护指针有效性,使用assert,其头文件为#include <assert.h> assert(dest && src); while (*dest++ = *src++) { ; } return ret; } int main() { //char arr1[] = "abcdef"; //char arr1[] = {'a', 'b', 'c', 'd', 'e', 'f'}; char arr1[] = {'a', 'b', 'c', 'd', 'e', 'f', '\0'}; char arr2[20] = "xxxxxxxxxxxx"; //const char* p = "xxxxxxxxxx"; my_strcpy(arr2, arr1); printf("%s\n", arr2); return 0; }
1.3 strcat
char * strcat ( char * destination, 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:
编辑
编辑
编辑编辑
编辑
编辑
编辑
编辑编辑
_ _cdel是函数调用约定,即函数的传值方式等!
#include <assert.h> char* my_strcat(char* dest, const char* src) { char* ret = dest; assert(dest && src); //1. 目标空间中的\0 while (*dest) { dest++; } //2. 追加内容到目标空间 while (*dest++ = *src++) { ; } return ret; } int main() { char arr1[30] = "hello"; char arr2[] = "world";// {'w', 'o', 'r', 'l', 'd', '\0'}; printf("%s\n", my_strcat(arr1, arr2)); return 0; }
1.4 strcmp
int strcmp ( const char * str1, const char * str2 );
◆This function starts comparing the first character of each string. If they are equal 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:
编辑
编辑
只是在VS编译环境下,将-1、0、1作为比较的结果评判,但在其他编译环境下可能返回的是-100(但满足库函数定义<0、=0、>0),因此以下代码错误:
编辑
编辑
编辑 两个常量字符串,他们的地址是相同的!但非常量字符串其地址不同!
1.5 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个
编辑
编辑
编辑
1.6 strncat
char * strncat ( char * destination, const char * 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. 编辑
编辑编辑
/* strncat example */ #include <stdio.h> #include <string.h> int main() { char str1[20]; char str2[20]; strcpy(str1, "To be "); strcpy(str2, "or not to be"); strncat(str1, str2, 6); puts(str1); return 0; }
1.7 strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
编辑
编辑
比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完
/* strncmp example */ #include <stdio.h> #include <string.h> int main() { char str[][5] = { "R2D2" , "C3PO" , "R2A6" }; int n; puts("Looking for R2 astromech droids..."); for (n = 0; n < 3; n++) if (strncmp(str[n], "R2xx", 2) == 0) { printf("found %s\n", str[n]); } return 0; }
1.8 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.
/* strstr example */ #include <stdio.h> #include <string.h> int main() { char str[] = "This is a simple string"; char* pch; pch = strstr(str, "simple"); strncpy(pch, "sample", 6); puts(str); return 0; }
编辑编辑
编辑
模拟实现strstr:
编辑
编辑
//strstr //char* strstr(const char* string, // const char* strCharSet); // //abcdefabcdef //bcdq #include <string.h> #include <assert.h> char* my_strstr(const char* str, const char* substr) { const char* s1 = str; const char* s2 = substr; const char* cur = str; assert(str && substr); if (*substr == '\0') { return (char*)str; } while (*cur) { s1 = cur; s2 = substr; while (*s1 && *s2 && *s1 == *s2) { s1++; s2++; } if (*s2 == '\0') return (char*)cur; cur++; } return NULL; } int main() { char arr1[] = "abbbcdef"; char arr2[] = "bbc"; char* ret = my_strstr(arr1, arr2); if (NULL == ret) printf("没找到\n"); else printf("%s\n", ret); return 0; }