2

我在教科书中看到了以下 C 代码片段,它工作正常......但我不明白输出以及为什么它工作正常,因为它看起来不对:

#include <stdio.h>

int main()
{

    struct {
        int x,y;
    } s[4] = {{10,20},{15,25},{8,75},{6,2}};
    int *i;
    i=s;

    clrscr();
    printf("\n%d",s[i[7]].x);
    printf("\n%d",i[i[1]-i[2]]);
    printf("\n%d",i[s[3].y]);
    printf("\n%d",(s+1)->x+5);
    printf("\n%d",s[i[0]-i[4]].y + 10);
    printf("\n%d",++i[i[6]]);
    getch();

    return 0;

}

另外我不明白我们如何s在语句中分配一个整数指针

i=s;
4

4 回答 4

2

我也不明白我们如何在语句中为 s 分配一个整数指针:i=s;

这很简单,你不能在没有演员表的情况下使用 C 语言。你的编译器可以接受这样的程序,但其他编译器有权拒绝编译该程序。

于 2012-06-16T16:27:32.927 回答
1

至于指针分配:

要从下面发表评论:

“整数数组和仅由整数组成的结构数组的内存布局是相同的”

必须定义指针类型的原因是编译器必须知道指针指向的数据的大小。整数的大小为 4 个字节,而此结构的大小为 8 个字节。当程序试图访问 location 的内存时,编译器知道程序需要 8 个字节之后的数据,而 where只需要 4 个字节之后的数据。s[1]s[0]i[1]i[0]

s是一个结构数组(有两个 int 类型的成员),i是一个指向 int 的指针。由于 的第一个元素s是 2 个整数的结构,i = s因此将 的第一个元素的第一个成员的地址分配si

i = &s[0]是同一个任务。

如果s[0]0x00开始,它的第一个成员的地址为0x00,而它的第二个成员的地址为0x04s[1]将从0x08开始,该位置的结构具有地址为0x0C的第二个成员。

i = s其中,具有i[0]地址0x00,而i[1]具有地址0x04,即 的第一个元素的第二个成员si[2]具有地址0x08,数组中第二个结构的第一个成员,i[3]具有地址0x0C,数组中第二个结构的第二个成员。等等...

  { 10, 20 } { 15, 25 } { 8, 75 } { 6, 2 }
s:|    0    |     1    |    2    |   3   |
i:| 0 |  1  |  2 |  3  |  4 | 5  | 6 | 7 |

i现在指向第一个整数(全部 8 个)。

i[0] = 10

i[7] = 2

第一个 printf 语句解释如下: 因为i[7] = 2, 那么我们s[2]指的{8,75}是具有 x 值的对8

指针确实不兼容,使用 gcc 版本 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1) 编译会产生以下警告

test.c:在函数'main'中:test.c:10:警告:来自不兼容的指针类型的赋值

但是,该程序会编译并生成输出:

8 75 15 20 85

于 2012-06-16T16:26:25.080 回答
1

补充一点:在 CI 中,当它出现这样的情况时,它会遵循技巧:每当你看到这样的 #type# s[p],s 是 #type# 类型的指针,s[p] 是另一种写法* (s+p)。因此 ('i' 分配了数组的基地址) 例如 -- i[i[1]-i[2]] 是 i[(*(i+1)) - (*(i+2))] => i[20 - 15] => i[5] => *(i+5) => 75。

另请注意,

1) 内部填充可用于为结构分配存储空间。例如。具有两个 int 和一个 char 的结构不一定会连续占用 4+4+2 = 10 个字节,可能存在内部填充。然而,这个只有两个整数的结构不使用内部填充。

2) 由于大多数编译器分配了不兼容的指针,将给出警告。

3) 'i' 被分配了结构数组的基地址,没有内部填充,因此这个精心设计的代码可以神奇地工作。

于 2012-06-19T05:09:46.653 回答
0

编译器将s[4]的数据存储在线性内存中,如10,20,15,25,8,75,6,2。i[7] 等于 2。这只是一个类似下面例子的技巧。

有这样的结构:

struct block{
int a;
int b;
};

struct block item;

如果我知道 的地址item->b,我怎么知道 的地址item

答案是使用item->b减号的地址((struct block *)0)->b

于 2012-06-16T16:47:29.703 回答