天天看點

結構體中指針成員的動态配置設定

示例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空間的起始位址,這樣就可以正常運作。

繼續閱讀