zoukankan      html  css  js  c++  java
  • 纯C 字符串操作函数 实现 (strcpy, strncpy, memcpy, memset, strcat, strlen ... ) .

    摘自:http://blog.csdn.net/crazyjixiang/article/details/6720236#

    实现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 */
    }


    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的实现方式来代替 。

  • 相关阅读:
    glog Windows Visual Studio 2013 编译项目
    Git Tag管理发行版本
    Ubuntu 16.04环境中读取XBOX 360手柄信息
    GCC 中 的pie和fpie选项
    CMakeLists.txt 常用指令说用
    chrome无法访问github.com
    删除前n天的数据
    shell(9)秒转换为时分秒
    Drools规则引擎实践直白总结
    空闲时间研究一个小功能:winform桌面程序如何实现动态更换桌面图标
  • 原文地址:https://www.cnblogs.com/CodeWorkerLiMing/p/12007609.html
Copyright © 2011-2022 走看看