最近,同事在負責一個項目的時候遇到一個問題:數組初始化后值異常,后來找出是使用memset函數的鍋,這里我也來跟着學習下。。
C語言中memset源碼如下:
void *memset(void *s, int c, size_t count) { char *xs = s; while (count--) *xs++ = c; return s; }
我們可以發現,在memset()函數中,會將(void *)類型轉換成(char *)類型,這樣會有什么影響呢?
1、試驗一
#include <stdio.h> #include <string.h> int main(void) { int i=0,j=0; int array_1[16]; char array_2[16]; memset(array_1, 0, 16); memset(array_2, 0, 16); printf("[array_1]:"); for(i; i<16; i++) { printf("%d ",array_1[i]); } printf("\n"); printf("[array_2]:"); for(j; j<16; j++) { printf("%d ",array_2[j]); } printf("\n"); return 0; }
這里分別設置兩個類型的數組,一個int型,一個char型,那么輸出結果如下:
[array_1]:0 0 0 0 1835627636 1600061541 1869833334 1952802655 1 0 4196205 0 0 0 0 0
[array_2]:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
可以發現,這時候int型的數組初始化是異常的。若細心一點可以發現,int型數組的前4個成員都是為0的(16個字節),這個長度剛好是array_2的長度。那這是不是由於memset是以char為單位進行置0,所以只初始化了int型數組的前四個成員呢?
2、試驗二:
memset(array_1, 0, 64);
那么輸出結果如下:
[array_1]:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[array_2]:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
可以發現,int型數組初始化完成了。那么是不是指針轉換是數據丟失呢?
3、實驗三:
#include <stdio.h> #include <string.h> int main(void) { int *addr_1 = (int *)0x12345678; char *addr_2 = (void *)addr_1; printf("addr_1 : %p\n",addr_1); printf("addr_2 : %p\n",addr_2); return 0; }
那么輸出結果如下:
addr_1 : 0x12345678
addr_2 : 0x12345678
也是就說,不同類型的指針的指針長度是一樣的,但是,指針偏移的時候會根據所聲明的類型來進行偏移。如同樣是prt++,int *表示偏移是4個字節,char *則表示偏移是1個字節
既然這樣的話,那么如果結構體里面成員類型不同的話,那么結構體的初始化也會有影響嗎?
4、實驗四:
#include <stdio.h>
#include <string.h>
typedef struct _s_param
{
int a;
int b;
char c;
}S_PARAM;
typedef struct _s_var
{
char a;
char b;
int c;
}S_VAR;
int main(void)
{
S_PARAM param;
S_VAR var;
memset(¶m, 0, sizeof(S_PARAM));
memset(&var, 0, sizeof(S_VAR));
printf("[param(%ld)] a=%d, b=%d, c=%d\n",sizeof(S_PARAM), param.a,param.b,param.c);
printf("[var(%ld)] a=%d, b=%d, c=%d\n",sizeof(S_VAR), var.a,var.b,var.c);
}
那么輸出結果如下:
[param(12)] a=0, b=0, c=0
[var(8)] a=0, b=0, c=0
可以發現結構體的初始化是正常的,這是因為輸入的長度是結構體的長度,那這樣的話,那前面的數組初始化用sizeof的話,應該也是初始化正常的(這里就不進行實驗啦)
