atoi,itoa,strcpy, strcmp,strcpy, strcpy_s, memc...

strcpy()、strlen()、memcpy()、memmove()、memset()的實現
ios


strcpy(), 字符串拷貝.
char *strcpy(char *strDest, const char *strSrc)
{
    assert((strDest!=NULL) && (strSrc !=NULL));
    char *address = strDest;     
    while( (*strDest++ = * strSrc++!= '\0'
        NULL ; 
    return address ;
}


strlen,
c++

第一種方法:
int strlen( const char *str)
{
    assert(str != NULL);
     int len = 0;
     while((*str++) !=  '\0')
        len++;
     return len;
}
第二種方法:
int strlen( const char *str)
{
    assert(str != NULL);
     const char *p = str;
     while((*p++) !=  '\0');
     return p - str - 1;
}
第三種方法:
int strlen( const char* str)
{
     if (str[0] ==  '\0')
         return 0;
     else
         return strlen((char *)(&str[0]+1))+1;
}


memcpy, 拷貝不重疊的內存塊 
 void *memcpy(void* pvTo, void* pvFrom, size_t count) 
 {
     assert(pvTo != NULL && pvFrom != NULL);
     byte* pbTo = (byte*)pvTo;
     byte* pbFrom = (byte*)pvFrom;
     
     assert(pbTo>=pbFrom+
count || pbFrom>=pbTo+count);
     while(
count-- > )
         *pbTo++ == *pbFrom++;
     return pvTo;
}


void* memmove(void *dest, const void *src,size_t count
{ 
     if (
count == return 
     if (dest == NULL) return 
     if (src == NULL)    return 
     char *psrc = (char*)src; 
     char *pdest = (char*)dest; 
     if((pdest <= psrc)  ||  (pdest >= psrc +
count))  
     {
        
 
         while (count--)
             *pdest++ = *psrc++;
     }
 
     else 
     {
        
 
         pdest += count - 1;
         psrc +=
 count - 1;
         while (
count--)
             *pdest-- = *psrc--;
     }
 
     return dest;
}


memset:把buffer所指內存區域的前count個字節設置成字符c
void * memset(void* buffer, int c, int count)
{
    char* pvTo=(char*)buffer;
    assert(buffer != NULL);
    while(count-- > )
        *pvTo++=(char)c;
    return buffer;
}


分析:
memmove、memcpy和memccpy三個函數都是內存的拷貝,從一個緩衝區拷貝到另外一個緩衝區。
memmove(void *dest,void*src,int count)
memcpy(void *dest,void *src,int count)
memccpy(void*dest,void*src,int ch,int count)
表頭文件: #include <string.h>
定義函數: void *memcpy(void *dest, const void *src, size_t n)
函數說明: memcpy()用來拷貝src所指的內存內容前n個字節到dest所指的內存地址上。與strcpy()不一樣的是,memcpy()會完整的複製n個字節,不會由於遇到字符串結束'\0'而結束
返回值:   返回指向dest的指針
表頭文件: #include <string.h>
定義函數: void *memccpy(void *dest, const void *src, int c, size_t n);
函數說明: memccpy()用來拷貝src所指的內存內容前n個字節到dest所指的地址上。與memcpy()不一樣的是,memccpy()若是在src中遇到某個特定值(int c)當即中止複製。
返回值:   返回指向dest中值爲c的下一個字節指針。返回值爲0表示在src所指內存前n個字節中沒有值爲c的字節。
表頭文件: #include <string.h>
定義函數: void *memmove(void *dest, const void *src, size_t n);
函數說明:memmove()是從一個緩衝區移動到另外一個緩衝區中。 
返回值:   返回指向dest指針。
當dest <= src-count 或dest >= src+count時,以上三個函數均不會產生覆蓋問題,即源數據不會被更改。
若不在以上範圍內,則源數據會被更改。 不妨用個小程序來測一下:

# include <string.h>
# include <stdio.h>

int main()
{
    int i = 0;
    int a[10];
 
    for(i; i < 10; i++)
    {
        a[i] = i;
   }

   memcpy(&a[4], a, sizeof(int)*6);
 
   for(i = 0; i < 10; i++)
   {
       printf("%d ",a[i]);
   }
 
   printf("\n");
   return 0;
 }
 
將上面代碼gcc以後再運行,結果爲:0 1 2 3 0 1 2 3 0 1 。
再把第13行改爲:memmove(&a[4], a, sizeof(int)*6),從新gcc再運行,結果爲:0 1 2 3 0 1 2 3 4 5 !
呵呵,二者的區別出現了。不過其實這樣還不夠,繼續修改13行: memmove(a, &a[4], sizeof(int)*6) //也就是將源、目的置換一下而已。從新gcc編譯再運行,結果爲:4 5 6 7 8 9 6 7 8 9 。
還不夠,繼續修改13行爲: memcpy(a, &a[4], sizeof(int)*6); gcc並運行,結果仍爲: 4 5 6 7 8 9 6 7 8 9 !
至此真相已經大白了。對比上面四個結果,不可貴出如下結論:
1. 當 src 和 dest 所指內存區有重疊時,memmove 相對 memcpy 能提供保證:保證能將 src 所指內存區的前 n 個字節正確的拷貝到 dest 所指內存中;
2. 當 src 地址比 dest 地址低時,二者結果同樣。換句話說,memmove 與 memcpy 的區別僅僅體如今 dest 的頭部和 src 的尾部有重疊的狀況下;


_____________________________
1.//整數轉換成字符串itoa函數的實現 
#include "stdafx.h"

#include <iostream>小程序

using namespace std;數組

void itoaTest(int num,char str[] )安全

{函數

       int sign = num,i = 0,j = 0;spa

       char temp[11];指針

       if(sign<0)//判斷是不是一個負數orm

       {內存

              num = -num;

       };

       do

       {

              temp[i] = num%10+'0';        

              num/=10;

              i++;

       }while(num>0);

       if(sign<0)

       {

              temp[i++] = '-';//對於負數,要加以負號

       }

       temp[i] = '\0';

       i--;

       while(i>=0)//反向操做

       {

              str[j] = temp[i];

              j++;

              i--;

       }

       str[j] = '\0';

}

2. //字符串轉換成整數atoi函數的實現

int atoiTest(char s[])

{

       int i = 0,sum = 0,sign;    //輸入的數前面可能還有空格或製表符應加判斷

       while(' '==s[i]||'\t'==s[i])

       {

              i++;

       }

       sign = ('-'==s[i])?-1:1;

       if('-'==s[i]||'+'==s[i])

       {

              i++;

       }

       while(s[i]!='\0')

       {

              sum = s[i]-'0'+sum*10;

              i++;

       }    

       return sign*sum;

}

3.//字符串拷貝函數

#include "stdafx.h"

#include <assert.h>

#include <string.h>

#include <iostream>

using namespace std;

char *srcpy(char *dest,const char *source)

{

       assert((dest!=NULL)&&(source!=NULL));

       char *address = dest;

       while(*source!='\0')

       {

              *dest++=*source++;

       }

       *dest = '\0';

       return address;

}

 4.//判斷輸入的是不是一個迴文字符串

#include "stdafx.h"

#include <string.h>

#include <iostream>

using namespace std;

//方法一:藉助數組

bool isPalindrome(char *input)

{

       char s[100];

       strcpy(s,input);

       int length = strlen(input);

       int begin = 0,end = length-1;

       while(begin<end)

       {

              if(s[begin]==s[end])

              {

                     begin++;

                     end--;

              }

              else

              {

                     break;

              }           

       }

       if(begin<end)

       {

              return false;

       }    

       else

       {

              return true;

       }     

}

//方法二:使用指針

bool isPalindrome2(char *input)

{

       if(input==NULL)

              return false;

       char *begin = input;

       char *end = begin+strlen(input)-1;

       while(begin<end)

       {

              if(*begin++!=*end--)

                     return false;

       }

       return true;

}

 int main(int argc, char* argv[])

{

       char *s ="1234554321";

       if(isPalindrome(s))

       {

              cout<<"True"<<endl;

       }

       else

       {

              cout<<"Fasle"<<endl;

       }

        if(isPalindrome2(s))

       {

              cout<<"True"<<endl;

       }

       else

       {

              cout<<"Fasle"<<endl;

       }

       cin.get();

        return 0;

}

5.//不使用庫函數,編寫函數int strcmp(char *source, char *dest),若相等返回0,不然返回-1

int strcmp(char *source, char *dest)

{

       assert(source != NULL && dest != NULL);

       while(*source++==*dest++)

       {

              if(*source=='\0'&&*dest=='\0')

                     return 0;        

       }

       return -1;

}



——————————————————————————————

一:strcmp,_stricmp
strcmp("ha","he")是能夠的。
可是以下代碼: 
string   str1   =   "ha"; 
string   str2   =   "he"; 
strcmp(str1,   str2); 
會產生以下的ERROR:
由於:
1)int   strcmp(const   char*   str1,   const   char*   str2); 
這個函數是C標準庫的函數,處理的是C風格0結尾字符數組字符串。 
C++標準庫中的string類有能夠直接使用的<,>,<=,>=,==,!=運算符,一般也用不到這個函數
或者說:   strcmp()處理的是C風格的字符串。 而你用的是string類,2者是不一樣的。

但能夠經過string成員函數string::c_str()轉換成char*類型。象這樣調用:strcmp(str1.c_str(),   str2.c_str())  

int ret = strcmp("aa", "ad"); //-1
int ret = _stricmp("aa", "ad");//-3
int ret = _stricmp("Aa","aD"); //-3
ret = strcmp("ad", "aa"); //1

ret = strcmp("aa", "aa"); //0
ret = _stricmp("aa", "AA"); //0

ret = strcmp("aa", "aad"); //-1

strcmp(s1,s2)與_stricmp(s1,s2)
相同點:處理的都是C格式的字串,若是比較C++格式的string類型字串時,可使用string.c_str()來轉換成C格式的字串再進行比較。
不一樣點:1)前者區分大小寫,後者不區分大小寫
              2)前者返回-1,0,1,後者返回字串實際差值,即整形數:負數,零,正數


二:strcpy_s&&strcpy的比較
以下所示:
char szBuf[2] = {0};
strcpy_s(szBuf, 2, "12131"); //注意第二個參數是申清空間的大小
strcpy(szBuf, "12131");   
上述代碼,明顯有緩衝區溢出的問題。 使用strcpy_s函數則會拋出一個異常。而使用strcpy函數的結果

則未定,由於它錯誤地改變了程序中其餘部分的內存的數據,可能不會拋出異常但致使程序數據錯誤,

也可能因爲非法內存訪問拋出異常。使用新的加強安全的CRT函數有什麼好處呢?簡單地說,新的函數

增強了對參數合法性的檢查以及緩衝區邊界的檢查,若是發現錯誤,會返回errno或拋出異常。

老版本的這些CRT函數則沒有那麼嚴格的檢查與校驗,若是錯誤地傳輸了參數或者緩衝區溢出,

那麼錯誤並不能被馬上發現,對於定位程序錯誤也帶來更大困難。

//--------------------strcpy,strcpy_s------------------------------------------

//原型:extern char *strcpy(char *dest,char *src);
//功能:把src所指由NULL結束的字符串複製到dest所指的數組中。
//說明:src和dest所指內存區域不能夠重疊且dest必須有足夠的空間來容納src的字符串,返回指向dest的指針。

//strcpy用法:
// 若源長<目標長 --->OK。
//將源串COPY至目標串(包括結尾符),其它字節保持不變,
//若源長>目標長 --->溢出報錯。
//將源串COPY至目標串(包括結尾符),但目標串過短,下標越界而溢出,不正常的字串顯然會在致使運行時異常,
//使用原則總結:使用時保證源長<目標長

//strcpy_s用法:
//若源長<目標長 sizeof([min, max])--->OK,但自定義拷貝的字串長度超過目標長度時,會因下標越界而致使運行異常
//若源長>目標長 sizeof任何一方都會發生運行異常,
//(有多是編譯器在copy前會先檢查二者長度,
//若是源串較長便會發生告警而退出,所以後續使用sizeof(strlen(strDest)=0)語句已無效)
//使用原則總結: 1,使用時保證:源長<目標長,2,長度不能超出szDest長度,建議使用sizeof(szDest)

#include <iostream>
#include <string>
using namespace std;

#define STRCPY_TEST 0
#define LEN_STR 15

void main()
{
char szDest[10];
char szSrc_shorter[] = "1234";
char szSrc_longer[] ="123456789012";

cout<<"char szDest[10];"<<endl;
cout<<"char szSrc_shorter[] = \"1234\";"<<endl;
cout<<"char szSrc_longer[] = \"123456789012345\";"<<endl;

#if (0 == STRCPY_TEST)
cout<<"\n[OK] strcpy(szDest, szSrc_shorter);\nstrDest[1~15] = ";
strcpy(szDest, szSrc_shorter);
for(int i = 0; i < LEN_STR; i++)
{
   cout<<szDest[i]<<", ";
}
cout<<endl<<"szDest = "<<szDest<<endl;

strcpy(szDest, szSrc_longer);
cout<<"\n[NG] strcpy(szDest, szSrc_longer);\nstrDest[1~15] = ";
for(int i = 0; i < LEN_STR; i++)
{
   cout<<szDest[i]<<", ";
}
cout<<endl<<"szDest = "<<szDest<<endl;

#else

cout<<"\n[OK] strcpy_s(szDest, sizeof(szSrc_shorter), szSrc_shorter);\nstrDest[1~15] = ";
strcpy_s(szDest, sizeof(szSrc_shorter), szSrc_shorter);
for(int i = 0; i < LEN_STR; i++)
{
   cout<<szDest[i]<<", ";
}
cout<<endl<<"szDest = "<<szDest<<endl;

cout<<"[OK] strcpy_s(szDest, sizeof(szDest), szSrc_shorter);\nstrDest[1~15] = ";
strcpy_s(szDest, sizeof(szDest), szSrc_shorter); 
for(int i = 0; i < LEN_STR; i++)
{
   cout<<szDest[i]<<", ";
}
cout<<endl<<"szDest = "<<szDest<<endl;


cout<<"[NG] strcpy_s(szDest, sizeof(szSrc_longer), szSrc_longer);\nstrDest[1~15] = ";
strcpy_s(szDest, sizeof(szSrc_longer), szSrc_longer); 
for(int i = 0; i < LEN_STR; i++)
{
   cout<<szDest[i]<<", ";
}
cout<<endl<<"szDest = "<<szDest<<endl;

cout<<"\n[NG] strcpy_s(szDest, sizeof(szDest), szSrc_longer);\nstrDest[1~15] = ";
strcpy_s(szDest, sizeof(szDest), szSrc_longer); 
szDest[sizeof(szDest) - 1] = 0;
for(int i = 0; i < LEN_STR; i++)
{
   cout<<szDest[i]<<", ";
}
cout<<endl<<"szDest = "<<szDest<<endl;

#endif

}

輸出:(NG部分的輸出已無心義,能夠不看)

(1)STRCPY_TEST==0
char szDest[10];
char szSrc_shorter[] = "1234";
char szSrc_longer[] = "123456789012345";
[OK] strcpy(szDest, szSrc_shorter);
strDest[1~15] = 1, 2, 3, 4, , ? ? ? ? ? ? ? ? ? ?

szDest = 1234
[NG] strcpy(szDest, szSrc_longer);
strDest[1~15] = 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, , ? ?

(2)STR_CPY_TEST<>0
char szDest[10];
char szSrc_shorter[] = "1234";
char szSrc_longer[] = "123456789012345";

[OK] strcpy_s(szDest, sizeof(szSrc_shorter), szSrc_shorter);
strDest[1~15] = 1, 2, 3, 4, , ? ? ? ? ? ? ? ? ? ?

szDest = 1234

[OK] strcpy_s(szDest, sizeof(szDest), szSrc_shorter);
strDest[1~15] = 1, 2, 3, 4, , ? ? ? ? ? ? ? ? ? ?

szDest = 1234

[NG] strcpy_s(szDest, sizeof(szSrc_longer), szSrc_longer);
strDest[1~15] = 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, , ? ?

szDest = 123456789012

[NG] strcpy_s(szDest, sizeof(szDest), szSrc_longer);
strDest[1~15] = 請按任意鍵繼續. . .

//-------------------------------memcpy-------------------------------------
// 原型:extern void *memcpy(void *dest, void *src, unsigned int count);
// 原理:由src所指內存區域複製count個字節到dest所指內存區域。
// 說明:src和dest所指內存區域不能重疊,函數返回指向dest的指針。
//strncpy() 是處理的字符串(遇零結束),
//memcpy() 是處理一個緩衝區(void*類型的),
//以字串類型的memcpy用法爲例:
//源長<目標長時,第3個參數使用任何一方的size,效果都同樣
//源長>目標長時,第3個參數用sizeof(strSrc),會形成下標越界,而使目標串溢出,從而致使運行異常
//                       第3個參數用sizeof(strDest), 末尾字符(\0)沒有被COPY,輸出字串會有亂碼,
//                       但不會運行異常,若是不考慮完整性,可使用strDest[sizeof(strDest)-1]=0截取前半部
//使用原則總結:1)保證源長<目標長;2)第3個參數推薦使用sizeof(strDest) 另外若是字串是指針要考慮一下sizeof的反作用

#include <iostream>
#include <string>
using namespace std;

void main()
{
char szSrc_shorter[] = "Good";
char szSrc_longer[] = "Have a Good Day!";
char szDest[10];

cout<<"char szSrc_shorter[] = \"Good\";"<<endl;
cout<<"char szSrc_longer[] = \"Have a Good Day!\";"<<endl;
cout<<"char szDest[10];"<<endl<<endl;

memcpy(szDest, szSrc_shorter, sizeof(szSrc_shorter));//<=>
//memcpy(szDest, szSrc_shorter, sizeof(szDest)); 
cout<<"[OK] memcpy(szDest, szSrc_shorter, sizeof(szSrc_shorter));";
cout<<"<=>\n[OK] memcpy(szDest, szSrc_shorter, sizeof(szDest));\nszDest[0~20] = \n";
for (int i = 0; i < 20; i++)
   cout<<szDest[i]<<", ";
cout<<endl<<"szDest = "<<szDest<<endl;

memcpy(szDest, szSrc_longer, sizeof(szDest));
cout<<"\n[OK] memcpy(szDest, szSrc_longer, sizeof(szDest));\nszDest[sizeof(szDest) - 1] = 0; \nszDest[0~20] = \n";
szDest[sizeof(szDest) - 1] = 0;
for (int i = 0; i < 20; i++)
   cout<<szDest[i]<<", ";
cout<<endl<<"szDest = "<<szDest<<endl;

memcpy(szDest, szSrc_longer, sizeof(szSrc_longer));
cout<<"\n[NG] memcpy(szDest, szSrc_longer, sizeof(szSrc_longer));\nszDest[sizeof(szDest) - 1] = 0; \nszDest[0~20] = \n";
szDest[sizeof(szDest) - 1] = 0;
for (int i = 0; i < 20; i++)
   cout<<szDest[i]<<", ";
cout<<endl<<"szDest = "<<szDest<<endl;

}


輸出:(NG部分的輸出沒有意義,能夠不看):

char szSrc_shorter[] = "Good";
char szSrc_longer[] = "Have a Good Day!";
char szDest[10];

[OK] memcpy(szDest, szSrc_shorter, sizeof(szSrc_shorter));<=>
[OK] memcpy(szDest, szSrc_shorter, sizeof(szDest));
szDest[0~20] =
G, o, o, d, , ?.....?(15個?)

szDest = Good

[OK] memcpy(szDest, szSrc_longer, sizeof(szDest));
szDest[sizeof(szDest) - 1] = 0;
szDest[0~20] =
H, a, v, e, , a, , G, o, , ? ...?(10個?)

szDest = Have a Go

[NG] memcpy(szDest, szSrc_longer, sizeof(szSrc_longer)); szDest[sizeof(szDest) - 1] = 0; szDest[0~20] = H, a, v, e, , a, , G, o, , d, , D, a, y, !, , ? ? ? szDest = Have a Go

相關文章
相關標籤/搜索