我刚刚开始搞乱结构和指针。
这是我的.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,或者是&amp; accounts [0],没关系。
帐户数组地址为1606416480
如果我用*帐户替换&帐户,我会得到:
帐户数组地址为1063600
第二个输出是:
账户n°1归David所有 ,其地址是1606416480
帐号n°2归Toto所有 ,其地址是1606416488
实际上这些是账户中包含的@账户指针,这些@在内存中每个自我占用8B。
如果我用帐户[i]替换&amp; accounts [i],那么通过* accounts [i]我得到:
账户n°1归David所有 ,其地址是1063600
账户n°2由Toto拥有,其地址为1063632
账户n°1归David所有 ,其地址是3874
帐号n°2归Toto所有 ,其地址是3880
在第一种情况下,我有2个指针,在第二种情况下,我有2个指针。
* STRUCT和STRUCT是不同的,为什么?
答案 0 :(得分:1)
数组在内部表示为连续的内存范围。在范围的最开始,放置了数组的第一个元素。
如果您的数组的名称与问题<div class="post_nav">
<div class="last">Last</div>
<div class="home"> </div>
<div class="next">Next</div>
</div>
.post_nav { position: relative; width: 30%; margin: 10px auto; text-align: center; font-family: 'Bitter', Georgia, serif; font-weight: 700; color: #c9c9c9; }
.post_nav div { display: inline-block; text-transform: uppercase; padding: 0 20px; }
.post_nav .last:before { content: ""; width: 30px; height: 30px; line-height: 20px ; background: url('http://i.imgur.com/BlY1jqF.png') no-repeat -60px 0; float: left; margin: auto 5px; overflow: hidden; }
.post_nav .home:before { content: ""; width: 30px; height: 30px; line-height: 30px ; background: url('http://i.imgur.com/BlY1jqF.png') no-repeat -120px 0; float: left; margin: auto 5px; padding: 0; overflow: hidden; }
.post_nav .next:after { content: ""; width: 30px; height: 30px; line-height: 30px ; background: url('http://i.imgur.com/BlY1jqF.png') no-repeat -90px 0; float: right; margin: auto 5px; overflow: hidden; }
中的方式相同,那么数组的地址和数组的第一个元素的地址具有相同的值。
如果要考虑你的例子,那么你有
accounts
表达式中的数组(例外情况,例如在sizeof运算符中使用它们)被转换为指向其第一个元素的指针。
因此,表达式Account * accounts[2];
具有类型accounts
和等式
Account **
评估为真。
表达式accounts == &accounts[0]
具有相同的值,因为它是范围的地址,但是具有不同的类型。它的类型是
&accounts
那就是你写的例子
Account * ( * )[2]
然后输出将等于16,因为在运行自己的代码的环境中,指针的大小等于8,而数组由两个指针元素组成。
你可能不会写条件
Account *( *p )[2] = accounts;
printf( "*p = %zu\n", sizeof( *p ) );
因为操作数有不同的类型。但是如果你写的话
&accounts == accounts
然后这个条件评估为真。
所以表达式的值
( void *)&accounts == ( void * ) accounts
,&accounts
和accounts
彼此相等,是数组占用的内存范围的地址。
对于结构,结构的地址等于其第一个成员的地址。但是,结构类型的对象名称不会隐式转换为指向其第一个成员的指针。
如果我用帐户[i]替换&amp; accounts [i],那么通过* accounts [i]我得到:
&accounts[0]
给出数组元素的地址。所以你会得到价值
&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 * )
给出存储在数组元素中的值。它们是结构类型的每个对象的动态alllocated内存的地址。
* accounts [i]是结构类型的对象。由于printf调用中的格式说明符与作为参数传递的对象不对应,因此函数行为未定义。
考虑到要打印指针,您必须使用格式说明符accounts[i]
。
答案 1 :(得分:0)
TL / DR版本:
数组很特殊,在大多数情况下,数组表达式被视为指向数组第一个元素的指针。 a
和&a
将产生相同的值(数组a
的第一个元素的地址),尽管表达式的类型会有所不同。
struct
类型(或任何其他聚合类型)不是这种情况。
David Foster Wallace版本:
除非它是sizeof
或一元&
运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,表达式为输入&#34; N
- T
&#34;的元素数组将被转换(&#34;衰减&#34;)到类型为#34的表达式;指向T
&#34;的指针,并且表达式的值将是该表达式中第一个元素的地址阵列。
为什么会这样?
首先,让我们看一下数组在内存中的表示方式。鉴于声明
T a[N];
然后你得到的东西看起来像这样:
+---+
a: | | a[0]
+---+
| | a[1]
+---+
...
+---+
| | a[N-1]
+---+
为数组元素留出存储空间,没有别的;没有任何元数据的存储空间,也没有任何指向数组第一个元素的指针。关键的是,除了数组元素之外没有对象arr
(换句话说,对象arr
是数组元素)。
但是数组下标操作a[i]
定义为*(a + i)
;也就是说,给定地址a
,我们从该地址偏移i
个元素(不是字节!)并取消引用结果。
但是a
是一个数组,而不是指针,那么它是如何工作的呢?
像这样 - 除非它是sizeof
或一元&
运算符的操作数,或者是用于初始化声明中另一个数组的字符串文字,表达式类型&#34; N
- 元素数组T
&#34;将被转换(&#34;衰减&#34;)到类型为&#34的表达式;指向T
&#34;的指针,并且表达式的值将是第一个元素的地址。阵列 1
因此,在像
这样的代码中printf( "a = %p\n", (void *) a ); // *always* use `%p` to print pointer values
表达式a
不是sizeof
或一元&
运算符的操作数,因此它被转换为(&#34;衰变&#34;)到类型为&的表达式#34;指向T
&#34;的指针,表达式的值是第一个元素的地址。
这里有一个方便的表格来记住其中一些:
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
因此,i
,i
,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
的指针-element数组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(go figure),而B存储是为&#34;指针&#34;到数组的第一个元素(在B中,指针只是整数偏移)。 Ritchie在开始设计C时保留了B的数组语义,但在他开始添加
.
类型时遇到了问题。他不想在结构数据中混合数组指针元数据。他通过创建上述转换规则解决了这个问题。