一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

C語言0長度數(shù)組(可變數(shù)組/柔性數(shù)組)詳解

 quasiceo 2017-11-19
CSDN GitHub
C語言0長度數(shù)組(可變數(shù)組/柔性數(shù)組)詳解 AderXCoding/language/c/zero_length_array


知識共享許可協(xié)議
本作品采用知識共享署名-非商業(yè)性使用-相同方式共享 4.0 國際許可協(xié)議進行許可, 轉(zhuǎn)載請注明出處, 謝謝合作

1 零長度數(shù)組概念


眾所周知, GNU/GCC 在標準的 C/C++ 基礎(chǔ)上做了有實用性的擴展, 零長度數(shù)組(Arrays of Length Zero) 就是其中一個知名的擴展.

多數(shù)情況下, 其應(yīng)用在變長數(shù)組中, 其定義如下

struct Packet
{
    int state;
    int len;
    char cData[0]; //這里的0長結(jié)構(gòu)體就為變長結(jié)構(gòu)體提供了非常好的支持
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

首先對 0長度數(shù)組, 也叫柔性數(shù)組 做一個解釋 :

  • 用途 : 長度為0的數(shù)組的主要用途是為了滿足需要變長度的結(jié)構(gòu)體

  • 用法 : 在一個結(jié)構(gòu)體的最后, 申明一個長度為0的數(shù)組, 就可以使得這個結(jié)構(gòu)體是可變長的. 對于編譯器來說, 此時長度為0的數(shù)組并不占用空間, 因為數(shù)組名本身不占空間, 它只是一個偏移量, 數(shù)組名這個符號本身代表了一個不可修改的地址常量

(注意 : 數(shù)組名永遠都不會是指針!), 但對于這個數(shù)組的大小, 我們可以進行動態(tài)分配

注意 :如果結(jié)構(gòu)體是通過calloc、malloc或 者new等動態(tài)分配方式生成,在不需要時要釋放相應(yīng)的空間。

優(yōu)點 :比起在結(jié)構(gòu)體中聲明一個指針變量、再進行動態(tài)分 配的辦法,這種方法效率要高。因為在訪問數(shù)組內(nèi)容時,不需要間接訪問,避免了兩次訪存。

缺點 :在結(jié)構(gòu)體中,數(shù)組為0的數(shù)組必須在最后聲明,使 用上有一定限制。

對于編譯器而言, 數(shù)組名僅僅是一個符號, 它不會占用任何空間, 它在結(jié)構(gòu)體中, 只是代表了一個偏移量, 代表一個不可修改的地址常量!

2 0長度數(shù)組的用途


我們設(shè)想這樣一個場景, 我們在網(wǎng)絡(luò)通信過程中使用的數(shù)據(jù)緩沖區(qū), 緩沖區(qū)包括一個len字段和data字段, 分別標識數(shù)據(jù)的長度和傳輸?shù)臄?shù)據(jù), 我們常見的有幾種設(shè)計思路

  • 定長數(shù)據(jù)緩沖區(qū), 設(shè)置一個足夠大小 MAX_LENGTH 的數(shù)據(jù)緩沖區(qū)

  • 設(shè)置一個指向?qū)嶋H數(shù)據(jù)的指針, 每次使用時, 按照數(shù)據(jù)的長度動態(tài)的開辟數(shù)據(jù)緩沖區(qū)的空間.

我們從實際場景中應(yīng)用的設(shè)計來考慮他們的優(yōu)劣. 主要考慮的有, 緩沖區(qū)空間的開辟, 釋放和訪問.

2.1 定長包(開辟空間, 釋放, 訪問)


比如我要發(fā)送 1024 字節(jié)的數(shù)據(jù), 如果用定長包, 假設(shè)定長包的長度 MAX_LENGTH2048, 就會浪費 1024 個字節(jié)的空間, 也會造成不必要的流量浪費.

  • 數(shù)據(jù)結(jié)構(gòu)定義
//  定長緩沖區(qū)
struct max_buffer
{
    int     len;
    char    data[MAX_LENGTH];
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 數(shù)據(jù)結(jié)構(gòu)大小

考慮對齊, 那么數(shù)據(jù)結(jié)構(gòu)的大小 >= sizeof(int) + sizeof(char) * MAX_LENGTH

由于考慮到數(shù)據(jù)的溢出, 變長數(shù)據(jù)包中的 data 數(shù)組長度一般會設(shè)置得足夠長足以容納最大的數(shù)據(jù), 因此 max_buffer 中的 data 數(shù)組很多情況下都沒有填滿數(shù)據(jù), 因此造成了浪費

