C语言的字符串函数|C语言的字符串函数,内存函数笔记详解
目录
- strlen
- strlen模拟实现
- strcpy
- strcpy的模拟实现
- strcat
- strcat的模拟实现
- strcmp
- strcmp模拟实现
- strstr
- strstr模拟实现
- strncpy
- strncat
- strncmp
- strtok
- memcpy
- memcpy模拟实现
- memmove
- memmove模拟实现
- memcmp
- 字符分类函数
- 字符串换函数
- 总结
strlen 此函数接收一个char*类型参数,返回字符串\0前字符数,注意返回类型是size_t型的
//关于strlen返回值的一个易错点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模拟实现
法一
使用计数器
size_t my_strlen1(const char* str){ assert(str); int count = 0; while (*str++) {count++; } return count; }
法二
指针相减
size_t my_strlen2(const char* str){ assert(str); char* start = str; while (*str!='\0')//注意这种写法不能写*str++; 这里要先判断再++;*str++的写法在'\0'的地方也+1了 {str++; } return str - start; //\0与起始位置的差就是字符数}
法三
递归,不适用临时变量
size_t my_strlen3(const char* str){ if ('\0' == *str)return 0; elsereturn 1 + my_strlen3(str + 1); }
strcpy 此函数接收两个char*类型参数,把后一个字符串拷贝到前一个字符串中,包括\0,注意前一个指针指向的数组空间要足够大,被拷贝的内容必须包含\0
strcpy的模拟实现
char* my_strcpy(char* dest, const char* src){ assert(dest && src); char* ret = dest; while (*dest++ = *src++) {; } return ret; }int main(){ char arr1[20] = "hello underworld"; //注意写成数组 char arr2[20] = "hello world"; printf("%s\n", arr2); printf("%s\n", my_strcpy(arr2, arr1)); return 0; }
strcat 此函数接收两个char*参数,在前一个字符串\0的位置开始拷贝后一个字符串,直到后一个字符串的\0,返回前一个字符串首地址。注意要保证前一个指针指向的空间足够大
strcat的模拟实现
char* my_strcat(char* dest, const char* src){ char* ret = dest; assert(dest && src); while (*dest)//让dest到达str1的\0位置 {dest++; } while (*dest++ = *src++)//这一部分和strcpy同 {; } return ret; }int main(){ char arr1[20] = "hello "; char arr2[20] = "underworld"; printf("%s\n", my_strcat(arr1, arr2)); return 0; }
strcmp 接收两个char*参数,依次比较每个字符,在第一个不相等的字符处比较他们的编码值,前者大则返回一个大于0的数,前者小则返回一个小于0的数,字符串完全相等则返回0
strcmp模拟实现
int my_strcmp(const char* str1, const char* str2){ while (*str1 == *str2) {if (*str1 == '\0')//说明两个字符串同时到达结束标记return 0; str1++; str2++; } return *str1 - *str2; //如果不是在循环内部返回,就一定不相等,而字符相减可以反映大小}int main(){ char *str1 = "hello world"; char *str2 = "hello underworld"; printf("%d\n", my_strcmp(str1, str2)); //w比u大 return 0; }
strstr 接收两个char*参数,返回第二个字符串在第一个字符串第一次出现的首位置指针
strstr模拟实现
char* my_strstr(const char* str1, const char* str2){ assert(str1 && str2); char* s1; //s1维护str1 char* s2; //s2维护str2 char* cp = str1; //cp用来记录比较开始的位置 if (*str2 == '\0')//特殊情况return str1; while (*cp) {s1 = cp; s2 = str2; while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)//其实*s1='\0'且*s2!='\0'时已经没有比较下去的必要了//*s1==*s2就让两个维护指针分别+1;不等就让cp+1,s1和s2分别重置{s1++; s2++; }if (*s2 == '\0')//*s2=='\0'说明找到了{return cp; }cp++; } return NULL; }
应用KMP算法的strstr
void get_next(char* str, int* next){ int i, k; i = 0; k = -1; next[0] = -1; //这个值没用;或者说是为了使i增加而j不增加 int len = strlen(str); while (i < len - 1)//next数组最大下标是字符串长度减1,数组长度和字符串长度相同 {if (k == -1 || *(str + i) == *(str + k)){++i; ++k; next[i] = k; }elsek = next[k]; } //测试打印next int z; printf("next:"); for (z = 0; z < len; z++) {printf("%d ", next[z]); } printf("\n"); }int Index_KMP(char* str1, char* str2, int pos){ int i = pos; int j = 0; int next[255]; get_next(str2, next); int len1 = strlen(str1); int len2 = strlen(str2); int count = 0; while (i < len1 && j < len2)//i从0到10(len1=11),共11次,但是考虑到走else的回溯,单字符查找一共循环22次 {count++; if (j == -1 || *(str1 + i) == *(str2 + j))//先判断,再把下标加1{++i; ++j; }else{j = next[j]; } } printf("i=%d\n", i); printf("j=%d\n", j); printf("count=%d\n", count); //是存在回溯的,那么这个函数的时间复杂度还是O(m)吗? //if ((len2!=1) && (j >=(len2-1)))//有缺陷,对于len2=1的情况无法处理 if (j >= (len2 - 1))//单字符查找情形,while结束时j=0,而len2-1也=0,故不能作为找到了的标志//对于单字符查找以外的情形,len2-1一定大于0,len2-1代表的就是目标串最后一个字符的下标,既然j//到达了这个位置,就说明完全匹配了return i - len2; //由于字符串长度与数组下标的差异造成len2=1时 elsereturn 0; }int main(){ char* str1 = "hello underworld!"; char* str2 = "under"; printf("%s\n", my_strstr(str1, str2)); printf("%s\n", *(str1+Index_KMP(str1, str2, 0))); return 0; }
strncpy 比strcpy多一个参数,描述拷贝的字节数,如果多于str2的长度,则会补0
int main(){ char arr1[20] = "abcdefghi"; char arr2[] = "xxxx"; //strncpy(arr1, arr2, 6); //从arr2拷贝6个字符给arr1?如果arr2长度不够,则补0 //strncpy(arr1, arr2, 3); //长度不够不拷贝\0 //strncpy(arr1, arr2, 4); strncpy(arr1, arr2, 5); printf("%s\n", arr1); return 0; }
strncat 比strcat多一个参数,最多只拷贝完整的str2(包括\0)
int main(){ char arr1[20] = "abc\0xxxxxxx"; char arr2[] = "def"; //strncat(arr1, arr2, 6); //在arr1后面接上arr2的六个字符?最多只接arr2这么长的字符串,包括\0 //strncat(arr1, arr2, 3); //自己会加上\0 strncat(arr1, arr2, 2); printf("%s\n", arr1); return 0; }
strncmp 比strcmp多一个参数,描述比较的字节数
int main(){ char arr1[] = "abcdew"; char arr2[] = "abcdeqj"; printf("%d\n",strncmp(arr1, arr2, 5)); printf("%d\n",strncmp(arr1, arr2, 6)); return 0; }
strtok 字符串分割函数,接收两个char*参数,第一个是要被分割的字符串,第二个是分割符,分割符顺序不重要;第一个参数不为NULL时,返回分割的第一段;第一个参数为NULL,将从上个位置开始查找下一段
int main(){ char arr1[] = "cjh@scu.edu"; char arr2[100] = { 0 }; //保存临时数据 char sep[] = "@."; char* ret = NULL; //接收strtok的返回值 strcpy(arr2, arr1); for (ret = strtok(arr2, sep); ret != NULL; ret = strtok(NULL, sep)) {printf("%s\n", ret); } return 0; }
int main(){ char str[] = "- This, a sample string."; char* pch; printf("Splitting string \"%s\" into tokens:\n", str); pch = strtok(str, ", .-"); //分隔标记的位置不重要 while (pch != NULL) {printf("%s\n", pch); pch = strtok(NULL, " ,.-"); //注意这里有空格 } return 0; }
memcpy 接收三个参数,第一个是char的目标位置,第二个是被拷贝的char的数据源,最后一个是size_t的拷贝字节数。注意标准未定义把自己的内容拷贝被自己的结果。
memcpy模拟实现
void* my_memcpy(void* dest, void* src, size_t count){ void* ret = dest; assert(dest && src); while (count--) {*(char*)dest = *(char*)src; dest = (char*)dest + 1; src = https://www.it610.com/article/(char*)src + 1; } //printf("%d\n", count); //count=-1 return ret; }int main(){ int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 }; int arr2[20] = { 0 }; my_memcpy(arr2, arr1, 10 * sizeof(int)); int i; for (i = 0; i < 20; i++) {printf("%d ", arr2[i]); } return 0;
memmove 此函数原型和memcpy一样,包含额memcpy的功能,且可以处理把自己的内容拷贝给自己的情景
#include #include int main(){ char str[] = "memmove can be very useful......"; printf("%c\n", *(str + 15)); printf("%c\n", *(str + 20)); memmove(str + 20, str + 15, 11); //注意memmove和memcpy不会遇到\0停下来,什么时候停取决于第三个参数 puts(str); return 0; }
memmove模拟实现
void* my_memmove(void* dest, void* src, size_t count)//关键在于拷贝之前先判断是否会出现overlap{ void* ret = dest; if (dest <= src || (char*)dest >= ((char*)src + count)) {while (count--){*(char*)dest = *(char*)src; dest = (char*)dest + 1; src = https://www.it610.com/article/(char*)src + 1; } } else {dest = (char*)dest + count - 1; src = (char*)src + count - 1; while (count--){*(char*)dest = *(char*)src; dest = (char*)dest - 1; src = (char*)src - 1; } } return ret; }int main(){ int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; my_memmove(arr + 2, arr, 4 * sizeof(int)); //1 2 1 2 3 4 7 8 9 10 //my_memcpy(arr + 2, arr, 4 * sizeof(int)); //1 2 1 2 1 2 7 8 9 10 int i; for (i = 0; i < 10; i++) {printf("%d ", arr[i]); } return 0; }
memcmp 接收三个参数,前两个是void*型,指向被比较的两块内容,最后一个size_t的参数表示要比较多少字节
#include #include int main(){ char buffer1[] = "DWgaOtP12df0"; char buffer2[] = "DWGAOTP12DF0"; int n; n = memcmp(buffer1, buffer2, sizeof(buffer1)); if (n > 0) printf("'%s' is greater than '%s'.\n", buffer1, buffer2); else if (n < 0) printf("'%s' is less than '%s'.\n", buffer1, buffer2); else printf("'%s' is the same as '%s'.\n", buffer1, buffer2); return 0; }
字符分类函数 【C语言的字符串函数|C语言的字符串函数,内存函数笔记详解】函数 如果他的参数符合下列条件就返回真
- iscntrl 任何控制字符
- isspace 空白字符:空格‘ ',换页‘\f',换行'\n',回车‘\r',制表符'\t'或者垂直制表符'\v'
- isdigit 十进制数字 0~9
- isxdigit 十六进制数字,包括所有十进制数字,小写字母af,大写字母AF
- islower 小写字母a~z
- isupper 大写字母A~Z
- isalpha 字母az或AZ
- isalnum 字母或者数字,az,AZ,0~9
- ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
- isgraph 任何图形字符
- isprint 任何可打印字符,包括图形字符和空白字符
字符串换函数
- tolower()
- toupper()
#include int main (){int i=0; char str[]="Test String.\n"; char c; while (str[i]) {c=str[i]; if (isupper(c)) c=tolower(c); putchar (c); i++; }return 0; }
总结 本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量