摘要:自己实现时返回值可根据实际情况而定源字符串必须以结束。语言中给了一些长度受限的字符串函数,而前面的函数是长度不受限的字符串函数。拷贝个字符从源字符串到目标空间。
目录
本章重点
前言
C 语言中对字符和字符串的处理很是频繁,但是 C 语言本身是没有字符串类型的,字符串通常放在 常量字符串 中 或者 字符数组 中。 字符串常量 适用于那些对它不做修改的字符串数。
size_t strlen ( const char * str );
注:size_t 即无符号整型(unsigned int)
strlen使用:
#include#includeint main(){ char arr1[] = "abcdef"; char arr2[] = { "a","b","c","d","e","f","/0"};//计算字符数组长度时末尾必须加"/0", //否则计算出的长度为随机值. printf("%d/n", strlen(arr1)); printf("%d/n", strlen(arr2)); return 0;}
strlen模拟实现:
//方法一:使用计数器size_t my_strlen(char* str){ assert(str);//检查指针有效性 int count = 0;//计数器 //while (*str != "/0") //{ //count++; //str++; //} //简化 while(*str++) { count++; } return count;}//方法二:递归size_t my_strlen2(char* str){ assert(str); if (!*str) { return 0; } else { return 1 + my_strlen(str + 1); }}//方法三:指针减指针size_t my_strlen3(char* str){ assert(str); char* cur = str; while (*cur) { cur++; } return cur - str;//两指针相减,结果为他们之间的元素个数}
注:下面的代码结果如何?
#include #include int main(){ const char*str1 = "abcdef"; const char*str2 = "bbb"; if(strlen(str2)-strlen(str1)>0)//由于strlen函数的返回值为无符号整型, //所以在计算时,会恒为正数。自己实现时返回值可根据实际情况而定 { printf("str2>str1/n"); } else { printf("srt1>str2/n"); } return 0;}
char* strcpy(char * destination, const char * source );
strcpy使用:
#include#includeint main(){ char arr1[10] = "xxxxxxxxx"; char arr2[] = "abcdef"; printf("%s/n", strcpy(arr1, arr2));//将arr2字符串中的内容拷贝到arr1中(包括"/0) return 0; //需保证arr1的空间大于等于arr2的空间}
strcpy模拟实现:
#include//用assert函数需包含此头文件char* my_strcpy(char* dest, const char* src)//返回值为目标空间的起始地址,src中的字符串 //不需要改变,为避免被修改所以再它前面加上const{ assert(dest && src);//检查指针的有效性 char* ret = dest;//保存目标空间的起始地址,dest后面会移动 //while (*src!="/0") //{ // *dest = *src; // dest++; // src++; //} //简化 while (*dest++ = *src++)//src先将值赋给dest,然后dest和src才++ { ; } return ret;}
char * strcat ( char * destination, const char * source );
strcat使用:
#include#includeint main(){ char arr1[10] = "abcd"; char arr2[] = "efgh"; printf("%s", strcat(arr1, arr2));//将arr2中的字符串追加到arr1中的字符串后面 return 0; //需保证arr1的空间容纳连接后的字符串}
strcat模拟实现:
#includechar* my_strcat(char* dest, const char* src){ assert(dest && src); char* ret = dest; while (*dest)//因为是将src中的字符串追加到dest的后面所以需先找到dest中"/0"的位置 { dest++; } while (*dest++ = *src++)//同strcpy { ; } return ret;}
其中大概步骤如图:
int strcmp ( const char * str1, const char * str2 );
strcmp使用 :
#include#includeint main(){ char arr1[] = "abcdef"; char arr2[] = "abcdxx"; int ret = strcmp(arr1, arr2); if (ret > 0) { printf("arr1 > arr2/n"); } else if (ret < 0) { printf("arr1 < arr2/n"); } else { printf("arr1 = arr2/n"); } return 0;}
strcmp模拟实现
#includeint my_strcmp(const char* str1, const char* str2)//str1和str2都不需要被改变{ assert(str1 && str2); while (*str1 == *str2)//如果找到不相等的字符直接返回他们的ascll码值之差, //而不是将所有的字符全部比较完之后再返回. { if (*str1 == "/0") { return 0; } str1++; str2++; } return *str1 - *str2;}
前面学习了这些字符串函数之后,大家是否有些许收获呢?
其实这些函数中有些是不安全的,比如:strcpy中如果目标空间的大小不能够容纳原空间的字符串,就会造成数组越界访问,strcat中也是同样的道理。还有如果字符串自己给自己追加,是不能使用strcat函数的;如果我们只想比较字符串中的部分字符串的大小,而不是全部,也不能使用strcmp。C语言中给了一些长度受限的字符串函数,而前面的函数是长度不受限的字符串函数。
char * strncpy ( char * destination, const char * source, size_t num );
strncpy使用:
#include#includeint main(){ char arr1[] = "xxxxxxxxxx"; char arr2[] = "xx"; char arr3[] = "abcdef"; printf("%s/n", strncpy(arr1, arr3, 8));//拷贝了8个字符,所以字符串中的"/0"也会被拷贝 printf("%s/n", strncpy(arr2, arr3, 1));//拷贝了1个字符,"/0"不会被拷贝 return 0;}
strncpy模拟实现:
#includechar* my_strncpy(char* dest, const char* src, int count)//参数count为需要拷贝的字节数{ assert(dest && src); char* ret = dest; while(count--) { *dest++ = *src++; } return ret;}
char * strncat ( char * destination, const char * source, size_t num );
strncat使用:
/* strncat example */#include #include int main (){ char str1[20]; char str2[20]; strcpy (str1,"To be "); strcpy (str2,"or not to be"); strncat (str1, str2, 6); puts (str1); return 0;}
strncat模拟实现:
char* my_strncat(char* dest, const char* src, int count){ assert(dest && src); char* ret = dest; while (*dest)//找到目标字符串中"/0"的位置 { dest++; } while (count--) { *dest++ = *src++;//从"/0"处开始追加 } *dest = "/0";//末尾需"/0" return ret;}
int strncmp ( const char * str1, const char * str2, size_t num );
strncmp使用:
/* strncmp example */#include #include int main (){ char str[][5] = { "R2D2" , "C3PO" , "R2A6" }; int n; puts ("Looking for R2 astromech droids..."); for (n=0 ; n<3 ; n++) if (strncmp (str[n],"R2xx",2) == 0)//比较两个字符串的前两个字符 { printf ("found %s/n",str[n]); } return 0;}
strncmp模拟实现:
int my_strncmp(char* str1, char* str2, int count){ assert(str1 && str2); while (*str1 == *str2) { if (count <= 0) { return 0; } str1++; str2++; } return *str1 - *str2;}
char * strstr ( const char *str1, const char *str2 );
strstr使用:
/* strstr example */#include #include int main (){ char str[] ="This is a simple string"; char * pch; pch = strstr (str,"simple"); strncpy (pch,"sample",6); puts (str); return 0;}
strstr模拟实现:
char* my_strstr(const char* str1, const char* str2){ assert(str1 && str2); while (*str1) { char* cur1 = str1; char* cur2 = str2; while (*cur1 == *cur2) { cur1++; cur2++; if (*cur2 == "/0") { return str1; } } str1++; } return NULL;}
此情况下可直接判断str2是否是str1的子串,并且返回相应的值。
当比较到第三个字符时,两字符不相等,而str1并未结束,后续还需比较,所以cur2需回到起始地址,而cur1会回到第一个相等字符的下一个字符的地址处(即第二个b的地址) 。
char * strtok ( char * str, const char * sep );
strtok使用:
/* strtok example */#include #include 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;}
char * strerror ( int errnum );
返回错误码,所对应的错误信息。
/* strerror example : error list */#include #include #include //必须包含的头文件int main (){ FILE * pFile; pFile = fopen ("unexist.ent","r"); if (pFile == NULL) printf ("Error opening file unexist.ent: %s/n",strerror(errno)); //出现错误时,会将错误码(一种错误对应一个错误码)放进errno中,strerror会将这个错误码对应的内容打印出来 //errno: Last error number return 0;}
例如:
#include#include#includeint main(){ printf("%s/n", strerror(0)); printf("%s/n", strerror(1)); printf("%s/n", strerror(2)); printf("%s/n", strerror(3)); return 0;}
对应错误码结果为:
void * memcpy ( void * destination, const void * source, size_t num );
memcpy使用:
#include#includeint main(){ int arr1[] = { 1,2,3,4,5,6,7,8,9 }; int arr2[10] = { 0 }; int* ret = memcpy(arr2, arr1, 16); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", ret[i]); } return 0;}
memcpy模拟实现:
#includevoid* my_memcpy(void* dest, const void* src, size_t count)//以字节为单位拷贝{ assert(dest && src); void* ret = dest; while (count--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } return ret;}
void * memmove ( void * destination, const void * source, size_t num );
memmove使用:
/* memmove example */#include #include int main (){ char str[] = "memmove can be very useful......"; memmove (str+20,str+15,11); puts (str); return 0;}
memmove模拟实现:
情况一:不存在内存重叠,可直接将内容移动。
情况二:存在内存重叠,且目标空间地址大于源空间地址, 如图将1移动到3的位置之后,3就会被覆盖,在移动3时实际移动的是1.
解决方法:从后往前移动,先移动4,再移动3直到所有字节移动完。
情况三:存在内存重叠,且目标空间地址小于源空间地址,如果再从后向前移动也会导致前面的内容被覆盖。
解决方法:从前往后移动,先移动3,再移动4直到所有字节移动完。
实现代码:
void* my_memmove(void* dest, const void* src, size_t count){ assert(dest && src); void* ret = dest; if (dest > src)//情况二 { void* cur1 = (char*)src + count - 1;//从后往前移动,需先找到两个空间的末尾地址 void* cur2 = (char*)dest + count - 1;//减1是因为加count之后会直接跳到目标空间和源空间的尾地址的下一个字节的地址 while (count--) { *(char*)cur2 = *(char*)cur1;//void*内型指针不能直接加减或解引用操作,需强制类型转换 cur2 = (char*)cur2 - 1;//指针移动 cur1 = (char*)cur1 - 1; } } else//情况1一,三 { void* cur1 = (char*)src; void* cur2 = (char*)dest; while (count--) { *(char*)cur2 = *(char*)cur1; cur2 = (char*)cur2 + 1; cur1 = (char*)cur1 + 1; } } return ret;}
int memcmp ( const void * ptr1,
const void * ptr2,
size_t num );
memcmp使用:
/* memcmp example */#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;}
memcmp模拟实现:
int my_memcmp(const void* str1, const void* str2, int count){ assert(str1 && str2); while (*(char*)str1 == *(char*)str2) { count--; if (count <= 0) { return 0; } str1 = (char*)str1 + 1; str2 = (char*)str2 + 1; } return (char*)str1 - (char*)str2;}
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/120819.html
摘要:在符号位中,表示正,表示负。我们知道对于整型来说,内存中存放的是该数的补码。在计算机系统中,数值一律用补码来表示和存储。表示有效数字,。规定对于位的浮点数,最高的位是 ...
目录 一、数据类型介绍 二、类型的意义 三、类型的基本归类 整型家族 浮点数家族 构造类型(自定义类型) 指针类型 空类型 四、整形在内存中的存储 原码、反码、补码 大小端字节序 为什么有大端和小端? 一道经典笔试题 一、数据类型介绍 数据从大的方向分为两类: 内置类型自定义类型内置类型我们前面已经学习过,如下: char //字符数据类型 short ...
摘要:的理解和区别代表有符号,整数在内存中存储的二进制位的最高位为符号位,表示负数,表示正数。那接下来我们来学习数据在所开辟的内存空间时如何存储的。请看下面例子为什么内存中存储的是补码对于整数来说数据存放内存中其实存放的是补码。 ...
摘要:目录数据在计算机的存储方式补码,反码,原码数据在计算机的存储方式补码,反码,原码整形在内存中的存储整形在内存中的存储整形类型整形类型大端字节序和小端字节序大端字节序和小端字节序浮点数在内存的储存浮点数在内 目录 数据在计算机的存储方式(补码,反码,原码) 整形在内存中的存储: 整形...
摘要:函数的返回值为指针就按照字面意思,指针函数的定义顾名思义,指针函数即返回指针的函数。 目录 前言指针与函数函数的返回值为指针作为函数参数的指针指针函数可以改变变量...
阅读 1266·2021-11-04 16:09
阅读 3327·2021-10-19 11:45
阅读 2357·2021-10-11 10:59
阅读 982·2021-09-23 11:21
阅读 2740·2021-09-22 10:54
阅读 1104·2019-08-30 15:53
阅读 2575·2019-08-30 15:53
阅读 3450·2019-08-30 12:57