2016-03-02 114 views
-4

我剛開始搞結構和指針。&array == array,結構怎麼樣?

這裏是我的.h:

#ifndef struct_struct_h 
#include <string.h> 
#define struct_struct_h 



#endif 


int count=0; 

typedef struct 
{ 
    int num; 
    double balance; 
    const char * name; 
    struct Account * acnt; 

} Account; 

Account* a = NULL; 

Account* new_account(const char * n) 
{ 
    Account *a1 = malloc(sizeof(Account)); 

    a1->num=++count; 
    a1->name = n; 
    return a1; 
} 

這裏是我的main.c:

#include <stdio.h> 
#include <string.h> 
#include "struct.h" 



int main(int argc, const char * argv[]) 
{ 

    // insert code here... 
    Account* accounts[2]; 

    for(int i=0; i<2; i++) 
    { 
     accounts[i] = (i==0 ? new_account("David") : new_account("Toto")); 
    } 
    printf("Accounts array address is %i\n",&accounts); 

    for(int i=0; i<2;i++) 
    { 
     printf("Account n°%i is owned by %s \n, its address is %i\n",accounts[i]->num,accounts[i]->name,&accounts[i]); 
    } 
    printf("There are %i accounts.\n",count); 

    return 0; 
} 

如果我的帳戶替換&賬戶,我得到了相同的結果:@array,要麼是&賬戶[0],沒關係。

帳戶陣列地址是1606416480

如果我更換&應收賬款按*帳戶,我得到這個:

帳戶陣列地址是1063600

第二輸出是:

賬戶N°1由大衛 擁有,其地址爲1606416480

賬戶N°2由託託 擁有,其地址爲1606416488

其實這些帳戶指針的@載在賬戶中,這些@每個8B在內存中。

如果我更換&帳戶[i]發表賬戶[I],然後通過*帳戶[I]我得到:

賬戶N°1由大衛 擁有,其地址爲1063600

帳戶N°2由託託擁有,其地址被1063632

帳戶N°1由大衛 擁有,其地址爲3874

AC計數N°2由託託 擁有,其地址爲3880

在第一種情況我有2個指針,並且在第二I具有2個*指針。

* STRUCT和STRUCT是不同的,爲什麼?

+5

使用'%p'將參數強制轉換爲'void *'來打印地址。 –

+2

如果一個數組是一個指針,它將被稱爲「指針」,而不是「數組」! &array是**不是**與'array'相同。即使** iff **數組_decays_大部分時間都是指向一個指針,它是一個不同的指針。而且你有更多的錯誤觀念:你的「標題」是錯誤的。請查看頭部必須包含的內容以及警衛的實際意圖。 – Olaf

+0

我對C很新,我讀過「公共」結構應該在頭部聲明。 – Aleks

回答

1

數組在內部表示爲連續的內存範圍。在範圍的最開始部分放置陣列的第一個元素。

如果您的數組命名方式與您的問題accounts相同,那麼數組地址和數組第一個元素的地址具有相同的值。

如果考慮您的示例然後例如在sizeof操作符使用它們轉換爲指針,以他們的第一個元素,你有除了極少數例外表情

Account * accounts[2]; 

陣列。

因此表達accounts的類型爲Account **和式

accounts == &accounts[0] 

評估爲真。

表達式&accounts具有相同的值,因爲它是範圍的地址但是是不同的類型。它的類型是

Account * (*)[2] 

,如果你寫例如

Account *(*p)[2] = accounts; 

printf("*p = %zu\n", sizeof(*p)); 

那麼輸出將等於16,因爲在你運行你自己的代碼的環境,是一個指針的大小等於8數組由兩個指針元素組成。

你可能不寫條件

&accounts == accounts 

,因爲操作數有不同的類型。但是,如果你寫

(void *)&accounts == (void *) accounts 

那麼這個條件計算爲真。

所以表達式

&accountsaccounts,和&accounts[0]的值相等彼此並且是由陣列所佔用的存儲器區的地址。

至於結構,那麼結構的地址等於它的第一個成員的地址。但是,結構類型的對象的名稱不會隱式轉換爲指向其第一個成員的指針。

如果我更換&帳戶[I]由帳戶[I],然後通過*帳戶[I]我得到:

&accounts[i]給出陣列的元素的地址。所以你會得到值

Account n°1 is owned by David , its address is 1606416480 

Account n°2 is owned by Toto , its address is 1606416488 

的值之間的差等於8即表達式的值sizeof(Account *)

accounts[i]給出存儲在數組中的元素的值。它們是結構類型的每個對象的動態全局定位內存的地址。

