纯C 字符串操作函数 实现 (strcpy, strncpy, memcpy, memset, strcat, strlen ... )

实现C/C++中的字符串操作函数是很练内功的,别看着这些函数很简单,自己实现起来,还是有许多地方需要考虑的,所以没独立写过的朋友,可以自己敲敲看 .--By Crazybaby

strcpy:

char* cb_strcpy(char* dst, const char* src) { assert((dst!=NULL) && (src!=NULL)); char* retAddr = dst; /**< retAddr is in static , char retAddr[] will in Stack, So... */ while ((*(dst++) = *(src++))!='\0') { ; } return retAddr; }

strncpy:

char* cb_strncpy(char* dst, const char* src, size_t size) { assert((dst!=NULL) && (src!=NULL)); char* retAddr = dst; /**< retAddr is in static , char retAddr[] will in Stack, So... */ int i = 0; while (((*(dst++) = *(src++))!='\0') && ((i++) < size)) { ; } *(retAddr+size)='\0'; /**< cut off String */ return retAddr; }

这个strncpy实现版本 和 stdlib.h 下的 strncpy 还是有区别的, 比如

char a[30]; strncpy(a, "Hello", 28); //a除了有Hello,之后会有23个repeat '\0' . 这样会有效率的问题. char b[30]; cb_strncpy(b, "Hello", 28); // 而只有 Hello'\0'

CB: strncpy相对于strcpy来说 ,安全性提高了一个等级 . 另外一个要非常注意的地方那个是 strcpy 和 strncpy 都会遇到 '\0' 结束.

另外:当请求的目标地址空间比源字符串空间要小的时候,strncpy 将不再用”\0”来结束字符串。这是一个巨大的隐患,所以还是不安全


memcpy Version 1:

char* cb_memcpyVer1(char* dst, const char* src, size_t size) { assert((dst!=NULL) && (src!=NULL)); char* retAddr = dst; while (size-- > 0) { *(dst++) = *(src++); } return retAddr; }


CB: memcpy 和 strncpy 最大的区别是 memcpy不会遇到 '\0' 结束拷贝 .


memcpy Version 2 :

char* cb_memcpyVer2(char* dst, const char* src, size_t size) { assert((dst!=NULL) && (src!=NULL)); char* retAddr = dst; size_t i = 0; /* --- 解决数据区重叠问题 --- */ if ((retAddr>src) && (retAddr<(src+size))) { for (i=size-1; i>=0; i--) { *(dst++) = *(src++); } } else { for (i=0; i<size; i++) { *(dst++) = *(src++); } } *(retAddr+size)='\0'; return retAddr; }

CB: memcpyVersion1不能防止overlapping区域的问题, Ver2很好的解决了.

memcpy还有种蛋疼的写法:

void* cb_memcpy(void* dest, const void* src, size_t count) { char* d = (char*)dest; const char* s = (const char*)src; /* --- 每次复制8bit --- */ int n = (count + 7) / 8; switch(count & 7) { case 0: do { *d++ = *s++; case 7: *d++ = *s++; case 6: *d++ = *s++; case 5: *d++ = *s++; case 4: *d++ = *s++; case 3: *d++ = *s++; case 2: *d++ = *s++; case 1: *d++ = *s++; } while (--n > 0); } return dest; }

memset:

void* cb_memset(void* buffer, int b, size_t size) { assert(buffer!=NULL); char* retAddr = (char*)buffer; while (size-- > 0) { *(retAddr++) = (char)b; } return retAddr; }


Memset使用时误区:

char a[10]; memset(a, 0, sizeof(char)*10); //这个操作完全没必要 因为下面这块内存马上要被使用了。 memcpy(a, "Hello", 5);

strlen:

int cb_strlen(const char* str) { assert(str!=NULL); int len = 0; while (*str!='\0') { /**< '\0', stop */ str++; len++ ; } return len; }


Recursive strlen:

int cb_strlen(const char *str) { if ((str == NULL) || (*str == '\0')) { return 0; } else { return cb_strlen(str+1)+1; /**< Rescursive */ } }

strcat:

char* cb_strcat(char* dst, char* src) { assert(src!=NULL); char* retAddr = dst; /* --- Find last position --- */ while (*dst++ != '\0') { ; } dst--; while (*dst++ = *src++) { ; } return retAddr; }

strcmp:

int cb_strcmp(char* str, char* str2) { assert((str!=NULL) && (str2!=NULL)); char* pStr = str; char* pStr2 = str2; while (*pStr && *pStr2 && (*pStr==*pStr2)) { pStr++; pStr2++; } return (*pStr - *pStr2); /**< 相等则为0 , 前者大于后者大于0, 反之小于0 */ }

strncmp:

int cb_strncmp(char* str, char* str2, size_t size) { assert((str!=NULL) && (str2!=NULL)); char* pStr = str; char* pStr2 = str2; while (size-- && *pStr && *pStr2 && (*pStr == *pStr2)) { pStr++; pStr2++; } return (*pStr - *pStr2); }

strchr:

char* cb_strchr(char* str, char c){ assert(str!=NULL); char* retAddr = str; while (*retAddr!=c) { retAddr++; } if (*retAddr == c) { return retAddr; } else { return NULL; } }


这些字符串操作函数实现时要注意这些问题 :
1. 需要检查指针的有效性,一般通过直接和NULL进行比较来判断。
2. 函数需要能够进行链式操作,也就是说 char* a = strcpy(b, "Hello");
3. src的值需要加 const
4. strcnpy 和 memcpy 有 '\0' 判断的区别
5. 内存区重叠问题 :

比如这个程序:

int main(void) { char buffer[]="abcdefg"; memcpy(buffer, buffer+2 ,3); //buffer+2(从c开始 长度3个 cde) printf("%s", buffer); }
这个结果为: cdedefg .

再看下面这个程序:

int main(void) { char buffer[]="abcdefg"; memcpy(buffer+2, buffer ,3); //如果你幸运的话 会出现 abcab[d]fg 中括号是随机值 printf("%s", buffer); }这里的memcpy就需要用 memmove的实现方式来代替 。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值