C語言柔性數組講解



#include<stdio.h> typedef struct _SoftArray{ int len; int array[]; }SoftArray; int main() { int len = 10; printf("The struct's size is %d\n",sizeof(SoftArray)); }

 

 

 

 

 

我們可以看出,_SoftArray結構體的大小是4,顯然,在32位操作系統下一個int型變量大小剛好為4,也就說結構體中的數組沒有占用內存。為什么會沒有占用內

存,我們平時用數組時不時都要明確指明數組大小的嗎?但這里卻可以編譯通過呢?這就是我們常說的動態數組,也就是柔性數組。

先不要亂,讓我們再看一段代碼

#include<stdio.h>
#include<malloc.h>

typedef struct _SoftArray{
    int len;
    int array[];
}SoftArray;

int main()
{
    int len = 10;

    SoftArray *p=(SoftArray*)malloc(sizeof(SoftArray) + sizeof(int)*len);
    printf("After the malloc function the struct's size is %d\n”,sizeof(SoftArray));

    return 0;
}

 

是不是有點奇怪,為什么申請了內存后結構體大小還是4呢?原因是動態申請的內存只是申請給數組拓展所用,從上個程序我們可以看出結構體的大小在創建時已經

確定了,array明確來說不算是結構體成員,只是掛羊頭賣狗肉而已。

下面我們來看看關於柔性數組的資料:

1、什么是柔性數組?

柔性數組既數組大小待定的數組, C語言中結構體的最后一個元素可以是大小未知的數組,也就是所謂的0長度,所以我們可以用結構體來創建柔性數組。

2、柔性數組有什么用途 ?

它的主要用途是為了滿足需要變長度的結構體,為了解決使用數組時內存的冗余和數組的越界問題。

3、用法 :在一個結構體的最后 ,申明一個長度為空的數組,就可以使得這個結構體是可變長的。對於編譯器來說,此時長度為0的數組並不占用空間,因為數組名

本身不占空間,它只是一個偏移量, 數組名這個符號本身代 表了一個不可修改的地址常量 (注意:數組名永遠都不會是指針! ),但對於這個數組的大小,我們

可以進行動態分配,對於編譯器而言,數組名僅僅是一個符號,它不會占用任何空間,它在結構體中,只是代表了一個偏移量,代表一個不可修改的地址常量!

對於柔性數組的這個特點,很容易構造出變成結構體,如緩沖區,數據包等等:

typedef struct _SoftArray

{

    Int len;

    int array[];

}SoftArray;

這樣的變長數組常用於網絡通信中構造不定長數據包,不會浪費空間浪費網絡流量,比如我要發送1024字節的數據,如果用定長包,假設定長包的長度為2048,就

會浪費1024個字節的空間,也會造成不必要的流量浪費。

 

4、舉個簡單是實例

#include<stdio.h>
#include<malloc.h>
typedef struct _SoftArray{
int len;
int array[];
}SoftArray;
int main()
{
    int len=10,i=0;
    
    SoftArray *p=(SoftArray*)malloc(sizeof(SoftArray)+sizeof(int)*len);
    p->len=len;
    
    for(i=0;i<p->len;i++)
   {
        p->array[i]=i+1;
    }
    for(i=0;i<p->len;i++)
   {  
        printf("%d\n",p->array[i]);
    }

    free(p);

    return 0;
}    

 

 

 

 

 

 

 

 

 

這代碼的作用是用柔性數組動態創建數組並輸出數組內容,這里我就直接解釋解釋這兩句代碼

   SoftArray* p = (SoftArray*)malloc(sizeof(SoftArray) + sizeof(int) *10);

      p->len = 10;

   第一句,主要是根據你要定義的數組長度和數據類型以及柔性數組本身的大小來開辟一塊內存空間給柔性數組,第二個是定義len的長度,便於確定循環打印輸出

是循環的次數。

5、運行錯誤的解決

#include<stdio.h>
#include<malloc.h>
typedef struct _SoftArray{
int len;
int array[];
}SoftArray;
int main()
{
    int len=10,i=0;
    
    SoftArray *p=(SoftArray*)malloc(sizeof(SoftArray)+sizeof(int)*len);
    p->len=len;
    
    for(i=0;i<11;i++)
   {
        p->array[i]=i+1;
    }
    for(i=0;i<11;i++)
   {  
        printf("%d\n",p->array[i]);
    }

    free(p);

    return 0;
} 
所謂初生牛犢不怕死,我在寫柔性數組程序時,為了做了個大膽的嘗試,那就是我在上一個代碼中申請內存時申請了10,但賦值時我把大小寫了11,問題出現了,
 
話不多說,直接上圖
 

我當時不知道是什么問題,我也蒙了~---~

但我又做出了一個偉大的決定,我把free(p)注釋掉了,結果11成功打印出來了。我當時真是One Face mengbi。

 

 
 
 
 
 
 
 
 
 
 
 
 
 
后來才發現其實是因為在動態分配內存的時候往往分配的是一個連續的地址,這一點從可以使用*[a+3]來取值就能夠知道。
 
因此,在動態分配的時候,會在數組界限外加一個用來標識數組范圍的標志,例如a數組,就會在array[-1]和array[11]有兩個標志,如果我們在這兩個位置賦值,賦
 
值和調用時並不會出錯,而是在freed掉array申請的內存時出錯,錯誤的名稱就是“DAMAGE: before Normal block”和“DAMAGE: after Normal block”。一般是后者居多。
 
因此,當你遇見這個錯誤的時候,記得去檢查一下自己數組的賦值吧。

6、注意說明

在定義這個結構體的時候,模子的大小就C89不支持這種東西,C99把它作為一種特例加入了標准。

但是,C99所支持的是 incomplete type,而不是 zero array,形同 int item[0];這種形式是非法的,C99支持的形式是形同 int item[];只不過有些編譯器把 int item[0];作

為非標准擴展來支持,而且在C99發布之前已經有了這種非標准擴展了,C99發布之后,有些編譯器把兩者合而為一了。當然,上面既然用 malloc函數分配了內存,

肯定就需要用 free函數來釋放內存:free(p);這兩個函數是一對CP,就好像fopen()和fclose();記住不要亂拆CP,拆CP是有風險的哦。

 

最后再送大家一個代碼玩玩:

 1 #include<stdio.h>
 2 #include<malloc.h>
 3 typedef struct _SoftArray{
 4     int len;
 5     int array[];
 6 }SoftArray;
 7 
 8 //打印輸出斐波那契數列
 9 void printfln(SoftArray *p,int len)
10 {
11     int i;
12 
13     for(i=0;i<len;i++)        //循環進行打印輸出    
14     {
15         printf("%d\n",p->array[i]);
16     }
17 }
18 
19 //動態生成斐波那契數列
20 void create(int len)
21 {
22     int i;
23     
24     SoftArray * p=(SoftArray*)malloc(sizeof(SoftArray)+sizeof(int)*len);    //聲明結構體指針p,動態申請內存,大小為結構體大小+10個int型大小
25 
26     for(i=0;i<len;i++)        //循環進行數組賦值
27     {
28         if( i <= 1 )
29         {
30             p->array[i] = 1;
31         }else if( i >= 2 )
32         {
33             p->array[i] = p->array[i-1] + p->array[i-2];
34         }else 
35         {
36             printf("DAMAGE: before Normal block or after Normal block");
37             return (-1);
38         }
39         
40     }
41     printfln(p,len);
42 
43     free(p);
44 }
45 
46 //主函數
47 int main()
48 {
49     int i=0;
50     int len;
51 
52     printf("請輸入生成斐波那契數列的行數:");
53     scanf("%d",&len);
54 
55     create(len);
56 
57     return 0;
58 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM