strlen()
1)计算给定字符串的长度,不包括’
strlen()
1)计算给定字符串的长度,不包括’\0’在内
unsigned int strlen(const char *s) { assert(NULL != s);//如果条件不满足,则终止程序 unsigned int length = 0; while (*s++ != '\0') ++length; return length; }
strcmp()
1)比较两个字符串,若str1、str2字符串相等,则返回零;若str1大于str2,则返回正数;否则,则返回负数
int strcmp(const char *str1, const char *str2) { assert(NULL != str1 && NULL != str2); while(*str1 && *str2 && *str1 == *str2) { ++str1; ++str2; } return *str1 - *str2; //若相等,则*str1 - *str2 = '\0' - '\0' = 0;否则,*str1 - *str2 != 0;因为前面的位都相等,所以只需要比较当前位来确定返回值 }
strcat()
1)将src所指向的字符串添加到dest结尾处(会覆盖dest结尾处的'\0')
2)src和dest所指内存区域不可以重叠且dest必须有足够的空间(sizeof(dest)-strlen(dest)必须>=strlen(src)+1)来容纳src的字符串
char* strcat(char* dest, const char* src) { assert(NULL != dest && NULL != src);//如果条件不满足,则终止程序 char* temp = dest; while ('\0' != *temp)//while循环出来temp指向原字符串的NULL空字符的位置 ++temp; while (*src != '\0') *temp++ = *src++; return dest; }
strcpy()
1)把字符串src(包括'\0')复制到dest
2)src和dest所指内存区域不可以重叠且dest必须有足够的空间(sizeof(dest)>=strlen(src)+1)来容纳src的字符串
3)返回值char*而不是void,实现了链式表达(就是让调用strcpy的时候可以方便一些,在调用的时候可以一连串(链式)写下来)
char* strcpy(char* dest, const char *src) { assert(NULL != dest && NULL != src); char * temp = dest; while (*src != '\0') *temp++ = *src++; return dest; }
strncpy()
1)将以字符串src所指向的地址开始的前n个字节复制到dest中,并返回dest
2)如果src的前n个字符不含NULL结束符,则dest不会以NULL字符结束
3)如果n>strlen(src)+1,则以'\0'填充dest,直到复制完n个字节
4)src和dest所指内存区域不可以重叠且dest必须有足够的空间(sizeof(dest)>=strlen(src)+1)来容纳src的字符串
5)dest和n应该满足:sizeof(dest)>=n
char* strncpy(char* dest, const char* src, unsigned int n) { assert(NULL != dest && NULL != src); char* temp = dest; while (n > 0 && *src != '\0') { *temp++ = *src++; --n; } while (n > 0) { *temp++ = '\0'; --n; } return dest; }
memset()
1)将以s所指向的地址开始的前n个字节用ch替换,并返回s
2)常用于对较大的数组进行清零操作
void* memset(void* s, int ch, unsigned int n) { assert(NULL != s); char* temp = s; //VS2017中这里会报错,gcc不会 while (n > 0) { *temp++ = (char)ch; //将int转化为char,截去高24位,只保留低8位 --n; } return s; }
3)注意:不能把memset当作万能的初始化工具,应该只把memset当作清0的工具,因为memset是以字节(8bits)为单位进行赋值的
int main() { int dest[2];//这里是int memset(dest, 1, sizeof(dest)); for (int i = 0; i < sizeof(dest) / sizeof(int); ++i) printf("%d\n", dest[i]); return 0; } 程序输出: 16843009 16843009 int main() { int dest[2];//这里是int memset(dest, 0, sizeof(dest)); for (int i = 0; i < sizeof(dest) / sizeof(int); ++i) printf("%d\n", dest[i]); return 0; } 程序输出: 0 0
程序解读:
1)1的二进制 : 00000000000000000000000000000001(32位),在memset源码中1将强制类型转换成char(1字节占8位):00000001(8位)
2)memset函数传入的是sizeof(dest),也就是8(字节),所以n=8,进行8次while循环
3)temp的类型是char*,所以会8位8位地去赋值
4)所以while循环结束,从起始地址开始的值为:0000000100000001000000010000000100000001000000010000000100000001(64位)
5)memset()调用结束后,dest的每个元素按照int类型读取(按32位读取),所以dest[0]=00000001000000010000000100000001(32位)=16843009,dest[1]=00000001000000010000000100000001(32位)=16843009
memcpy()
1)将以src所指向的地址开始的前n个字节到拷贝到dest
2)src和dest所指内存区域不可以重叠,否则拷贝出来的数据将是错误的
void* memcpy(void* dest, const void* src, unsigned int n) { assert(NULL != dest && NULL != src); void* temp = dest; for (int i = 0; i < n; ++i) *((char*)temp + i) = *((char*)src + i); //1个字节1个字节地拷贝,未知类型,不能++ return dest; }
memmove()
1)memmove也是将以src所指向的地址开始的前n个字节到拷贝到dest,但是可以它可以处理src和dest所指内存区域存在重叠的情况(src<dest<src+n)
2)memmove这个函数名称中有"move"这个单词,但实际上并不是"移动"了。这个函数名称有它的历史原因:因为有了memcpy函数后,发现这个函数在使用时容易出现问题,于是又发明了一个能够处理重叠的memcpy函数,但为了保证兼容性依然保留了memcpy函数
void* memmove(void* dest, const void* src, unsigned int n) { assert(NULL != dest && NULL != src); void* temp = dest; if (dest > src || dest < src + n)//内存重叠 { for (int i = n - 1; i >= 0; --i)//从高地址向低地址拷贝 *((char*)temp + i) = *((char*)src + i); } else//内存不重叠 { for (int i = 0; i < n; ++i) *((char*)temp + i) = *((char*)src + i); } return dest; }
’在内
unsigned unsigne