目录
前言
一、求字符串长度
strlen
注意要点
strlen的模拟实现
二、长度不受限制的字符串函数
strcpy
注意要点
模拟实现
strcat
注意要点
模拟实现
strcmp
注意要点
模拟实现
三、长度受限制的字符串函数
strncpy
注意要点
模拟实现
strncat
注意要点
模拟实现
strncmp
注意要点
四、字符串查找
strstr
注意要点
模拟实现
strtok
注意要点
前言
在c语言的使用中,要经常对字符串和内存进行各种各样的操作,但是c语言并没有字符串类型,也不能直接对内存进行复杂操作。我们通常用常量字符串或者字符数组来存储并操作字符串,用指针来对内存空间进行操作。这时,就需要有一些函数,通过将指针传入而对字符串和内存进行各种操作。而字符串常量只适用于对它不做修改的字符串函数。下面就是一些可以对字符和内存进行较复杂操作的函数。
一、求字符串长度
strlen
size_t strlen ( const char * str );
相信大家对这个函数已经很熟悉了,现在主要对该函数的要点进行总结:
注意要点
1.字符串以’\0‘作为结束的标志,strlen函数返回的是在字符串中’\0‘前面出现的字符个数(不包含’、0‘)。
2.参数指向的字符串必须以’\0‘结束,否则会越界访问。
3.注意函数返回值时size_t,默认无符号数。
例如:
#include#includeint 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的模拟实现
strlen实现有三种方式:
1.计数器
size_t my_strlen(const char* str){int count = 0;while (*str){count++;str++;}return count;}
2.递归(不创建临时变量的计数器)
size_t my_strlen(const char* str){if (*str){return 1 + my_strlen(str + 1);}else{return 0;}}
3.指针-指针
size_t my_strlen(const char* str){char* tmp = str;while (*tmp){tmp++;}return tmp - str;}
二、长度不受限制的字符串函数
strcpy
char* strcpy ( char * destination , const char * source );
strcpy函数就是把source指针指向的字符串拷贝到destination指针指向的数组中,包括结束字符。
注意要点
1.源字符串必须以 ‘\0’ 结束。
2.会将源字符串中的 ‘\0’ 拷贝到目标空间。
3.目标空间必须足够大,以确保能存放源字符串。
4.目标空间必须可变,不能是常量或常变量。
5.返回值是目标空间起始地址。
例如:
#include#includeint main(){char arr1[10] = "abcdef";char arr2[3] = "ab";printf("%s",strcpy(arr1, arr2));return 0;}
函数执行前:
函数执行后:
原来的abc被ab\0覆盖掉了。
模拟实现
#includechar* my_strcpy(char* dest, const char* src){char* ret = dest;//先用指针临时存储,以便最后返回目的地址assert(dest && src);//断言,防止指针是空指针while (*dest++ = *src++)//巧妙的思路,根据操作符优先级依次解引用、赋值、判断、自增{;}return ret;}
strcat
char * strcat ( char * destination , const char * source );
将源字符串的副本追加到目标字符串。目标中的终止空字符被源字符串的第一个字符覆盖,并且在目标字符串中由两者串联形成的新字符串的末尾包含一个空字符。
注意要点
1.源字符串必须以 ‘\0’ 结束。
2.目标空间必须有足够的大,能容纳下源字符串的内容。
3.目标空间必须可修改。
4.字符串自己给自己追加,会出错。
前面三个不用多讲,但最后一个自己跟自己追加,会怎样呢?我们来试验一下:
通过调试,我们清楚地看到,在执行这个函数时发生了错误,而错误原因正是arr数组后面的’\0‘被覆盖掉了,函数没有办法结束,无限地在后面追加,陷入死循环。
模拟实现
#include#includechar* my_strcat(char* dest, const char* src){assert(dest && src);char* tmp = dest;while (*dest){dest++;}while (*dest++ = *src++){;}return tmp;}
strcmp
int strcmp ( const char * str1, const char * str2 );
将字符串str1与字符串str2进行比较。
注意要点
1.此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续以下对,直到字符不同或达到终止空字符。
2.此函数执行字符的二进制比较。
3.标准规定:
- 第一个字符串大于第二个字符串,则返回大于 0 的数字
- 第一个字符串等于第二个字符串,则返回0
- 第一个字符串小于第二个字符串,则返回小于0的数字
例如:
#include#includeint main(){char arr1[10] = "abcdef";char arr2[10] = "abcde";if (0 == strcmp(arr1, arr2)){printf("arr1=arr2");}else if (strcmp(arr1, arr2) > 0){printf("arr1>arr2");}else if (strcmp(arr1, arr2) < 0){printf("arr1
输出结果为arr1>arr2
模拟实现
#includeint my_strcmp(const char* p1,const char* p2){assert(p1 && p2);while (*p1 == *p2){if (*p1 == "\0")return 0;p1++;p2++;}return *p1 - *p2;}
三、长度受限制的字符串函数
strncpy
char * strncpy ( char * destination , const char * source , size_t num );
从字符串中复制字符
注意要点
1.将源字符串开头的num个字符复制到目标字符串。
2.如果在复制num个字符之前找到源字符串的末尾,则目标字符串将填充零,直到总共写入num个字符为止。
例如:
int main(){char arr1[10] = "abcdefghi";char arr2[12] = "hijklm";printf("%s",strncpy(arr1, arr2, 5));return 0;}
输出结果hijklfghi
模拟实现
#includechar* my_strncpy(char* dest,const char* str, size_t num){char* tmp = dest;assert(dest && str);while (num--){if (*str){*dest++ = *str++;}else{*dest++ = '\0';}}return tmp;}
记得如果给的个数过多需要’\0‘来凑
strncat
char * strncat ( char * destination, const char * source, size_t num );
为字符串追加字符
注意要点
1.将源字符串的开头的num个字符追加到目标字符串,外加一个终止空字符。
2.如果源字符串中字符串的长度小于num,则仅追加终止空字符之前的内容。
3.长度限制,可以自己跟自己追加。
例如:
int main(){char arr[20] = "abcdefghi";printf("%s", strncat(arr, arr, 9));return 0;}
结果是两个重复的abcdefghi
模拟实现
#includechar* my_strncat(char* dest, const char* src, size_t n){ assert(dest); assert(src); char* ret = dest; while (*dest) { dest++; } while (n--) { *dest++ = *src++; } *dest = '\0'; return ret;}
strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
比较两个字符串的字符
注意要点
1.此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续比较,直到字符不同,或达到终止的空字符,或者直到两个字符串中的num字符匹配。
2.
例如:
#include #include 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;}
四、字符串查找
strstr
char * strstr ( const char * str1 , const char * str2 );
注意要点
1.返回str2在str1中第一次出现的位置,如果没有,返回NULL。
2.以’\0‘作为结束标志。
例如:
int main(){char arr1[20] = "abbbcdefbbc";char arr2[10] = "bbc";if (strstr(arr1, arr2)){printf("%s\n", strstr(arr1, arr2));}else{printf("没找到\n");}return 0;}
结果是从bbc开始向后打印。
模拟实现
char* my_strstr(const char* dest, const char* str){char* cp = (char*)dest;//把一个安全的指针交给一个不太安全的指针,权限放大,有警告,因此强制类型转换char* s1, * s2;while (*cp){s1 = cp;//以cp作为标记,在匹配失败后能重新返回到这个点s2 = (char*)str;while (*s1 == *s2 && *s1 && *s2){s1++;s2++;}if (*s2 == '\0'){return cp;}cp++;}return NULL;}
strtok
char * strtok ( char * str , const char * sep );
注意要点
1.sep参数是个字符串,定义了用作分隔符的字符集合
2.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
3. strtok 函数找到 str 中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注 strtok 函数会改变被操作的字符串,所以在使用 strtok 函数切分的字符串一般都是临时拷贝的内容 并且可修改。) 4. strtok 函数的第一个参数不为 NULL ,函数将找到 str 中第一个标记, strtok 函数将保存它在字符串 中的位置。 5. strtok 函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标 记。 6. 如果字符串中不存在更多的标记,则返回 NULL 指针。 什么意思呢?其实就是把一个字符串的有分隔符的地方改成’\0‘,但是每次使用只能改一个,并返回此处的指针。下次使用会继续改后面的。直到最后返回空指针。 例如:
#include #includeint main(){char* p = "jichengdianlupian@163.com";const char* sep = ".@";char arr[30];char* str = NULL;strcpy(arr, p);//将数据拷贝一份,处理arr数组的内容for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep)){printf("%s\n", str);}}
To Be Continued...