2012-10-18 132 views
-2

比方說,我有一個結構:內存分配

typedef struct { 
    int number1; /* dummy */ 
    int number2; /* dummy */ 
    int number3; /* dummy */ 
    char *name1; 
    char name2[]; 
} Klass; 

和代碼的其餘部分是:

int main(int argc, char const *argv[]) 
{ 
    char *name1 = "this is a name";   /* 1st case */ 
    char name2[] = "this is also a name";  /* 2nd case */ 

    Klass k; 
    k.number1 = 10; 
    k.number2 = 20; 
    k.number3 = 30; 
    k.name1 = "this is my first name";   /* 3rd case */ 

    /* error: invalid use of flexible array member */ 
    k.name2 = "this is my second name"; 

    Klass *kp = (Klass*)malloc(sizeof(Klass)); 
    kp->number1 = 100; 
    kp->number2 = 200; 
    kp->number3 = 300; 
    kp->name1 = "this is also my first name"; /* 4th case */ 

    /* error: invalid use of flexible array member */ 
    kp->name2 = "this is my second name"; 

    return 0; 
} 
  1. 任何人都可以澄清我如何記憶被分配(堆vs堆棧)在標記的情況下?
  2. 我應該如何在主塊的末尾釋放內存?
  3. 編譯器給 error: invalid use of flexible array member的原因是什麼?

編輯 如果你說k.name = "this is my name";kp->name = "this is also my name";是在棧上,你能解釋我如何能達到"this is my name"這樣的:

Klass *kp; 

int foo() { 
    Klass k; 
    k.number1 = 10; 
    k.number2 = 20; 
    k.number3 = 30; 
    k.name = "this is my name"; 
    kp = &k; 
} // k is destroyed now 

int main(int argc, char const *argv[]) 
{ 
    kp = (Klass*)malloc(sizeof(Klass)); 
    foo(); 
    printf("%d\n", kp->number1); /* segfault */ 
    printf("%d\n", kp->number2); /* segfault */ 
    printf("%d\n", kp->number3); /* segfault */ 
    printf("%s\n", kp->name); /* prints "this is my name" */ 
    return 0; 
} 
+2

請一次提出一個問題。那裏有三種不同的東西,其中前兩種已經被問及過無數次了。 – Mat

+0

3.的原因是你不能分配給數組。這是一個靈活的陣列成員是偶然的。 –

+0

@Mat我很想看到這些問題的鏈接,以便我可以解釋爲什麼這些答案不適用於我.. – none

回答

1
char *name1 = "this is a name";   /* 1st case */ 

這只是分配一個指針,將其設置爲指向字符串(其被保持爲靜態數據)。

char name2[] = "this is also a name";  /* 2nd case */ 

這是短期的char name2[sizeof(init_string)] = "this is also a name";並分配足夠的空間來字符存儲的字符串中。

你的第三個案例

char name2[]; 

分配沒有空間可言!沒有地方存儲一個字符串(無論如何都必須使用strcpy來複制)。

的第四殼體

kp->name1 = "this is also my first name"; /* 4th case */ 

類似於情況1 - name1是被設置爲指向一個靜態文本的指針。

+0

那個'靜態數據'的內存管理呢,它在堆還是棧上?我應該在事後釋放它嗎? – none

+0

不,靜態數據是一個單獨的區域(不是堆棧而不是堆)。你不必做任何事情,它由系統處理。 –

0

時,你應該釋放自己的內存只有時刻當你來(m)分配一些東西,或者調用這樣做的函數時(strdup(),...)

在情況1,3和4你分配的條紋在堆棧中,當你離開函數時,這些字符串將不可用。第二種情況有點棘手,但是這個字符串在可執行文件中是硬編碼的,並且不能對其進行修改(如果您嘗試這樣做,則會出現分段錯誤)。

由於name2不是指針,而是數組,因此不能將name2指向字符串。

+0

請參閱我的編輯問題。 – none

+0

由於您使用的是硬編碼字符串,因此該字符串將映射到內存中。但是,無論如何,發生的事情都是未定義的行爲。它可以隨時分段。 – tomahh

1

靈活長度的數組旨在主要用於指針。

Klass *kp = malloc(sizeof(Klass) + 100); 

這100是額外的字節,可以通過name2成員訪問。通常存在用於存儲柔性部件尺寸的結構的成員。

釋放此內存與您將用於常規結構的內存沒有任何區別。

編譯器抱怨的原因是它仍然是一個數組(不是指針),你不能簡單地分配數組。當您訪問kp->name2時,不會引入額外的間接尋址(與name2是指針的情況不同)。

至於存儲器分配:

1)name1是指向某些存儲器區域(最有可能只讀存儲器),其中一個字符串文字被存儲(字節包含與終止0 char數組)。試圖修改name1指向的字符串將導致未定義的行爲(您不允許修改字符串文字)。

2)name2是一個數組,它在堆棧中。您可以自由修改其內容。將字符串文字放入此數組的初始化代碼在不同的平臺和編譯器中可能會有所不同。我甚至看到了反彙編,其中一個字符串文字處於只讀內存區(.rodata)中,它簡單地用memcpy'編輯爲'name2。

3)和4)是分配給非法數組的嘗試。

+0

我認爲你的答案中混合了案例索引,但我想這是因爲我的問題與所有這些問題/案例/變量索引混淆。無論如何,我想我已經得到了你的答案,謝謝.. – none

1
    1. 的字符串的內存是靜態區域,這是所有的字符串常量住的地方。 name1只是一個指向該地區的指針。
    2. 內存具有自動存儲(「在堆棧上」)。
    3. 相同的情況下1
  1. 是的,因爲你已經叫malloc。必須通過致電free來鏡像每個malloc

  2. Klass,會員name2flexible array member,其大小是未知的編譯器(以及其中,順便說一句,你還沒有被分配在malloc調用任何內存)。另外,你不能直接拷貝C中的數組;如果您分配了足夠的內存,則可以使用memcpystrcpy

+0

你的答案缺少1.4,但我猜它也與案例1相同 – none

+0

@gokcehan:沒有看到它,但它確實是一樣的。 –