1. 程式人生 > >memset+strcpy+strncpy的函式詳解以及字元陣列輸出的特殊情況

memset+strcpy+strncpy的函式詳解以及字元陣列輸出的特殊情況

memset:

標頭檔案:#include在<string.h>

原型:   void *memset(void *s, int c, size_t n);

將已開闢記憶體空間的s所指向的每一塊記憶體中的每一個位元組全部設定為c為ASCII碼!!!

The  memset()  function  fills  the  first  n  bytes of the memory area  pointed to by s with the constant byte c

原型函式:

void* memset(void* s, int c, size_t n){
                     unsigned char* p = (unsigned char*) s;

                     while (n > 0) {
                                *p++ = (unsigned char) c;
                                  --n;
                      }

                     return s;
           }


1, memset常被用來做初始化陣列

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

int main()
{
        int i;
        char p[5];
        for(i = 0; i<5;i++){
                printf("%c\n", p[i]);
        }
        return 0;
}

執行結果:

可以看到我們的中的p[5]陣列沒有初始化的話,會得到一些奇怪的東西,則可能會導致我們程式的錯誤執行,如果我們不初始化的話!!!

為了避免這種情況,我們可以加入:

memset(p, '0', strlen(p));
        for(i = 0; i<5;i++){
                printf("%c\n", p[i]);                                                                                                           
        }
這樣,我們看的話,就可以得到正確的結果了,

但是要注意的是,memset的第二個引數是char型別的

如果寫成這樣:memset(p,  0  ,  strlen(p))

那麼得到的結果是:什麼也看不到,只是因為0對應的ascii碼是空格,而‘0’對應的是48

程式二:

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

int main()
{
        int i;
        char p[5] = "1234";
        p[4] = 0;
        printf("%c    %d\n", p[4], p[4]);
        p[2] ='0';
        printf("%c    %d\n", p[2], p[2]);
        printf("after:%s\n", p);
        return 0;
}
執行結果:


可以看出,我們先將p[4]賦值為0,從輸出結果可以直觀的看到:p [4]的字元輸出為空格,整形輸出為0

p[2]賦值為字元0,字元輸出為0,整形輸出為48

值得我們注意的是:

有些特殊的賦值,如:

 p[3] = 0;
 printf("%c    %d\n", p[3], p[3]);
輸出:

           0

0         48

after:120

p[3] = ‘\n’;
printf("%c    %d\n", p[3], p[3]);
輸出:

           10

0         48

after:120

p[3] = ‘ ’;             //賦值一個空格                           
 printf("%c    %d\n", p[3], p[3]);
輸出:

           32

0         48

after:120

p[3] = ‘\t’;
printf("%c    %d\n", p[3], p[3]);
輸出:

                               9

0          48

after:  120

可以看出對於字元陣列以格式化輸出時:當碰到ascii為0,空格(ascii為32),換行符(ascii為10),tab鍵(ascii為9)都會輸出停止的                 

還有就是:

char p[5] = "1234";
p[4] = 0;
printf("%c    %d\n", p[4], p[4])
char *p = "1234";
p[4] = 0;
printf("%c    %d\n", p[4], p[4]);
當我們執行第一個的時候,是沒有問題的,可以得到一定的結果

但是,當我們執行第二個程式的時候,執行是會出錯,顯示段錯誤 (核心已轉儲)

分析可知,是因為p所指向的是一個常量字串,不可以直接或者簡介的改變裡面的內容

轉為正題:

2,這個函式也多用於socket中用於清空陣列,如我們經常這樣用:memset(buffer, 0, sizeof(buffer))

       而且這個函式還方便的用於清空結構型別的陣列或變數(轉:)

struct sample_struct
{
char csName[16];
int iSeq;
int iType;
};

對於變數:
struct sample_strcut stTest;

一般情況下,清空stTest的方法:

stTest.csName[0]='/0';
stTest.iSeq=0;
stTest.iType=0;

用memset就非常方便:
memset(&stTest,0,sizeof(struct sample_struct));

如果是陣列:

struct sample_struct TEST[10];

memset(TEST,0,sizeof(struct sample_struct)*10);

3, 引數問題:

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

int main()
{

        char p[5];
        p[3] = 'a';p[4]= 'b';                                                                                                                   
        memset(p, '0'  , 3);
        printf("%s   ,\n", p);

        return 0;
}
執行結果:

看得出來,對於memset置0的時候,只對前三項初始化了,所以他們不影響後面兩項,至於輸出結果後面出現的(007f),則應該是對於上面這種把p的記憶體數限定的情況下,但是在結束的時候還沒有找到退出的條件的,(即上面提到的幾種情況)

char p[5] ;
        printf("%s   ,\n", p);
多次執行結果如下:




strcpy:

標頭檔案:#include <string.h>

char *strcpy(char *dest,char *src);把從src地址開始且含有NULL結束符的字串賦值到以dest開始的地址空間,返回dest(地址中儲存的為複製後的新值)。要求:src和dest所指記憶體區域不可以重疊且dest必須有足夠的空間來容納src的字串

原始檔:

char *strcpy(char *strDest, const char *strSrc);//strDest為目標,strSrc為源
{
     assert((strDest!=NULL) && (strSrc !=NULL)); //如果兩個為空則不用複製,直接中止
     char *address = strDest;       //用address指向strDest開始地址
     while( (*strDest++ = * strSrc++) != ‘\0’ ) //複製,直到源串結束; 
        NULL ; //空操作
     return address ;    //返回strDest開始地址                       
     }
}
如:

char  a[50], b[100];

strcpy(a,   b,)這裡將b的內容賦值給a,如果b中的(‘\0’)出現在前50個裡面,那麼就沒有問題,如果在50個以後,那麼就會造成記憶體洩露

strcpy和memcpy都是標準C庫函式,它們有下面的特點。
strcpy提供了字串的複製。即strcpy只用於字串複製,並且它不僅複製字串內容之外,還會複製字串的結束符。

已知strcpy函式的原型是:char* strcpy(char* dest, const char* src);
memcpy提供了一般記憶體的複製。即memcpy對於需要複製的內容沒有限制,因此用途更廣。
void *memcpy(void *memTo, const void *memFrom, size_t size)
{
  if((memTo == NULL) || (memFrom == NULL)) //memTo和memFrom必須有效
         return NULL;
  char *tempFrom = (char *)memFrom;             //儲存memFrom首地址
  char *tempTo = (char *)memTo;                  //儲存memTo首地址      
  while(size -- > 0  &&  *tempFrom++!='\0')                //迴圈size次,複製memFrom的值到memTo中
         *tempTo++ = *tempFrom++ ;  
  return memTo;
}

strcpy和memcpy主要有以下3方面的區別。
1、複製的內容不同。strcpy只能複製字串,而memcpy可以複製任意內容,例如字元陣列、整型、結構體、類等。
2、複製的方法不同。strcpy不需要指定長度,它遇到被複制字元的串結束符"\0"才結束,所以容易溢位。memcpy則是根據其第3個引數決定複製的長度。
3、用途不同。通常在複製字串時用strcpy,而需要複製其他型別資料時則一般用memcpy

程式4:

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

int main()
{

        char a[5]= "1234";
        char b[5]= "abcd";

        b[3]= '\0';
        strcpy(a, b);
        printf("%s\n", a);
        memcpy(a, b, 5);
        printf("%s\n", a);
        return 0;
}
執行結果:

abc

abc

可以看出:兩者的賦值都是碰到('\0')就退出