  • 數(shù)據(jù)包的構(gòu)造

假如我們要發(fā)送 CURR_LENGTH = 1024 個字節(jié), 我們?nèi)绾螛?gòu)造這個數(shù)據(jù)包呢:

一般來說, 我們會返回一個指向緩沖區(qū)數(shù)據(jù)結(jié)構(gòu) max_buffer 的指針.

    ///  開辟
    if ((mbuffer = (struct max_buffer *)malloc(sizeof(struct max_buffer))) != NULL)
    {
        mbuffer->len = CURR_LENGTH;
        memcpy(mbuffer->data, "Hello World", CURR_LENGTH);


        printf("%d, %s\n", mbuffer->len, mbuffer->data);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 訪問

這段內(nèi)存要分兩部分使用

前部分 4 個字節(jié) p->len, 作為包頭(就是多出來的那部分),這個包頭是用來描述緊接著包頭后面的數(shù)據(jù)部分的長度,這里是 1024, 所以前四個字節(jié)賦值為 1024 (既然我們要構(gòu)造不定長數(shù)據(jù)包,那么這個包到底有多長呢,因此,我們就必須通過一個變量來表明這個數(shù)據(jù)包的長度,這就是len的作用),

而緊接其后的內(nèi)存是真正的數(shù)據(jù)部分, 通過 p->data, 最后, 進行一個 memcpy() 內(nèi)存拷貝, 把要發(fā)送的數(shù)據(jù)填入到這段內(nèi)存當中

  • 釋放

那么當使用完畢釋放數(shù)據(jù)的空間的時候, 直接釋放就可以了

    /// 銷毀
    free(mbuffer);
    mbuffer = NULL;
  • 1
  • 2
  • 3
  • 小結(jié)

    1. 使用定長數(shù)組, 作為數(shù)據(jù)緩沖區(qū), 為了避免造成緩沖區(qū)溢出, 數(shù)組的大小一般設(shè)為足夠的空間 MAX_LENGTH, 而實際使用過程中, 達到 MAX_LENGTH 長度的數(shù)據(jù)很少, 那么多數(shù)情況下, 緩沖區(qū)的大部分空間都是浪費掉的.

    2. 但是使用過程很簡單, 數(shù)據(jù)空間的開辟和釋放簡單, 無需程序員考慮額外的操作

2.2 指針數(shù)據(jù)包(開辟空間, 釋放, 訪問)


如果你將上面的長度為 MAX_LENGTH 的定長數(shù)組換為指針, 每次使用時動態(tài)的開辟 CURR_LENGTH 大小的空間, 那么就避免造成 MAX_LENGTH - CURR_LENGTH 空間的浪費, 只浪費了一個指針域的空間.

  • 數(shù)據(jù)包定義
struct point_buffer
{
    int     len;
    char    *data;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 數(shù)據(jù)結(jié)構(gòu)大小

考慮對齊, 那么數(shù)據(jù)結(jié)構(gòu)的大小 >= sizeof(int) + sizeof(char *)

  • 空間分配

但是也造成了使用在分配內(nèi)存時,需采用兩步

    // =====================
    // 指針數(shù)組  占用-開辟-銷毀
    // =====================
    ///  占用
    printf("the length of struct test3:%d\n",sizeof(struct point_buffer));
    ///  開辟
    if ((pbuffer = (struct point_buffer *)malloc(sizeof(struct point_buffer))) != NULL)
    {
        pbuffer->len = CURR_LENGTH;
        if ((pbuffer->data = (char *)malloc(sizeof(char) * CURR_LENGTH)) != NULL)
        {
            memcpy(pbuffer->data, "Hello World", CURR_LENGTH);


            printf("%d, %s\n", pbuffer->len, pbuffer->data);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  1. 首先, 需為結(jié)構(gòu)體分配一塊內(nèi)存空間;

  2. 其次再為結(jié)構(gòu)體中的成員變量分配內(nèi)存空間.

這樣兩次分配的內(nèi)存是不連續(xù)的, 需要分別對其進行管理. 當使用長度為的數(shù)組時, 則是采用一次分配的原則, 一次性將所需的內(nèi)存全部分配給它.

  • 釋放

相反, 釋放時也是一樣的.

    /// 銷毀
    free(pbuffer->data);
    free(pbuffer);
    pbuffer = NULL;
  • 1
  • 2
  • 3
  • 4
  • 小結(jié)

    1. 使用指針結(jié)果作為緩沖區(qū), 只多使用了一個指針大小的空間, 無需使用 MAX_LENGTH 長度的數(shù)組, 不會造成空間的大量浪費.

    2. 但那是開辟空間時, 需要額外開辟數(shù)據(jù)域的空間, 施放時候也需要顯示釋放數(shù)據(jù)域的空間, 但是實際使用過程中, 往往在函數(shù)中開辟空間, 然后返回給使用者指向 struct point_buffer 的指針, 這時候我們并不能假定使用者了解我們開辟的細節(jié), 并按照約定的操作釋放空間, 因此使用起來多有不便, 甚至造成內(nèi)存泄漏

2.3 變長數(shù)據(jù)緩沖區(qū)(開辟空間, 釋放, 訪問)


定長數(shù)組使用方便, 但是卻浪費空間, 指針形式只多使用了一個指針的空間, 不會造成大量空間分浪費, 但是使用起來需要多次分配, 多次釋放, 那么有沒有一種實現(xiàn)方式能夠既不浪費空間, 又使用方便的呢?

GNU C 的0長度數(shù)組, 也叫變長數(shù)組, 柔性數(shù)組就是這樣一個擴展. 對于0長數(shù)組的這個特點,很容易構(gòu)造出變成結(jié)構(gòu)體,如緩沖區(qū),數(shù)據(jù)包等等:

  • 數(shù)據(jù)結(jié)構(gòu)定義
//  0長度數(shù)組
struct zero_buffer
{
    int     len;
    char    data[0];
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 數(shù)據(jù)結(jié)構(gòu)大小

這樣的變長數(shù)組常用于網(wǎng)絡(luò)通信中構(gòu)造不定長數(shù)據(jù)包, 不會浪費空間浪費網(wǎng)絡(luò)流量, 因為char data[0]; 只是個數(shù)組名, 是不占用存儲空間的,

sizeof(struct zero_buffer) = sizeof(int)

  • 開辟空間

那么我們使用的時候, 只需要開辟一次空間即可

    ///  開辟
    if ((zbuffer = (struct zero_buffer *)malloc(sizeof(struct zero_buffer) + sizeof(char) * CURR_LENGTH)) != NULL)
    {
        zbuffer->len = CURR_LENGTH;
        memcpy(zbuffer->data, "Hello World", CURR_LENGTH);


        printf("%d, %s\n", zbuffer->len, zbuffer->data);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 釋放空間

釋放空間也是一樣的, 一次釋放即可

    ///  銷毀
    free(zbuffer);
    zbuffer = NULL;
  • 1
  • 2
  • 3

2.4 總結(jié)

// zero_length_array.c
#include <stdio.h>
#include <stdlib.h>


#define MAX_LENGTH      1024
#define CURR_LENGTH      512

//  0長度數(shù)組
struct zero_buffer
{
    int     len;
    char    data[0];
}__attribute((packed));


//  定長數(shù)組
struct max_buffer
{
    int     len;
    char    data[MAX_LENGTH];
}__attribute((packed));


//  指針數(shù)組
struct point_buffer
{
    int     len;
    char    *data;
}__attribute((packed));

int main(void)
{
    struct zero_buffer  *zbuffer = NULL;
    struct max_buffer   *mbuffer = NULL;
    struct point_buffer *pbuffer = NULL;


    // =====================
    // 0長度數(shù)組  占用-開辟-銷毀
    // =====================
    ///  占用
    printf("the length of struct test1:%d\n",sizeof(struct zero_buffer));
    ///  開辟
    if ((zbuffer = (struct zero_buffer *)malloc(sizeof(struct zero_buffer) + sizeof(char) * CURR_LENGTH)) != NULL)
    {
        zbuffer->len = CURR_LENGTH;
        memcpy(zbuffer->data, "Hello World", CURR_LENGTH);


        printf("%d, %s\n", zbuffer->len, zbuffer->data);
    }
    ///  銷毀
    free(zbuffer);
    zbuffer = NULL;


    // =====================
    // 定長數(shù)組  占用-開辟-銷毀
    // =====================
    ///  占用
    printf("the length of struct test2:%d\n",sizeof(struct max_buffer));
    ///  開辟
    if ((mbuffer = (struct max_buffer *)malloc(sizeof(struct max_buffer))) != NULL)
    {
        mbuffer->len = CURR_LENGTH;
        memcpy(mbuffer->data, "Hello World", CURR_LENGTH);


        printf("%d, %s\n", mbuffer->len, mbuffer->data);
    }
    /// 銷毀
    free(mbuffer);
    mbuffer = NULL;

    // =====================
    // 指針數(shù)組  占用-開辟-銷毀
    // =====================
    ///  占用
    printf("the length of struct test3:%d\n",sizeof(struct point_buffer));
    ///  開辟
    if ((pbuffer = (struct point_buffer *)malloc(sizeof(struct point_buffer))) != NULL)
    {
        pbuffer->len = CURR_LENGTH;
        if ((pbuffer->data = (char *)malloc(sizeof(char) * CURR_LENGTH)) != NULL)
        {
            memcpy(pbuffer->data, "Hello World", CURR_LENGTH);


            printf("%d, %s\n", pbuffer->len, pbuffer->data);
        }
    }
    /// 銷毀
    free(pbuffer->data);
    free(pbuffer);
    pbuffer = NULL;


    return EXIT_SUCCESS;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100

運行結(jié)果

  • 長度為0的數(shù)組并不占有內(nèi)存空間, 而指針方式需要占用內(nèi)存空間.

  • 對于長度為0數(shù)組, 在申請內(nèi)存空間時, 采用一次性分配的原則進行; 對于包含指針的結(jié)構(gòu)體, 才申請空間時需分別進行, 釋放時也需分別釋放.

  • 對于長度為的數(shù)組的訪問可采用數(shù)組方式進行

3 GNU Document中 變長數(shù)組的支持


參見

6.17 Arrays of Length Zero

C Struct Hack – Structure with variable length array

C90 之前, 并不支持0長度的數(shù)組, 0長度數(shù)組是 GNU C 的一個擴展, 因此早期的編譯器中是無法通過編譯的

對于 GNU C 增加的擴展, GCC 提供了編譯選項來明確的標識出他們

1、-pedantic 選項,那么使用了擴展語法的地方將產(chǎn)生相應(yīng)的警告信息

2、-Wall 使用它能夠使GCC產(chǎn)生盡可能多的警告信息

3、-Werror, 它要求GCC將所有的警告當成錯誤進行處理

// 1.c
#include <stdio.h>
#include <stdlib.h>


int main(void)
{
    char a[0];
    printf("%ld", sizeof(a));
    return EXIT_SUCCESS;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

我們來編譯

gcc 1.c -Wall   # 顯示所有警告
#none warning and error

gcc 1.c -Wall -pedantic  # 對GNU C的擴展顯示警告
1.c: In function ‘main’:
1.c:7: warning: ISO C forbids zero-size array ‘a(chǎn)’


gcc 1.c -Werror -Wall -pedantic # 顯示所有警告同時GNU C的擴展顯示警告, 將警告用error顯示
cc1: warnings being treated as errors
1.c: In function ‘main’:
1.c:7: error: ISO C forbids zero-size array ‘a(chǎn)’
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

運行結(jié)果

0長度數(shù)組其實就是靈活的運用的數(shù)組指向的是其后面的連續(xù)的內(nèi)存空間

struct buffer
{
    int     len;
    char    data[0];
};
  • 1
  • 2
  • 3
  • 4
  • 5

在早期沒引入0長度數(shù)組的時候, 大家是通過定長數(shù)組和指針的方式來解決的, 但是

  • 定長數(shù)組定義了一個足夠大的緩沖區(qū), 這樣使用方便, 但是每次都造成空間的浪費
  • 指針的方式, 要求程序員在釋放空間是必須進行多次的free操作, 而我們在使用的過程中往往在函數(shù)中返回了指向緩沖區(qū)的指針, 我們并不能保證每個人都理解并遵從我們的釋放方式

所以 GNU 就對其進行了0長度數(shù)組的擴展. 當使用data[0]的時候, 也就是0長度數(shù)組的時候,0長度數(shù)組作為數(shù)組名, 并不占用存儲空間.

C99之后,也加了類似的擴展,只不過用的是 char payload[]這種形式(所以如果你在編譯的時候確實需要用到-pedantic參數(shù),那么你可以將char payload[0]類型改成char payload[], 這樣就可以編譯通過了,當然你的編譯器必須支持C99標準的,如果太古老的編譯器,那可能不支持了)

// 2.c payload
#include <stdio.h>
#include <stdlib.h>

struct payload
{
    int   len;
    char  data[];
};

int main(void)
{
    struct payload pay;
    printf("%ld", sizeof(pay));
    return EXIT_SUCCESS;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

使用 -pedantic 編譯后, 不出現(xiàn)警告, 說明這種語法是 C 標準的

gcc 2.c -pedantic -std=c99
  • 1

2

所以結(jié)構(gòu)體的末尾, 就是指向了其后面的內(nèi)存數(shù)據(jù)。因此我們可以很好的將該類型的結(jié)構(gòu)體作為數(shù)據(jù)報文的頭格式,并且最后一個成員變量,也就剛好是數(shù)據(jù)內(nèi)容了.

GNU手冊還提供了另外兩個結(jié)構(gòu)體來說明,更容易看懂意思:

struct f1 {
    int x;
    int y[];
} f1 = { 1, { 2, 3, 4 } };

struct f2 {
    struct f1 f1;
    int data[3];
} f2 = { { 1 }, { 5, 6, 7 } };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

我把f2里面的2,3,4改成了5,6,7以示區(qū)分。如果你把數(shù)據(jù)打出來。即如下的信息:

f1.x = 1
f1.y[0] = 2
f1.y[1] = 3
f1.y[2] = 4
  • 1
  • 2
  • 3
  • 4

也就是f1.y指向的是{2,3,4}這塊內(nèi)存中的數(shù)據(jù)。所以我們就可以輕易的得到,f2.f1.y指向的數(shù)據(jù)也就是正好f2.data的內(nèi)容了。打印出來的數(shù)據(jù):

f2.f1.x = 1
f2.f1.y[0] = 5
f2.f1.y[1] = 6
f2.f1.y[2] = 7
  • 1
  • 2
  • 3
  • 4

如果你不是很確認其是否占用空間. 你可以用sizeof來計算一下。就可以知道sizeof(struct f1)=4,也就是int y[]其實是不占用空間的。但是這個0長度的數(shù)組,必須放在結(jié)構(gòu)體的末尾。如果你沒有把它放在末尾的話。編譯的時候,會有如下的錯誤:

main.c:37:9: error: flexible array member not at end of struct
     int y[];
         ^
  • 1
  • 2
  • 3

到這邊,你可能會有疑問,如果將struct f1中的int y[]替換成int *y,又會是如何?這就涉及到數(shù)組和指針的問題了. 有時候吧,這兩個是一樣的,有時候又有區(qū)別。

首先要說明的是,支持0長度數(shù)組的擴展,重點在數(shù)組,也就是不能用int *y指針來替換。sizeof的長度就不一樣了。把struct f1改成這樣:

struct f3 {
    int x;
    int *y;
};
  • 1
  • 2
  • 3
  • 4

在32/64位下, int均是4個字節(jié), sizeof(struct f1)=4,而sizeof(struct f3)=16

因為 int *y 是指針, 指針在64位下, 是64位的, sizeof(struct f3) = 16, 如果在32位環(huán)境的話, sizeof(struct f3) 則是 8 了, sizeof(struct f1) 不變. 所以 int *y 是不能替代 int y[] 的.

代碼如下

// 3.c
#include <stdio.h>
#include <stdlib.h>


struct f1 {
    int x;
    int y[];
} f1 = { 1, { 2, 3, 4 } };

struct f2 {
    struct f1 f1;
    int data[3];
} f2 = { { 1 }, { 5, 6, 7 } };


struct f3
{
    int x;
    int *y;
};

int main(void)
{
    printf("sizeof(f1) = %d\n", sizeof(struct f1));
    printf("sizeof(f2) = %d\n", sizeof(struct f2));
    printf("szieof(f3) = %d\n\n", sizeof(struct f3));

    printf("f1.x = %d\n", f1.x);
    printf("f1.y[0] = %d\n", f1.y[0]);
    printf("f1.y[1] = %d\n", f1.y[1]);
    printf("f1.y[2] = %d\n", f1.y[2]);


    printf("f2.f1.x = %d\n", f1.x);
    printf("f2.f1.y[0] = %d\n", f2.f1.y[0]);
    printf("f2.f1.y[1] = %d\n", f2.f1.y[1]);
    printf("f2.f1.y[2] = %d\n", f2.f1.y[2]);

    return EXIT_SUCCESS;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

運行結(jié)果

4 0長度數(shù)組的其他特征


4.1 為什么0長度數(shù)組不占用存儲空間


參見

結(jié)構(gòu)體中的指針與零長度數(shù)組

GNU C中的零長度數(shù)組

0長度數(shù)組與指針實現(xiàn)有什么區(qū)別呢, 為什么0長度數(shù)組不占用存儲空間呢?

其實本質(zhì)上涉及到的是一個C語言里面的數(shù)組和指針的區(qū)別問題. char a[1]里面的achar *bb相同嗎?

《 Programming Abstractions in C》(Roberts, E. S.,機械工業(yè)出版社,2004.6)82頁里面說

“arr is defined to be identical to &arr[0]”.

也就是說,char a[1]里面的a實際是一個常量,等于&a[0]。而char *b是有一個實實在在的指針變量b存在。 所以,a=b是不允許的,而b=a是允許的。 兩種變量都支持下標式的訪問,那么對于a[0]和b[0]本質(zhì)上是否有區(qū)別?我們可以通過一個例子來說明。

參見如下兩個程序 gdb_zero_length_array.cgdb_zero_length_array.c

//  gdb_zero_length_array.c
#include <stdio.h>
#include <stdlib.h>

struct str
{
    int len;
    char s[0];
};

struct foo
{
    struct str *a;
};

int main(void)
{
    struct foo f = { NULL };

    printf("sizeof(struct str) = %d\n", sizeof(struct str));

    printf("before f.a->s.\n");
    if(f.a->s)
    {
        printf("before printf f.a->s.\n");
        printf(f.a->s);
        printf("before printf f.a->s.\n");
    }

    return EXIT_SUCCESS;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

測試結(jié)果

//  gdb_pzero_length_array.c
#include <stdio.h>
#include <stdlib.h>

struct str
{
    int len;
    char *s;
};

struct foo
{
    struct str *a;
};

int main(void)
{
    struct foo f = { NULL };

    printf("sizeof(struct str) = %d\n", sizeof(struct str));

    printf("before f.a->s.\n");

    if (f.a->s)
    {
        printf("before printf f.a->s.\n");
        printf(f.a->s);
        printf("before printf f.a->s.\n");
    }

    return EXIT_SUCCESS;
}

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    国产精品二区三区免费播放心| 久久久精品日韩欧美丰满 | 在线视频免费看你懂的| 亚洲一区二区三区四区| 日本久久精品在线观看| 国产国产精品精品在线| 成人日韩在线播放视频| 女同伦理国产精品久久久| 亚洲最新av在线观看| 日本少妇中文字幕不卡视频| 精品国产亚洲av成人一区| 日本免费熟女一区二区三区| 精品日韩国产高清毛片| 性感少妇无套内射在线视频| 少妇熟女亚洲色图av天堂| av国产熟妇露脸在线观看| 91在线播放在线播放观看| 久久99国产精品果冻传媒| 国产熟女一区二区不卡| 国产一区二区不卡在线视频| 日本女优一区二区三区免费| 国产丝袜女优一区二区三区| 我想看亚洲一级黄色录像| 欧美国产在线观看精品| 日韩中文字幕免费在线视频| 自拍偷拍福利视频在线观看| 男人把女人操得嗷嗷叫| 日本精品中文字幕在线视频| 国产水滴盗摄一区二区| 亚洲欧洲日韩综合二区| 中文字幕一区二区免费| 国产大屁股喷水在线观看视频 | 国产精品熟女在线视频| 亚洲综合精品天堂夜夜| 久久99这里只精品热在线| 欧美一二三区高清不卡| 国产视频在线一区二区| 日韩国产欧美中文字幕| 日韩精品一级片免费看| 日韩精品你懂的在线观看| 国产av大片一区二区三区|