* accounts [i]是結構類型的一個對象。由於printf調用中的格式說明符不對應於作爲參數傳遞的對象,因此函數行爲未定義。

考慮到要打印指針,必須使用格式說明符%p

+0

非常感謝您的回答,因爲我開始用C語言編寫內存,將其視爲一個大陣列。這種方法有助於我理解高級語言中可變性與引用之間的關係。 – Aleks

+0

@Aleks根本沒有。不用謝。:) –

0

TL/DR版本:

數組是特殊的,並且在大多數情況下的陣列表達被視爲一個指針數組的第一個元素。 a&a將產生相同的值(數組a的第一個元素的地址),但表達式的類型將不同。

這不是struct類型(或任何其他聚合類型)的情況。

大衛福斯特華萊士版本:

除了當它是sizeof或一元&運營商的操作數,或是一個字符串被用來在聲明初始化另一個陣列,表達型的N -12le」的元素數組將被轉換(「衰減」)爲「指向T的指針」類型的表達式,並且表達式的值將是數組中第一個元素的地址。

爲什麼會出現這種情況?

首先,我們來看看數組是如何在內存中表示的。鑑於申報

T a[N]; 

,那麼你得到的東西看起來是這樣的:

+---+ 
a: | | a[0] 
    +---+ 
    | | a[1] 
    +---+ 
    ... 
    +---+ 
    | | a[N-1] 
    +---+ 

存儲進行設置預留的數組元素和沒有別的;沒有存儲任何元數據或指向數組第一個元素的指針。關鍵的是,除了數組元素之外沒有任何對象arr(換句話說,對象arr數組元素)。

但是數組下標操作a[i]定義爲*(a + i);也就是說,給定地址a,我們從該地址抵消了i元素(而不是字節!)並取消了結果。

a數組,而不是一個指針,所以如何工作?

這樣的 - 除了當它是sizeof或一元&運營商的操作數,或是使用在聲明初始化另一個數組文本字符串,表達型的NT - 元素陣列」,將被轉換(「衰減」)爲類型「指向T的指針」的表達式,並且該表達式的值將是該數組的第一個元素的地址。

因此,在像

printf("a = %p\n", (void *) a); // *always* use `%p` to print pointer values 

代碼表達a不是sizeof或一元&運營商的操作數,因此它被轉換(「衰變」),以類型的表達式「指針T」 ,表達式的值是第一個元素的地址。

這裏有一個方便的表來記錄一些這樣的:


    Expression  Type  "Decays" to  Value 
    ----------  ----  -----------  ----- 
      a  T [N]  T *    Address of first element 
      &a  T (*)[N] n/a    Same value as above, different type 
      *a  T   n/a    Value of first element 
     a[i]  T   n/a    Value of i'th element 
     &a[i]  T *   n/a    Address of i'th element 
    sizeof a  size_t  n/a    Number of bytes in array 
    sizeof *a  size_t  n/a    Number of bytes in single element 
sizeof a[i]  size_t  n/a    Same as above 
    sizeof &a  size_t  n/a    Number of bytes in pointer to array 
sizeof &a[i]  size_t  n/a    Number of bytes in pointer to single element 

因此,sizeof a == sizeof (T [N])sizeof *a == sizeof (T)sizeof &a == sizeof (T (*)[N])sizeof &a[i] == sizeof (T *)

注意,表達式a&a&a[0]所有產生相同(數組的第一元素的地址),但類型中表達的將是不同的。 a*&a[0]均具有類型T *(指向T),但&a具有類型T (*)[N](指向N-元素數組T)。這對指針算術等事情很重要。例如,假定下面的代碼:

T a[N]; 
T *p = a; 
T (*ap)[N] = &a; 

printf(" p = %p, p + 1 = %p\n", (void *) p, (void *) p + 1); 
printf("ap = %p, ap + 1 = %p\n", (void *) ap, (void *) ap + 1); 

p + 1將產生陣列的下一個元素的以下p地址。 ap + 1將產生當前數組之後的下一個N - 元素數組T的地址。

沒有爲struct或其他聚合類型沒有相應的轉換規則,因爲沒有必要治療struct表達在某些情況下與他人的指針。組件選擇運算符.->與下標運算符的工作方式不同。


1. C由稱爲B較早的編程語言派生(去圖),並在乙存儲預留一個「指針」到所述陣列的所述第一元件(在B,指針只是整數偏移量)。 Ritchie在開始設計C時保留了B的數組語義,但是當他開始添加struct類型時遇到了問題;他不想在結構數據中混合數組指針元數據。他通過創建上述轉換規則來解決問題。