memset與初始化


定義變量時往往要進行初始化,尤其是數組和結構體這種占用內存大的數據結構。在使用數組的時候經常因為沒有初始化而產生“燙燙燙燙燙燙”這樣的野值,俗稱“亂碼”。

PS:當然,也有個別例外的。比如strtol函數中的第二個參數,對於這個參數,我們只需要定義一個字符指針變量,並且不需要賦初值,然后將字符指針的地址放到strtol函數的第二個參數即可。參考:https://www.cnblogs.com/cyx-b/p/12491043.html

每種類型的變量都有各自的初始化方法,memset() 函數可以說是初始化內存的“萬能函數”,通常為新申請的內存進行初始化工作。它是直接操作內存空間,mem即“內存”(memory)的意思。該函數的原型為:

#include <string.h>
void *memset(void *s, int c, unsigned long n);

函數的功能是:將指針變量 s 所指向的前 n 字節的內存單元用一個“整數” c 替換,注意 c 是 int 型。s 是 void* 型的指針變量,所以它可以為任何類型的數據進行初始化。

memset() 的作用是在一段內存塊中填充某個給定的值。因為它只能填充一個值,所以該函數的初始化為原始初始化,無法將變量初始化為程序中需要的數據。用memset初始化完后,后面程序中再向該內存空間中存放需要的數據。

memset 一般使用“0”初始化內存單元,而且通常是給數組或結構體進行初始化。一般的變量如 char、int、float、double 等類型的變量直接初始化即可,沒有必要用 memset。如果用 memset 的話反而顯得麻煩。

當然,數組也可以直接進行初始化,但 memset 是對較大的數組或結構體進行清零初始化的最快方法,因為它是直接對內存進行操作的。

這時有人會問:“字符串數組不是最好用'\0'進行初始化嗎?那么可以用 memset 給字符串數組進行初始化嗎?也就是說參數 c 可以賦值為'\0'嗎?”可以的。雖然參數 c 要求是一個整數,但是整型和字符型是互通的。但是賦值為 '\0' 和 0 是等價的,因為字符 '\0' 在內存中就是 0。所以在 memset 中初始化為 0 也具有結束標志符 '\0' 的作用,所以通常我們就寫“0”。

memset 函數的第三個參數 n 的值一般用 sizeof()  獲取,這樣比較專業。注意,如果是對指針變量所指向的內存單元進行清零初始化,那么一定要先對這個指針變量進行初始化,即一定要先讓它指向某個有效的地址。而且用memset給指針變量如p所指向的內存單元進行初始化時,n 千萬別寫成 sizeof(p),這是新手經常會犯的錯誤。因為 p 是指針變量,不管 p 指向什么類型的變量,sizeof(p) 的值都是 4。

在網絡編程中,常常有各種各樣花里胡哨的結構體,因此常會用memset來初始化。

比如下面這個例子:

struct sockaddr_in ServerAddr;
ServerAddr.sin_family = AF_INET;    //IPV4
ServerAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);   //IP地址
ServerAddr.sin_port = htons(PORT);    //端口號
memset(ServerAddr.sin_zero, 0x00, 8);   //零填充

或者也可以像下面這樣:

struct sockaddr_in ServerAddr;
memset(&ServerAddr, 0, sizeof(ServerAddr));
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
ServerAddr.sin_port = htons(PORT);

PS:關於sockaddr_in可以參考https://www.cnblogs.com/cyx-b/p/12450811.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM