簡體   English   中英

為什么 memset() 錯誤地初始化 int?

[英]Why is memset() incorrectly initializing int?

為什么以下程序的輸出是84215045

int grid[110];
int main()
{
    memset(grid, 5, 100 * sizeof(int));
    printf("%d", grid[0]);
    return 0;
}

memset將目標緩沖區的每個字節設置為指定值。 在您的系統上,一個int是四個字節,在調用memset之后每個字節是 5。 因此, grid[0]的值為0x05050505 (十六進制),即十進制的84215045

一些平台為memset提供了替代 API,可以將更廣泛的模式寫入目標緩沖區; 例如,在 OS X 或 iOS 上,您可以使用:

int pattern = 5;
memset_pattern4(grid, &pattern, sizeof grid);

獲得您似乎期望的行為。 你的目標是什么平台?

在 C++ 中,您應該只使用std::fill_n

std::fill_n(grid, 100, 5);
memset(grid, 5, 100 * sizeof(int));

您正在設置 400 個字節,從(char*)grid開始,到(char*)grid + (100 * sizeof(int))結束,到值5 (這里需要強制轉換,因為memset處理字節,而指針算術交易objects

十六進制的842150450x05050505 由於int (在您的平台/編譯器/等上)由四個字節表示,因此當您打印它時,您會得到“四個五”。

memset是關於設置字節,而不是值。 在 C++ 中設置數組值的眾多方法之一是std::fill_n

std::fill_n(grid, 100, 5);

不要使用 memset。

您將內存的每個字節[]設置為 5。每個 int 的長度為 4 個字節[5][5][5][5] ,編譯器將其正確解釋為 5*256*256*256 + 5* 256*256 + 5*256 + 5 = 84215045。相反,使用 for 循環,它也不需要 sizeof()。 一般來說, sizeof() 意味着你正在做一些艱難的事情。

for(int i=0; i<110; ++i)
    grid[i] = 5;

好吧, memset使用選定的值寫入字節。 因此 int 看起來像這樣:

00000101 00000101 00000101 00000101

然后將其解釋為 84215045。

你實際上並沒有說你想讓你的程序做什么。

假設您要將grid的前 100 個元素中的每一個設置為 5(並忽略100110的差異),只需執行以下操作:

for (int i = 0; i < 100; i ++) {
    grid[i] = 5;
}

我了解您擔心速度,但您的擔心可能是錯誤的。 一方面, memset()可能會被優化,因此比簡單的循環更快。 另一方面,優化可能包括一次寫入多個字節,這就是這個循環所做的。 另一方面, memset()無論如何都是一個循環; 顯式編寫循環而不是將其埋在函數調用中並不會改變這一點。 另一方面,即使循環很慢,也可能無關緊要。 專注於編寫清晰的代碼,如果實際測量表明存在嚴重的性能問題,則考慮對其進行優化。

您編寫問題所花費的時間比您的計算機設置grid所花費的時間要多很多數量級。

最后,在我手忙腳亂(為時已晚!)之前,如果memset()不能滿足您的要求,那么它的速度並不重要。 (根本不設置grid甚至更快!)

如果你在 shell 上輸入man memset ,它會告訴你

void * memset(void *b, int c, size_t len)

一個簡單的英語解釋是,它填充一個長度為len的字節串b ,每個字節都有一個值c

對於你的情況,

memset(grid, 5, 100 * sizeof(int));

由於sizeof(int)==4 ,因此上面的代碼片段看起來像:

for (int i=0; i<100; i++)
    grid[i]=0x05050505;

或者

char *grid2 = (char*)grid;
for (int i=0; i<100*sizeof(int); i++)
    grid2[i]=0x05;

它將打印出84215045

但在大多數 C 代碼中,我們希望將一塊內存塊初始化為零。

  • char類型 --> \\0NUL
  • int類型 --> 0
  • float類型 --> 0.0f
  • double類型 --> 0.0
  • 指針類型 --> nullptr

gccclang等現代編譯器可以自動為您處理好這個問題。

// variadic length array (VLA) introduced in C99
int len = 20;
char carr[len];
int iarr[len];
float farr[len];
double darr[len];
memset(carr, 0, sizeof(char)*len);
memset(iarr, 0, sizeof(int)*len);
memset(farr, 0, sizeof(float)*len);
memset(darr, 0, sizeof(double)*len);
for (int i=0; i<len; i++)
{
    printf("%2d: %c\n", i, carr[i]);
    printf("%2d: %i\n", i, iarr[i]);
    printf("%2d: %f\n", i, farr[i]);
    printf("%2d: %lf\n", i, darr[i]);
}

但請注意,C ISO 委員會並沒有強加這樣的定義,它是特定於編譯器的。

此代碼已經過測試。 這是一種將“整數”數組設置為 0 到 255 之間的值的方法。

MinColCost=new unsigned char[(Len+1) * sizeof(int)];

memset(MinColCost,0x5,(Len+1)*sizeof(int));

memset(MinColCost,0xff,(Len+1)*sizeof(int));

由於 memset 寫入字節,我通常使用它將一個 int 數組設置為零,例如:

int a[100];
memset(a,0,sizeof(a));

或者您可以使用它來設置 char 數組,因為 char 正是一個字節:

char a[100];
memset(a,'*',sizeof(a));

更重要的是,一個 int 數組也可以通過 memset 設置為 -1:

memset(a,-1,sizeof(a));

這是因為 -1 在 int 中是 0xffffffff,在 char(一個字節)中是 0xff。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM