內(nèi)存操作函數(shù)

字符串是以'\0'作為結(jié)束符,所以字符串函數(shù)夜市根據(jù)這一特性編寫的,這就造成字符串函數(shù)無法處理字符串內(nèi)部有'\0'的數(shù)據(jù),這時可以使用內(nèi)存操作函數(shù),頭文件依舊是<string.h>


內(nèi)存操作函數(shù)

memcpy

void *memcpy( void *to, const void *from, size_t count );
功能:函數(shù)從from中復(fù)制count 個字符到to中,并返回to指針。 如果to 和 from 重疊,則函數(shù)行為不確定。

{
    char str[] = "welcom\0 to Beijing";
    char ch[] = "aaaaaaaaaaaaaaaaaa";
    char c[] = "aaaaaaaaaaaaaaaaaa";
    memcpy(ch,str,sizeof(str));
    strcpy(c,str);
    //打印數(shù)據(jù)查看有無復(fù)制成功
    printf("ch[8] = %c\n",ch[8]);
    printf("c[8] = %c\n",c[8]);

    return 0;
}

結(jié)果

ch[8] = t
c[8] = a

可以看到strcpy函數(shù)并沒有復(fù)制成功,只是復(fù)制到'\0'.就結(jié)束,看到memcpy函數(shù)已經(jīng)復(fù)制成功了后面的字符數(shù)據(jù)內(nèi)容發(fā)生改變。所以,如果字符串內(nèi)部有'\0',要使用內(nèi)存操作函數(shù),不然會操作字符串失敗,導(dǎo)致運行出錯。這個內(nèi)存操作函數(shù)也可以用于數(shù)組復(fù)制。

const int count = 10;
char ch[] = "0123456789";
char c[] = "0123456789";
char str[8];
//memcpy不檢查源能存放的數(shù)據(jù)大小
memcpy(str,ch,count*sizeof(char));
printf("%s\n",str);
printf("%s\n",c);

結(jié)果

012345678923456789
8923456789
過程

可以看到,memcpy函數(shù)不檢查源的數(shù)據(jù)大小和目標(biāo)的數(shù)據(jù)大小,造成其他變量的值發(fā)生變化,運行時發(fā)生不可預(yù)測的結(jié)果。建議檢查復(fù)制的數(shù)據(jù)大小,避免造成不必要的錯誤。

//舊版本的memecpy源碼
void *my_memcpy(void *dest, const void *src, size_t count)
{
    char *tmp = dest;
    const char *s = src;

    while (count--)
        *tmp++ = *s++;
    return dest;
}
int main()
{
    int a[10] = {1,2,3,4,5,6,7,8,9};
    //數(shù)組a的a+1數(shù)據(jù)后2位復(fù)制到a
    my_memcpy(a+1,a,sizeof(int)*2);
    printf("%s\n",ch);
    int i;
    for(i = 0; i < 10; i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    return 0;
}

結(jié)果

1 1 1 4 5 6 7 8 9 0

這里看到數(shù)據(jù)不對,不應(yīng)該是1 1 2 4 5 6 7 8 9 0才對嗎,這是因為源與目標(biāo)地址重疊,造成重疊的數(shù)據(jù)可能數(shù)據(jù)會被修改,沒有被封保存,所以結(jié)果不可預(yù)測。


memcpy

如果源與目標(biāo)地址有重疊,就有兩種情況:
1.恰巧重疊部分的數(shù)據(jù)與前面數(shù)據(jù)重復(fù),修改后數(shù)據(jù)仍然一樣
2.兩者數(shù)據(jù)沒有關(guān)系,造成重疊部分?jǐn)?shù)據(jù)被修改后原值丟失,memcpy后數(shù)據(jù)有變。
所以 如果to 和 from 重疊,則函數(shù)行為不確定。
但是現(xiàn)在的源碼已經(jīng)改進(jìn),源與目標(biāo)地址可以重疊,但是為了穩(wěn)定性,建議在此種情況使用mommove函數(shù)。

memmove

void *memmove( void *to, const void *from, size_t count );
功能: 與mencpy相同,不同的是當(dāng)to 和 from 重疊,函數(shù)正常仍能工作。

int a[10] = {1,2,3,4,5,6,7,8,9};
memmove(b+1,b,sizeof(int)*2);
int i;
for(i = 0; i < 10; i++)
{
    printf("%d ",b[i]);
}
printf("\n");

結(jié)果

1 1 2 4 5 6 7 8 9 0

源與目標(biāo)重疊時,建議使用這個函數(shù)。memmove函數(shù)會比memcpy效率低點,因為memmove是先復(fù)制一份數(shù)據(jù),然后再復(fù)制到目標(biāo)。

memchr

void *memchr( const void *buffer, int ch, size_t count );
功能:函數(shù)在buffer指向的數(shù)組的count個字符的字符串里查找ch 首次出現(xiàn)的位置。返回一個指針,指向ch 在字符串中首次出現(xiàn)的位置, 如果ch 沒有在字符串中找到,返回NULL。

char str[] = "welcom to Beijing";
char *ptr = memchr(str,'l',sizeof(char)*10);
printf("%c\n",*ptr);

結(jié)果

l

這個函數(shù)使用與strchr差不多,只是memchr不會因'\0',停止。

memset

void *memset( void *buffer, int ch, size_t count );
功能: 函數(shù)拷貝ch 到buffer 從頭開始的count 個字符里, 并返回buffer指針。 memset() 可以應(yīng)用在將一段內(nèi)存初始化為某個值。

int array[10];
memset(array,0,sizeof(array));
int i;
for(i = 0; i < 10; i++)
{
    printf("%d ",array[i]);
}
printf("\n");

結(jié)果

0 0 0 0 0 0 0 0 0 0

這是一個將數(shù)組置為某個值的快捷方法。

memcmp

int memcmp( const void *buffer1, const void *buffer2, size_t count );
功能:函數(shù)比較buffer1 和 buffer2的前count 個字符。

char str[] = "Hello";
char ch[] = "welcom";
int cmp = memcmp(str,ch,sizeof(char)*4);

用法簡單,和strcmp效果差不多,但是memcmp支持處理的數(shù)據(jù)類型更多。

總結(jié)

內(nèi)存操作函數(shù)不會檢查源的數(shù)據(jù)大小,只會根據(jù)使用者傳入的count來操作,所以要避免傳入的count大于源地址的數(shù)據(jù)大小,也不要大于目標(biāo)地址的數(shù)據(jù)大小。如果源與目標(biāo)存在重疊,建議使用mommove,雖然memcpy已經(jīng)改進(jìn),但為了穩(wěn)定性,還是使用mommove。


微信號
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容