結構體0長度陣列的作用

2021-05-26 03:00:22 字數 4118 閱讀 6455

在標準 c 和 c++ 中,不允許用 0 長度陣列,但在 gnu c 中,卻可以定義 0 長度陣列。比如:

引用

struct

line

0 長度陣列不占有空間,從列印 sizeof (struct line) 可以看到這個結構體的長度為 4,這 4 位元組空間屬於整型量 length 。那麼結構體裡最後的 0 長度字元陣列 contents[0] 用來做什麼呢?答案是,它可以用來指向一段由你自己分配的 buffer 空間。如:

引用

int

this_length

=60 ;

struct

line

*thisline

= (struct

line

* ) malloc (

sizeof(

struct

line )

+this_length );

thisline->length = this_length;

這樣,就開闢了 64 位元組空間。前面 4 個位元組為 this_length 用,後面 60 個位元組被 contents 陣列用。經過空間分配後,就相當於把結構體定義為:

引用

struct

line

順便看一下這個空間的分布,做如下列印:

引用

printf (

"thisline 指向的位址為 %p

/n

",thisline );

printf (

"thisline指向的第乙個元素值為:%d

/n

",thisline

->

length );

printf (

"該元素的位址為%p

/n

",&thisline

->

length );

printf (

"%p/n

",&thisline

->

contents );

printf (

"%p/n

",&thisline

->

contents[0

]);printf (

"%p/n

",&thisline

->

contents[1

]);

輸出為:

引用

thisline 指向的位址為 0x8780008

thisline指向的第乙個元素值為:60

該元素的位址為0x8780008

0x878000c

0x878000c

0x878000d

從輸出可以看到,thisline-contents 只是乙個「不占有空間「(其特性由編譯器決定)的常量指標。在這裡,它表示接著整型值後的起始位址。

現在,我們可以使用這個陣列了,比如給這個陣列的前幾個元素賦下值:

引用

char

c='x' ;

int

i ;thisline

->

contents[0

]=c ; c=

'y' ;

thisline

->

contents[1

]=c ; c=

'z' ;

thisline

->

contents[2

]=c ;

for(

i=0 ;

i<

3 ;

i++ )

printf (

"%c/n

",thisline

->

contents[i

]);

還有乙個問題需要**。既然用了 malloc() 函式,那麼在最後就會使用 free() 函式來釋放掉所申請的記憶體空間。那麼,在這裡,是不是只是用 free(thisline) 就能達到目的了呢?下面做乙個實驗:

首先在程式中,將分配緩衝區的首位址備份起來:

引用

struct

line

*thisline_bak

=thisline ;

現在做如下釋放然後看一下空間中首元素(length)的值:

引用

free(thisline);

printf (

"%d/n

",thisline_bak

->

length );

一般在列印裡可以看到 length 的輸出值為 0 ,這也說明,首個元素的記憶體空間確實被釋放了。在這裡,嚴格的說,這個指標已經不能再這麼用,因為它指向了乙個被釋放的記憶體空間。

但是,如果我們再次執行

引用

for(

i=0 ;

i<

3 ;

i++ )

printf (

"%c/n

",thisline

->

contents[i

]);

這 個列印,發現仍然能夠正常的列印出值來,從而說明了,後面申請的陣列緩衝區還沒釋放。原因是,由於分配的空間返回的指標被強制轉換為 struct line 型別,且所得到的空間並不是平緩的(包含的不是同一種元素型別的空間)。在這裡的空間組成是,乙個整型值 + 後面一大塊字元型緩衝區。所以,在釋放時,free() 函式認為 *thisline 只是乙個指向 4 位元組整型值的空間。因而,我們要完全釋放整個申請的空間,還需要:

引用

free (thisline->contents);

此後,如果再次列印之前那 3 個賦值的元素時,會發現段錯誤,或者是類似下面的錯誤:

引用

*** glibc detected *** ./array4: free(): invalid pointer: 0x09e4300c ***

*****== backtrace: *****====

/lib/tls/i686/cmov/libc.so.6(+0x6b591)[0x5b8591]

/lib/tls/i686/cmov/libc.so.6(+0x6cde8)[0x5b9de8]

/lib/tls/i686/cmov/libc.so.6(cfree+0x6d)[0x5bcecd]

./array4[0x80485ad]

/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0x563bd6]

./array4[0x80483c1]

*****== memory map: *****===

... ...

所以,在不用這段空間時,可如下釋放:

引用 free (thisline->contents);   /*先釋放掉後面的陣列buffer*/

free(thisline);    /*再釋放掉 4 位元組整型空間*/

0 長度陣列

在標準 c 和 c 中,不允許用 0 長度陣列,但在 gnu c 中,卻可以定義 0 長度陣列。比如 引用 struct line 0 長度陣列不占有空間,從列印 sizeof struct line 可以看到這個結構體的長度為 4,這 4 位元組空間屬於整型量 length 那麼結構體裡最後的 0...

0長度陣列問題

標準c c 不支援0長度陣列,gnu支援 struct node int main int argc,char argv 上述 輸出為12,0長度陣列不占用記憶體空間 中e表示乙個常量指標,這個特性由編譯器來實現的,故具有不可移植性 對於這個用法,我們定義的結構體指標可以指向任意長度的記憶體buff...

柔性陣列(0長度陣列)

柔性陣列這個概念相信大多數人博友都沒有聽說過,但是它確實存在。在c99中,結構 結構體 的最後乙個元素允許是未知大小的陣列,這就叫做柔性陣列成員。比如 struct s 或者是 struct s 一 結構中柔性陣列成員前面必須至少有乙個其他成員比如,當你建立含有柔性陣列成員的結構體時,結構體成員不能...