示例1:
typedef struct _a{
int type;
char dat[];
}A;
int main(void)
{
char* ptr = "hello_world";
A *a = malloc(sizeof(A) + strlen(ptr) + );
memcpy(a->dat, ptr, strlen(ptr) + );
printf("a->dat = %s\n", a->dat);
free(a);
return ;
}
運作結果正常。
結構體A占據的記憶體空間是8位元組(32Bit作業系統),int型變量和char型變量各占據4位元組,strlen(ptr)等于11位元組,是以malloc配置設定的空間是20位元組,配置設定出來的空間是位址連續的堆空間。執行memcpy()時候,ptr字元串内容會覆寫結構體中dat數組變量的起始空間,而後續的空間又有(strlen(ptr) + 1)大小,是以運作正常。
示例2:
如果把結果體A中的數組變量dat改成指針變量*dat呢,
typedef struct _a{
int type;
char *dat;
}A;
int main(void)
{
char* ptr = "hello_world";
A *a = malloc(sizeof(A) + strlen(ptr) + );
memcpy(a->dat, ptr, strlen(ptr) + );
printf("a->dat = %s\n", a->dat);
free(a);
return ;
}
顯然,運作後發生Segmentation fault。這是因為malloc是在堆記憶體配置設定空間的,堆上的資料預設是0,也就是說指針變量預設是NULL。
在malloc之後列印結構體A的首位址以及type、dat的位址:
printf("a = %p, &a->type = %p, a->dat = %p\n", a, &a->type, a->dat);
運作:
memcpy()函數通路的目标位址是0位址處,是以自然段錯誤。
如何修改,顯然需要将a->dat指針指向一個合适的地方去。指向a->type之後的位址?
int mian()
{
char* ptr = "hello_world";
A *a = malloc(sizeof(A) + strlen(ptr) + );
printf("a = %p, &a->type = %p, a->dat = %p\n", a, &a->type, a->dat);
a->dat = (char* )(&(a->type) + ); //加1加的是步長,等價于加偏移4位元組位址
printf("a->dat = %p\n", a->dat);
memcpy(a->dat, ptr, strlen(ptr) + );
printf("a->dat = %s\n", a->dat);
free(a);
}
運作結果還是段錯誤:
memcpy()操作的目的位址是0x8b4d00c,而結構體變量a的起始位址,也就是a結構體首個變量type的位址0x8b4d008,其中偏移4位元組,跟前面示例1對比,看似并沒什麼問題,但是注意,示例1中a->type之後是一個數組變量,而在本例中,a->type之後是一個指針變量,它原指向NULL,經這麼修改,它指向的是自己的位址了。指針變量也是變量,它的存在本身也需要位址存放,每個指針都需要占據空間給自己用,memcpy()函數的是dat指針給自己生存用的位址,是以出現段錯誤。應修改為:
也就是說a->dat指向A之外的記憶體大小為strlen(ptr) + 1空間的起始位址,這樣就可以正常運作。