字符函数,字符串函数,内存函数

张开发
2026/4/11 22:32:43 15 分钟阅读
字符函数,字符串函数,内存函数
Typora图片上云折腾了好久最后终于成功了文章目录ctype.h1.字符判断2.字符转换string.hstrlen和sizeof的比较三种方法模拟实现strlenstrcpy/strncpy特殊情况模拟实现strcat/strncat注意事项模拟实现二者的区别strcmp/strncmp模拟实现得到的教训strstr模拟实现strtok注意事项strerror与perrormemcpy和strcpy对比局限memmove和memcpy对比模拟实现memset局限性memcmp和strcmp对比ctype.h1.字符判断判断是否是对应内容如果是就返回非0不是就返回0iscntrl控制字符https://c.biancheng.net/c/ascii/中的黄色的码值为0~31和127常见的有\n ,\0isspace空格 ASCII 32换页\f12换行\n10回车\r13制表符\t9垂直制表符\v11isdigit数字字符isxdigit16进制数字所包含的字符09az、A~Zislower小写字母isupper大写字母isalpha字母isalnum字母数字ispunct标点符号! # $ % ’ ( ) * , - . / : ; ? [ \ ] ^ _ { | } ~isgraph能看见的ASCII 33 ~ 126所有可打印字符排除空格 isprint能打印的ASCII 32 ~ 126所有可打印字符加上空格 2.字符转换tolower小写转大写其他不变toupper大写转小写其他不变具体实践将商标中的小写转化成大写通过字符判断函数//将商标中的小写字母转为大写#includestdio.h#includestring.h#includectype.hchar*atoA(char*s,intsize){char*rets;for(inti0;isize;i){if(islower(s[i]))s[i]s[i]-32;}returnret;}intmain(){chars[]12310Tag;intsizestrlen(s)/sizeof(s[0]);printf(%s\n,atoA(s,size));return0;}通过字符转换函数char*atoA(char*s,intsize){char*rets;for(inti0;isize;i){s[i]toupper(s[i]);}returnret;}string.hstrlen基本功能和条件计算字符串长度传参是char*返回值是size_t字符串要有\0使用双引号初始化strlen只读到\0一般示例求学生英文作文中包含空格的字数//求作文中包含空格的字数#includestdio.h#includestring.hintmain(){chars[]this is my article;printf(%zu\n,strlen(s));return0;}特殊事例字符串中有‘\0’的情况#includestdio.h#includestring.hintmain(){chars[]this \0 is my article;printf(%zu\n,strlen(s));return0;}和sizeof的比较二者返回值都是size_t类型strlen只计算字符数组的长度sizeof计算任意数组的字节长度strlen计算到\0截止sizeof不会截止计算含\0的字符串后者会计算\0不能用于遍历三种方法模拟实现strlen直接进行计数#includestdio.hsize_tmystrlen(char*s){size_t len0;while(*s!\0){len;s;}returnlen;}intmain(){chars[]hello i am 12310;printf(%zu\n,mystrlen(s));return0;}使用递归的方式#includestdio.hsize_tmystrlen(char*s){size_t len0;if(*s\0)return0;return(mystrlen(s1)1);}intmain(){chars[]hello i am 12310;printf(%zu\n,mystrlen(s));return0;}两个指针相减的方式size_tmystrlen(char*s){char*tmps;while(*s){s;}return(s-tmp);}strcpy/strncpy功能将source中的内容复制到destination中条件传参前者传两个参数第一个是目标地址第二个是source的地址后者传3个参数前两个参数和前者一样 多了一个长度的参数一般示例strcpy将nihao复制到hello的位置:strcpy会将后面的斜杠零也复制进去导致使用printf的时候打印到第一个\0就会停#includestdio.h#includestring.hintmain(){chars[]hello i am 12310;chars0[]nihao;printf(%s\n,strcpy(s,s0));return0;}strncpy:这里只将你好的长度作为第3个参数传进去了所以不会复制结尾的斜杠0使用printf自然也不会出问题#includestdio.h#includestring.hintmain(){chars[]hello i am 12310;chars0[]nihao;printf(%s\n,strncpy(s,s0,strlen(s0)));return0;}特殊情况Source未满 \ Source中(第N个字符前)有\0内存情况该放进去的位置还是会放进去只是不够的补成了\0模拟实现strcpy#includestdio.hchar*mystrcpy(char*dest,char*sou){char*retdest;//从第一个字符开始将sou中的复制到dest中while(*sou){*dest*sou;dest;sou;}*dest\0;returnret;}intmain(){chars[]hello i am 12310;chars0[]nihao;printf(%s\n,mystrcpy(s,s0));return0;}缺点逻辑清晰但是代码行数比较多。而且当sou到遇\0了就会停止进行复制微微改造后置加加先使用再加加。相当于和前面一样那两句再次微微改造这个语句等号语句它的返回值相当于就是赋值后的内容那么当赋值为斜杠铃之后会停止这时候斜杠0已经放进去了不需要在结尾再单独再最后放一个\0最终版本#includestdio.hchar*mystrcpy(char*dest,char*sou){char*retdest;//从第一个字符开始将sou中的复制到dest中while(*(dest)*(sou)){;}returnret;}intmain(){chars[]hello i am 12310;chars0[]nihao;printf(%s\n,mystrcpy(s,s0));return0;}strncpy注意事项我这个句子比较简便我在while循环中直接上了一个num可是可是while循环中的这个句子它是会从前往后顺下去也就是说当你的num已经变成0时前面的(dest) (sou)多进行了一次进行了4次而不是num中的3。这时候会导致错误: 就比如我例子中你好最后的\0也添加进去了所以打印的时候只打印出了你好错误示例正确示例二者的区别后者有复制数的限制参数也多一个在有\0的字符串的复制中前者只能起到覆盖作用因为斜杠铃是必须会加进去的strcat/strncat基本用法将source字符串添加到destination字符串的末尾前者直接添加后者有添加数的限制注意事项我图中出现的错误虽然我想把S0添加到S的后面但是他们在初始化的时候字符串的长度已经把数组长度给填满了所以已经没位置给我的S0了。所以如果想使用的话字符串在创建的时候必须要给更长的长度错误示例正确示例特殊情况sou中间有\0只会添加\0之前的内容模拟实现strcatstrncat二者的区别后者多了一个参数更灵活更安全。后者的source也不需要有\0了strcmp/strncmp基本用法传参基本和前两个一样返回值是int类型如果前者大就返回正数后者大就返回负数一样大返回0按照字典去比较模拟实现strcmp#includestdio.hintcmp(char*s1,char*s2){//前面的元素可能相同所以先找到第一个不相同的元素while(*s1*s2){s1;s2;}return(*s1-*s2);}intmain(){chars1[]hello;chars2[]he;if(cmp(s1,s2)0)printf(hello 的字典序更大);elseif(cmp(s1,s2)0)printf(hi 的字典序更大);elseprintf(两者 字典序一样大);return0;}strncmp:错误示范原因是 我只想比较前两个字符while循环也的确只进行了两次但是两次之后得到的是第三个字符通过第三个字符来比较自然是不合理的正确示范得到的教训While循环实际进行的次数和我们想要的次数 的关系 比较难以确定如本题中想要while中的数组只比较下标为0和1的元素但是因为while执行两次最后指针指向的下标是2想让比较过的元素在最后相减就不行strstr基本用法传参传两参数第一个参数是一个字符串的地址第二个参数是想找的字符串的地址返回值也是个地址是想找的字符串在第一个字符串中 第一次出现的位置。如果不存在返回NULL例子找到abcddfghi中的dd并改为de模拟实现//模拟实现strstr#includestdio.hchar*mystrstr(char*str,char*target){//从第一个元素开始双层循环外层是对str的遍历内层是判断这次的位置p开始的字符和target中的是否匹配//如果能一直匹配直到target的\0就return p。while(*str){char*pstr;char*posofttarget;//position of target指向target的首while(*posoft*p(*posoft*p))//当然还有前提条件就是遍历的两个量都不是\0{posoft;p;}if(*posoft\0)returnstr;str;}returnNULL;}intmain(){chars[]hello this is the ans;chars1[]the;//如果能找到‘the’就从the开始打印printf(%s\n,mystrstr(s,s1));return0;}strtok基本用法最基本的用法第一次使用传参的第一个参数是一个字符串的 地址第二个参数也是一个字符串字符串中的每一个字符都会被当做想要截断的字符对应位置在被截断的时候会变为\0在第二次以及以后的传参第一个参数变成了NULL每次都会返回一个地址截断所得的 前一段的地址当整个字符串已经都被截断过了返回的就是NULL#includestring.h#includestdio.hintmain(){chars[]emm,its hard to tell.maybe,next time;printf(%s\n,strtok(s,,.));printf(%s\n,strtok(NULL,,.));printf(%s\n,strtok(NULL,,.));printf(%s\n,strtok(NULL,,.));return0;}一般用法使用for循环)#includestring.h#includestdio.hintmain(){chars[]emm,its hard to tell.maybe,next time;for(char*tmpstrtok(s,.,);tmp!NULL;tmpstrtok(NULL,.,)){printf(%s\n,tmp);}return0;}注意事项这会将整个字符串截断字符串应该提前复制保留传的第二个参数是个字符串其中的每个字符都会被当做单独的 要去截断的字符截段意味着把它变成\0strerror与perror前者的使用需要配合errno需要单独的头文件errno.h当运行有错误的时候使用strerror参数为errno打印的时候使用%s就能打印对应错误信息#includestdio.h#includestring.h#includeerrno.hintmain(){// 尝试打开一个不存在的文件FILE*fpfopen(不存在的文件.txt,r);// 判断fopen 失败会返回 NULLif(fpNULL){// 用 strerror 翻译 errno 里的错误码printf(文件打开失败原因%s\n,strerror(errno));//打印出来的结果:文件打开失败原因No such file or directoryreturn1;}fclose(fp);return0;}后者的使用更加简洁不过头文件相同。传的参数是一个字符串打印错误时会在字符串后面添上一个冒号再添加上对应的错误perror(打开文件失败);//打印的结果打开文件失败: No such file or directorymemcpy基本用法使用时的目的和strcpy相似前两个参数和strcpy相同但是第三个参数变成了字节长度和strcpy对比前者仅对字符串有效后者没有限制前者在遇到\0时停止并且会把\0也添加上去。后者不会局限memcpy无法处理内存重叠的情况(此时使用memmove)模拟实现#includestdio.hvoid*mymemcpy(void*dest,void*sou,intlen){void*retdest;//逐个字节进行修改for(inti0;ilen;i){*((char*)desti)*((char*)soui);}returndest;}intmain(){intarr[10]{0,1,2,3,4,5,6,7,8,9};intu[3]{3,3,5};mymemcpy(arr,u,sizeof(u));for(inti0;i10;i){printf(%d ,arr[i]);}return0;}memmove基本用法基本用法和memcpy相同但是能处理内存重叠的情况在模拟实现的时候需要考虑从前往后还是从后往前和memcpy对比memmove能够应对内存重叠的情况模拟实现#includestdio.hvoid*mymemmove(void*dest,void*sou,intlen){void*retdest;//逐个字节进行修改if((char*)soulen-1destsoudest){while(len--){*((char*)destlen)*((char*)soulen);}}else{for(inti0;ilen;i){*((char*)desti)*((char*)soui);}}returndest;}intmain(){intarr[10]{0,1,2,3,4,5,6,7,8,9};mymemmove(arr3,arr,20);for(inti0;i10;i){printf(%d ,arr[i]);}return0;}memset基本用法第一个参数是一个地址第二个参数是想把地址上设置的内容可以是数字也可以是字符第三个参数是想设置的字节数局限性在设置字符的时候自然是没有问题因为一个字符就是一个字节但是如果想将整型数组设置的话就不太行毕竟一个征信的是4个字节嘛一般对整型数组使用的时候只设****0memcmp基本用法传的参数和strcmp相似第三个参数的含义变了——相比较的字节数和strcmp对比strcmp只能比较字符串而且只能比较到一个字符串的\0 。而memcmp没有限制

更多文章