字符、字符串函数与内存函数

字符、字符串函数与内存函数 1.1字符分类函数字符分类函数用于区分不同类型的字符 每个函数所分类的内容不同但这些函数都包含在ctype.h中。字符分类函数有以下几种iscntrl任何控制字符isspace空白字符isdigit‘0’—‘9’字符islowera—zisalphaA—Z等等。字符分类函数的用法相似符合分类标准的返回非零整数否则返回0。注虽然在字符分类函数传参的类型是int类型 但我们可以直接传递char类型的数据之后会自动发生类型转换。#用例字符串小写转换大写#include stdio.h#include ctype.hint main (){int i 0;char str[] Test String.\n;char c;while (str[i]){c str[i];if (islower(c))c - 32;putchar(c);i;}return 0;}上述代码中的putchar用于输出打印前置if分类判断小写转换为大写若本为大写则返回0跳过if直接输出。1.2字符转换函数C语言中提供了两个转换函数tolower大写转小写toupper小写转大写这样我们可以改进上述用例中的c-32变为toupperc1.3.1strlen函数的使用strlen专门用于计算字符串的长度从首字母开始直到遇到第一个\0随后返回元素个数。正常情况下创建一个字符串有两种方式①char arr “abc”②通过双引号开辟一个字符串存放在常量池中使用指针指向首元素地址char* p“abc”但因为由于是字符常量所以不可被修改。这两种存储方式在末尾元素后会附带\0因此strlen可以正常使用但是如果创建一个字符型数组其成员使用单引号存储char arr[]{‘a’‘b’‘c’}则在末尾元素后不附带\0因此strlen会越界访问直到在数组界限外的随机值中遇到首个\0才会停下。如果坚持使用这种写法可以在末尾主动加一个\0以解决问题。1.3.2strlen的模拟实现strlen有三种模拟实现方法1使用单指针遍历直到找到\0并在循环中使用coust计数器技术2使用双指针。利用指针-指针元素个数的规则直接返回末地址-初地址。3递归。递归的目的是把复杂的问题拆成一个个小问题并且使用时要求有结束条件。我们可以预见当字符串中没有元素只有\0时strlen会输出0这属于结束条件 我们可以往前倒推当只有一个元素时可以返回1没有字符是的情况…最后我们可以得到递推公式return 1mystrlenstr。1.4.1strcpy的使用strcpy函数用于复制一个字符型数组的内容至另一个数组其参数为char* strcpy(char * destination, const char * source );形参1是需要拷贝到的目的地形参2是拷贝项目返回目的地的地址。注在vs编译器中strcpy可以在相邻重合数组间进行拷贝但不代表stecpy本身适合干这件事情对于重合数组间的拷贝我们需要使用到内存函数1.4.2strcpy的模拟实现char* my_strcpy(char *dest, const char*src){char *ret dest;assert(dest ! NULL);assert(src ! NULL);while((*dest *src)){;}return ret;}比较简单在这里不过多赘述需要注意的点strcpy会拷贝末尾的\0原本在while函数内写的两个可以合并到while判断条件中由于解引用操作符优先级高于所以会先赋值再效果与放在内部等同。赋值操作返回所赋的值当*src为\0时\0的ASCII码值为0正好返回0 while循环终止和放在内部不相同的是当循环结束时作为条件放在内部会把执行完毕再结束循环此时指针指向\0之后而把放在内部由于一遇到\0就停止没机会往里执行所以最后指针指向\0处。1.5.1strcat的使用strcat用于两个不重叠字符串的追加。char* strcat(char * destination, const char * source );传参类型与strcpy相同此函数会从源头函数的地址开始依次放到目的函数地址中。1.5.2strcpy的模拟实现和strcpy的思路类似 区别是要先用while循环找到目的数组的\0处然后从此开始追加由于我们需要的地址是\0的地址所以不能把放到判断条件中原因见上然后就和strcpy一样遍历赋值。1.6.1strcmp的使用strcmp用于比较两个字符串的大小只比较第一个互不相同的字符即可分出大小。int strcmp(const char * str1, const char * str2 );注意此函数返回类型为整形若大于返回大于0的数小于返回小于0的数等于返回0。1.6.2strcmp的模拟实现思路也很简单循环找到第一个不相同的字符由于返回值大小不重要主要看正负号因此不需要进行比较直接返回两个元素的ASCII码值相减的结果就行int my_strcmp (const char * str1, const char * str2){int ret 0 ;assert(str1 ! NULL);assert(str2 ! NULL);while(*str1 *str2){if(*str1 \0)return 0;str1;str2;}return *str1-*str2;}1.7strncpy的使用与strcpy不同的是形参的最后会加一个需要比较的个数size_t num其次strncpy不需要原函数有\0其本身也不会拷贝\0只拷贝需要的个数1.8 strncat的使用同样是字符追加 同样是多了第三个形参size_t num 不多赘述1.9strncmp的使用比较指定个数的字符 多了第三个参数size_t num1.10strstr的使用strstr用于比较第二个字符串是否为第一个字符串的子串。char* strstrconst char* str1const char* str2如果不是子串就返回NULL如果是子串就返回第一次相同的地址。1.10.1strstr的模拟实现模拟实现需要一套半指针 第一套指针p和p2用于遍历两个数组判断是否存在相同第二个指针cur用于记录开始比较时的母串指针p1当没有遇到相同字符时p1和p2同时 当遇到相同字符时说明从此地址开始有可能是子串所以用一个cur指针记录 然后继续遍历如果中间出现不同说明cur处开始不可能是子串所以cur并把p1置会curp2置回首元素重新开始遍历。结束条件是当p2指向\0说明中间没有不同 所以返回cur地址即为子串所在。1.11strtok函数的使用char* strtokchar* strconst char *delim第二个形参用于提供一个分隔符集合第一个形参是符合分隔符集合中格式的字符串。若调用成功则返回子串地址并将第一个分隔符置为\0并存储此分隔符的地址。当第二次调用时若第一形参是NULL则从记录的第一个分隔符处开始继续分割当没有更多子串可以分割时返回NULL。注strtok会直接修改原字符串若不希望改变应先拷贝一份。1.12strerror的使用char* strerrorint errnum在C语言中会有一个头文件errno.h用于说明程序发生错误时的错误码错误码都是整数每个数字对应不同的错误。在程序开始运行时会创建一个全局变量errno用于存放出错的错误码正常情况下是0表示没有错误我们可以使用此函数返回错误信息。1.13perrorperror和strerror类似 区别是perror相当于printf和strerror的集合 我们可以在括号中填入我们想说的话用双引号包含函数会输出这句话并附带冒号后加错误原因。2.C语言内存函数2.1.1memcpy的使用次函数用于拷贝指定长度的内存块适用于任何类型的数据因此其参数为void * memcpy ( void * destination, const void * source, size_t num );注仅适用于两块区域内存不重叠的情况两块区域内存重叠的情况是未定义的。2.1.2memcpy的模拟实现while循环条件为拷贝的字节数内部赋值然后各自地址加一。注意由于适用于任何类型的数据所以需要强制转换为char*的指针按字节遍历。2.2.1memmove使用memmove函数可以完成内存拷贝对于内存重叠的情况也能完成形参与memcpy相同。2.2.2memmove模拟实现我们实现时可以通过两块内存的前后来分类赋值方式到底是从后往前还是从前往后。例如1 2 3 4 5 6 7↑ ↑当存在重叠且目的区域在前时当我们要把456拷贝到234区域 如果从后往前拷贝当6拷贝完就会覆盖4导致失败所以我们要从前往后拷贝。同理当重叠且目的区域在后时需要从后往前拷贝。因此整体可根据前后分为两种方式。2.3memset使用void * memset ( void * ptr, int value, size_t num );memset用于设置内存块的内容将指定长度的空间设置为特定内容2.4memcmp的使用int memcmp ( const void * ptr1, const void * ptr2, size_t num );用于比较指定两块内存块的内容向后num个字节 根据大小不同返回正数负数或0。