c编程中的整数数组

时间:2014-01-18 12:06:10

标签: c

我在学校有这个家庭作业,我必须评估以下代码的输出:

#include<stdio.h>
int main()
{
    int a[2][2] = {1, 2, 3, 4};
    int i, j;
    int *p[] = {(int*)a, (int*)a+1, (int*)a+2};
    for(i=0; i<2; i++)
    {
        for(j=0; j<2; j++)
        {
            printf("%d, %d, %d, %d\n",
              *(*(p+i)+j), *(*(j+p)+i),
              *(*(i+p)+j), *(*(p+j)+i));
        }
    }
    return 0;
}

输出是:

1,1,1,1
2,2,2,2
2,2,2,2,
3,3,3,3

我没有学习,但我把它作为家庭作业,是这些内容:

int a[2][2] = {1, 2, 3, 4};
int *p[] = {(int*)a, (int*)a+1, (int*)a+2};

我也不明白*(*(p+i)+j)*(*(i+p)+j)之间的区别。谢谢。

3 个答案:

答案 0 :(得分:0)

实际上你需要了解编译器如何看待数组。 正如您所提到的*(*(p+i)+j)*(*(i+p)+j)

实际上编译器会将*(*(p+i)+j)视为*(*(address of P + number of increment in memory block)+number of increment in memory block)

假设p是值为5000且i = 2,j = 3

的基址

*(*(p+i)+j) = *(*(5000+2)+3) = *(*(5008)+3)

*(*(i+p)+j) = *(*(2+5000)+3) = *(*(5008)+3)

正如你所看到的,结果都是一样的。 我假设编译器将整数分配为4个字节。 希望这会对你有所帮助。

答案 1 :(得分:0)

int a[2][2] = {1, 2, 3, 4};

这是编写int a[2][2] = {{1, 2}, {3, 4}};

的可怕方式

这是一个二维数组。因此,a可以被解释为指向它的第一个元素的指针,即{1,2}的地址。同样,a + 1是{3,4}的地址。

int *p[] = {(int*)a, (int*)a+1, (int*)a+2};

将其解析为int *p[] = {(int*)a, (int*)(a+1), (int*)(a+2)};

不,实际上是((int*)a)+1等等。

每个强制转换(int *)将指向数组{1,2}的指针转换为指向int 1的指针。

它使用aa + sizeof(int[2])a + 2 * sizeof(int[2])三个二维数组中第一个int的地址填充int *数组。第三个是不存在的,是指针“越过末端”。

即使a不是一维数组,它也会使用poiinters填充数组,即使它不是一维数组。

所有这些都是一样的。

*(*(p+i)+j), *(*(j+p)+i),
*(*(i+p)+j), *(*(p+j)+i));

(p + i) == (i + p)(cummutativity)和(*(j+p)+i) == p[j][i]以及(*(p+i)+j) == p[i][j]。但是p[x][y] == *((int*)a + x) + y) == a[x + y]所以p[j][i] == p[i][j] == (a[i + j])

C语言中的{p> *(array_name + i)主要用于在array_name[i]完全可以理解时混淆用户。

答案 2 :(得分:-1)

你正在触及多维数组,指针和双重解除引用:你要么是几个月(可能接近一年),要么你的老师希望能让你们认真对待这个课程(很多人都认为CS课程很简单)。或许她是个虐待狂。很难说,真的。

“我也不明白(p + i)+ j)和(i + p)+ j)之间有什么区别” 没有区别。这就是每行输出重复相同数字的原因。每条线以数学方式评估相同的内容。我认为这是试图证明指针只是一个数字。

我将试着解释清楚:内存是一个连续的数据序列。 你的第一行证明了这一点。     int a [2] [2] = {1,2,3,4}; 专注于最后一部分     {1,2,3,4} 这实际上是一个数据列表。第一个数据是1,第二个是2,第三个是3,等等。你可以很容易地反转这个 - 数据根本不必匹配序列。例如,{100,43,512,-1}会产生输出:

  

100,100,100,100   43,43,43,43   512,512,512,512   -1,-1,-1,-1   并且,在计算机的内存中,这些内容是连续存储的;一个接一个。

现在,在通常被认为是错误形式的情况下,您的老师选择将此单个列表定义为两个列表的列表(在CS术语中,是两个数组的数组)。 a [2] [2]基本上与声明“a是两个数组的数组,每个数组包含两个元素”,或者“我有两个列表,其中包含两个元素”。

因为所有内存都是连续的,所以这两个数组都是相互连续的。在内存中,它就像第二个数组刚刚添加到第一个数组的末尾一样。这就是为什么你可以有两个元素的数组,每个元素表示为一个包含四个元素的数组(2 * 2 = 4)。

她写这条线的另一种方式是:     int a [2] [2] = {{1,2},{3,4}}; 要么     int a [4] = {1,2,3,4}; 要么     int a [] = {1,2,3,4};

我认为你至少对编码有一点了解,所以我不会侮辱你解释i和j或循环。

...留下了这个宝石:

int *p[] = {(int*)a, (int*)a+1, (int*)a+2};

'p'是我们称之为指针数组的东西。指针是表示内存中位置的数字。所有记忆都是连续的。这意味着如果你从可以存储在内存中的第一个“int”开始,并且一次向前移动一个int直到你到达pth int,那么你将在内存p表示的位置。我们称它们为指针,因为它们“指向”内存。 此外,数组也是指针。 “a”指向它的第一个元素。所以我们可以再次重写第一行:

int *a = { 1, 2, 3, 4 };

(免责声明:它可能无法编译,从未见过以前编写过的代码,但它基本上是我们已经为文本做的。) 第三行可以这样重写:

int *p[] = (int *)a;
希望我能够对你解释得很好!

另外,告诉你的老师这样的代码如果伴随着一系列令人沮丧和抱歉的评论,甚至可以解释为什么决定以这种方式编写代码,并且你会更好地服务显示代码可以在现实世界中使用,而不是这种学术上的废话。