C语言进阶--字符串+内存函数
求字符串长度strlen()
长度不受限制的字符串函数strcpy()、strcat()、strcmp()
长度受限制的字符串函数strncpy()、strncat()、strncmp()
字符串查找函数strstr()、strtok()
错误信息报告strerror()
字符操作
内存操作函数memcpy()、memmove()、memset()、mencmp()
strlen()
size_t strlen(const char* str);
字符串将’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数(不包括’\0’).
参数指向的字符串必须要以’\0’结束。
注意函数的返回值是size_t,是无符号的(易错)。
#include <stdio.h>
#include <string.h>int main()
{char arr[] = {"abcdef"}; //abcdef\0int len = strlen(arr);printf("%d\n", len); //6return 0;
}
#include <stdio.h>
#include <string.h>int main()
{char arr[] = {'b', 'i', 't'}; //[][][][][][][b][i][t][][][][]int len = strlen(arr); printf("%d\n", len); //随机值return 0;
}
#include <stdio.h>
#include <string.h>int main()
{//if (strlen("abc") - strlen("abcdef") > 0) //size_t。error,>if (strlen("abc") > strlen("abcdef")) //<={printf(">\n");}else{printf("<=\n"); }return 0;
}
模拟实现strlen
1、计算器方法
2、指针-指针的方法
3、递归的方法
#include <assert.h>
#include <stdio.h>size_t my_strlen(const char* str)
{size_t count = 0;assert(str);while (*str != '\0'){count++;str++;}return count;
}
int main()
{char arr[] = "abcdef";size_t n = my_strlen(arr);printf("%u\n", n); //6return 0;
}
strcpy()
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’拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。
#include <stdio.h>
#include <string.h>int main()
{char name[20] = {0};strcpy(name, "zhangsan"); //name = "zhangsan"; //error,name数组名是地址,地址是一个常量值,不能被赋值printf("%s\n", name); //zhangsanreturn 0;
}
#include <stdio.h>
#include <string.h>int main()
{char name[20] = {0};strcpy(name, "zhang\0san"); printf("%s\n", name); //zhangreturn 0;
}
#include <stdio.h>
#include <string.h>int main()
{char name[20] = "xxxxxxxxxxx";char arr[] = {'b', 'i', 't'};strcpy(name, arr); //原始数据须有\0printf("%s\n", name); //zhangreturn 0;
}
#include <stdio.h>
#include <string.h>int main()
{char name[3] = "";char arr[] = "abcdef";strcpy(name, arr); printf("%s\n", name); //abcdef,程序崩溃return 0;
}
#include <string.h>int main()
{char* p = "abcdef";char arr[] = "bit";strcpy(p, arr); //目标区域不可变return 0;
}
模拟实现strcpy
#include <stdio.h>
char* my_strcpy(char* dest, const char* src)
{assert(dest);assert(src);char* ret = dest;while (*src){*dest++ = *src++;}*dest = *src; // \0return ret; //返回目标空间的地址
}
int main()
{char arr1[] = {"abcdef"};char arr2[] = {0};my_strcpy(arr2, arr1);printf("%s\n", arr2); //abcdefreturn 0;
}
//优化
#include <stdio.h>
char* my_strcpy(char* dest, const char* src)
{assert(dest && src);char* ret = dest;while (*dest++ = *src++){;}return ret; //返回目标空间的起始地址
}
int main()
{char arr1[] = {"abcdef"};char arr2[] = {0};my_strcpy(arr2, arr1);printf("%s\n", arr2); //abcdefreturn 0;
}
strcat():字符串追加
源字符串必须以’\0’结束。
目标空间必须足够大,能容纳下源字符串的内容。
目标空间必须可修改。
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "hello ";strcat(arr1, "world");printf("%s\n", arr1); //hello worldreturn 0;
}
模拟实现strcat
#include <stdio.h>
#include <assert.h>char* my_strcat(char* dest, const char* src)
{char* ret = dest;assert(dest && src);//1.找到目标空间的末尾\0while(*dest != '\0'){dest++;}//2.拷贝字符串while (*dest++ = *src++){;}return ret;
}
int main()
{char arr1[20] = "hello ";my_strcat(arr1, "world");printf("%s\n", arr1); //hello worldreturn 0;
}
自己给自己追加?死循环
#include <stdio.h>
#include <assert.h>char* my_strcat(char* dest, const char* src)
{char* ret = dest;assert(dest && src);//1.找到目标空间的末尾\0while(*dest != '\0'){dest++;}//2.拷贝字符串while (*dest++ = *src++){;}return ret;
}
int main()
{char arr1[20] = "hello ";my_strcat(arr1, arr1);printf("%s\n", arr1); return 0;
}
strcmp()
//error,这里是在比较2个地址,而不是比较2个字符串的内容
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "zhangsan";char arr2[] = "zhangsanfen";//比较两个字符串是否相等if (arr1 == arr2) //arr1是数组名,数组名是数组首元素的地址;arr2是数组名,数组名是数组首元素的地址{printf("==\n");}elseprintf("!=\n"); //!=return 0;
}
2个字符串比较相等,应该使用strcmp。
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "zhangsan";char arr2[] = "zhangsanfen";int ret = strcmp(arr1, arr2);if (ret < 0)printf("<\n"); //<else if (ret == 0)printf("==\n");elseprintf(">\n");return 0;
}
#include <stdio.h>
#include <string.h>int main()
{char arr1[] = "abcdef";char arr2[] = "abq"; //一对一对比较ASCII码值int ret = strcmp(arr1, arr2);if (ret < 0)printf("<\n"); //<else if (ret == 0)printf("==\n");elseprintf(">\n");return 0;
}
模拟实现strcmp
#include <stdio.h>
#include <string.h>
#include <assert.h>int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);while (*str1 == *str2){if (*str1 == '\0')return 0; //相等str1++;str2++;}if (*str1 > *str2)return 1;elsereturn -1;
}
int main()
{char arr1[] = "abc";char arr2[] = "abc"; int ret = my_strcmp(arr1, arr2);if (ret < 0)printf("<\n"); else if (ret == 0)printf("==\n"); //==elseprintf(">\n"); return 0;
}
//优化
#include <stdio.h>
#include <string.h>
#include <assert.h>int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);while (*str1 == *str2){if (*str1 == '\0')return 0; //相等str1++;str2++;}return (*str1 - *str2);
}
int main()
{char arr1[] = "abc";char arr2[] = "abc"; int ret = my_strcmp(arr1, arr2);if (ret < 0)printf("<\n"); else if (ret == 0)printf("==\n"); //==elseprintf(">\n"); return 0;
}
strncpy()
长度受限制的字符串函数strncpy()、strncat()、strncmp()
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "abcdef";char arr2[] = "hello bit";strncpy(arr1, arr2, 5);printf("%s\n", arr1); //hellofreturn 0;
}
strncat()
strncmp()
#include <stdio.h>
#include <string.h>int main()
{char arr1[] = "abcdef";char arr2[] = "abcq";int ret = strncmp(arr1, arr2, 4);if (ret == 0)printf("==\n");else if (ret < 0)printf("<\n"); //<elseprintf(">\n");return 0;
}
#include <stdio.h>
#include <string.h>int main()
{char arr1[] = "abcdef";char arr2[] = "abcq";int ret = strncmp(arr1, arr2, 3);printf("%d\n", ret); //0return 0;
}
strstr():查找子串
#include <stdio.h>
#include <string.h>int main()
{char email[] = "zpw@bitejiuyeke.com";char substr[] = "bitejiuyeke";char* ret = strstr(email, substr);if (ret == NULL)printf("子串不存在\n");elseprintf("%s\n", ret); //bitejiuyeke.comreturn 0;
}
模拟实现strstr
#include <stdio.h>
#include <string.h>
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;
}
int main()
{char email[] = "zpw@bitejiuyeke.com";char substr[] = "bitejiuyeke";char* ret = my_strstr(email, substr);if (ret == NULL)printf("子串不存在\n");elseprintf("%s\n", ret); //bitejiuyeke.comreturn 0;
}
也可使用KMP算法:用来实现一个字符串中查找子字符串的,效率高,但是实现难度大。(B站搜索:大比特博哥)
strtok():切割字符串
char* strtok(char* str, const char* sep);
sep参数是一个字符串,定义了用作分隔符的字符集合。
第一个参数指定一个字符串,它包含了0个或多个由sep字符串中一个或多个分隔符分割的标记。
strtop函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(注意:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回NULL指针。
#include <stdio.h>
#include <string.h>int main()
{const char* sep = "@.";char email[] = "zhangpengwei@bitejiuyeke.com";char cp[30] = {0}; strcpy(cp, email);char* ret = strtok(cp, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);ret = strtok(NULL, sep);printf("%s\n", ret);return 0;
}
//显得啰嗦
#include <stdio.h>
#include <string.h>int main()
{const char* sep = "@.";char email[] = "zhangpengwei@bitejiuyeke.com";char cp[30] = {0}; strcpy(cp, email);char* ret = strtok(cp, sep);if (ret != NULL)printf("%s\n", ret);ret = strtok(NULL, sep);if (ret != NULL)printf("%s\n", ret);ret = strtok(NULL, sep);if (ret != NULL)printf("%s\n", ret);return 0;
}
//for循环修正
#include <stdio.h>
#include <string.h>int main()
{const char* sep = "@.";char email[] = "zhangpengwei@bitejiuyeke.com";char cp[30] = {0}; strcpy(cp, email);char* ret = NULL;for (ret = strtok(cp, sep); ret != NULL; ret = strtok(NULL, sep)){printf("%s\n", ret);}return 0;
}
strerror():返回错误码,所对应的错误信息
C语言的库函数,在执行失败的时候,都会设置错误码。0 1 2 3 4 5 6 7 8
#include <stdio.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));printf("%s\n", strerror(4));printf("%s\n", strerror(5));return 0;
}
//errno:C语言设置的一个错误码存放的全局变量,但需要包含头文件#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{FILE* pf = fopen("test.txt", "r");if (pf == NULL){printf("%s\n", strerror(errno));return 1;}else{//}return 0;
}
字符分类函数
函数 | 如果它的参数符合下列条件就返回真 |
---|---|
iscntrl | 任何控制字符 |
isspace | 空白字符:空格‘ ’,换页’\f’,换行’\n’,回车’\r’,制表符’\t’或者垂直制表符’\v’ |
isdigit | 十进制数字0-9 |
isxdigit | 十六进制数字,包括所有十进制数字,小写字母a-f,大写字母A-F |
islower | 小写字母a-z |
isupper | 大写字母A-Z |
isalpha | 字母a-z或A-Z |
isalnum | 字母或者数字,a-z,A-Z,0-9 |
ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph | 任何图形字符 |
isprint | 任何可打印字符,包括图形字符和空白字符 |
#include <stdio.h>
#include <ctype.h>int main()
{int a = isspace(' ');printf("%d\n", a); //8return 0;
}
#include <stdio.h>
#include <ctype.h>int main()
{int a = isdigit('0');printf("%d\n", a); //4return 0;
}
#include <stdio.h>
#include <ctype.h>int main()
{int a = isdigit('x');printf("%d\n", a); //0return 0;
}
字符转换函数
tolower()
toupper()
#include <stdio.h>
#include <ctype.h>int main()
{printf("%c\n", tolower('W')); //wreturn 0;
}
#include <stdio.h>
#include <ctype.h>int main()
{printf("%c\n", tolower('@')); //@return 0;
}
memcpy():内存拷贝
strcpy()和strncpy()只能拷贝字符串。如果想要拷贝整型或者其它类型怎么办呢?
#include <stdio.h>
#include <string.h>
int main()
{int arr1[] = {1,2,3,4,5,6,7};int arr2[10] = {0};memcpy(arr2, arr1, 28);float arr3[5] = {1.0, 2.5, 3.0, 5.0, 6.0};float arr4[10] = {0.0};memcpy(arr4, arr3, 20);return 0;
}
模拟实现memcpy
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{assert(dest && src);void* ret = dest;while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}
int main()
{int arr1[] = {1,2,3,4,5,6,7};int arr2[10] = {0};my_memcpy(arr2, arr1, 28);return 0;
}
memcpy负责拷贝两块独立空间中的数据。
像上述案例,想要重叠内存的拷贝,是怎么做的呢?使用memmove()函数。
memmove()
windows自带的“画图”工具。【英文名:mspaint】
复习前半段:
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{assert(dest && src);void* ret = dest;while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}void test2()
{int arr1[] = {1,2,3,4,5,6,7,8,9,10};my_memcpy(arr1+2, arr1, 20); //1 2 1 2 3 4 5 8 9 10int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}
}
int main()
{test2();return 0;
}
并未如结果所示,所以使用memmove():
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{assert(dest && src);void* ret = dest;while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}void test2()
{int arr1[] = {1,2,3,4,5,6,7,8,9,10};//my_memcpy(arr1+2, arr1, 20); //1 2 1 2 3 4 5 8 9 10memmove(arr1+2, arr1, 20); //memcpy函数是不用来处理重叠的内存之间的数据拷贝;使用memmove函数来实现,重叠内存之前的数据拷贝int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}
}
int main()
{test2();return 0;
}
注意:VS下的内置memcpy()函数是可以实现重叠内存的数据拷贝,可自己尝试,由此看出函数也很卷啊!
模拟实现memmove()
#include <stdio.h>
#include <string.h>
#include <assert.h>void my_memmove(void* dest, const void* src, size_t num)
{assert(dest && src);void* ret = dest;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;
}
void test3()
{int arr1[] = {1,2,3,4,5,6,7,8,9,10}; my_memmove(arr1+2, arr1, 20); //my_memmove(arr1, arr1 + 2, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}
}
int main()
{test3();return 0;
}
有时候需要从前往后处理数据,有时候又需要从后往前处理数据。
memcmp()
#include <stdio.h>
#include <string.h>int main()
{int arr1[] = {1,2,3,4,5}; //01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00int arr2[] = {1,3,2}; //01 00 00 00 03 00 00 00 02 00 00 00int ret = memcmp(arr1, arr2, 12);printf("%d\n", ret); //-1return 0;
}
memset():内存设置
#include <stdio.h>
#include <string.h>
int main()
{char arr[] = "hello bit";memset(arr, 'x', 5);printf("%s\n", arr); //xxxxx bitreturn 0;
}
#include <stdio.h>
#include <string.h>
int main()
{char arr[] = "hello bit";memset(arr+6, 'x', 3);printf("%s\n", arr); //hello xxxreturn 0;
}
//将arr初始化为全1,答案并非我们所想
#include <stdio.h>
#include <string.h>
int main()
{int arr[10] = {0};memset(arr, 1, 40);int i = 0;for (i = 0; i < 10; i++){printf("%d\n", arr[i]);}return 0;
}
总结
今天就暂且更新至此吧,期待下周再会。如有错误还请不吝赐教。希望对您学习有所帮助,翻页前留下你的支持,以防下次失踪了嗷。
作者更新不易,免费关注别手软。