2016-03-02 98 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类型时遇到了问题;他不想在结构数据中混合数组指针元数据。他通过创建上述转换规则来解决问题。