2014-04-08 60 views
2

我知道不可能将数组传递给C中的函数,并且无需使用发送引用的方式对其进行修改,那么Chess方法如何初始化数组并将其打印正确的主要?C修改数组意外行为

int chess(int rows, int cols, int array[rows][cols]) 
{ 

    /* Go through the rows and colums in the array */ 
    for (int i = 0; i < rows;i++) 
    { 

    for (int j = 0; j < cols; j++) 
    { 
     /* If the location is even, then print a 0, else print a 1. */ 
     if (((i + j) % 2) ==0) 
     { 
     array[i][j] = 0; 
     } 
     else 
     { 
     array[i][j] = 1; 
     } 
    } 
    } 
    /* return */ 
    return 0; 

} 

int main(void) 
{ 
    int arrayDimensions; 

    int noOfTests = 7; 

    /* run the program for the given amount of tests */ 
    /*for (arrayDimensions = 0; arrayDimensions <= noOfTests; arrayDimensions++)*/ 
    { 
    /* Declare an array for each dimension */ 
    int array[6][5]; 

    /* call the chess method passing it the arguments specified. */ 
    chess(6, 5, array); 

    /* Print out the array according to the size of the array. */ 
    for (int i = 0; i < 6; i++) 
    { 
     printf("\n"); 
     for (int j = 0; j < 5; j++) 
     { 
     printf("%d", array[i][j]); 
     } 

    } 
    /* Create a new line after each row */ 
    printf("\n"); 

    } 

} 

回答

3

虽然你可能已经知道了大部分这一点,但后半部分是相关的,所以暂时留下来。

你可能知道什么

C是一个传递价值的语言。这意味着,当你这样做:

void foo(int x) 
{ 
    x = 5; 
} 

称为

int n = 1; 
foo(n); 
printf("%d\n", n); // n is still 1 

调用者传递一个值,x接收它的参数。但更改x对呼叫者没有影响。如果你想修改一个呼叫者的数据变量,你必须这样做 - 地址。你可以通过声明的形式参数做这是一个指针到类型,解引用指针修改指向的数据,最后,通过地址变量的修改:

void foo(int *p) 
{ 
    *p = 5; 
} 

称为如:

int n = 1; 
foo(&n); 
printf("%d\n", n); // n is now 5 

为什么这么在意?

那么什么这与你的数组有关?C中的数组是数组的基础类型的连续数据序列,并且数组的表达式是其第一个元素的地址

嚼上最后一句话一分钟。这意味着一个int变量具有存储在其中的int值,数组变量具有其第一个元素的地址作为其“值”。现在你知道指针保存地址。知道和以前的描述意味着这一点:

int ar[10]; 
int *p = ar; 

是合法的。 ar的“值”是它的第一个元素地址,我们将该地址分配给指针p

好吧然后,所以语言明确定义为参数作为指针简单地指向其第一个元素。因此这两种是等效的:

void foo(int *p) 
{ 
    *p = 5; 
} 

void bar(int ar[]) 
{ 
    ar[0] = 5; 
} 

和呼叫者侧:

int ar[10]; 
foo(ar); // legal, ar's "value" is its first element address 
bar(ar); // legal, identical to the above. 

短语我经常使用说明指针和数组的基本原理时很简单:

指针是一个变量,包含的地址;一个数组是一个变量,的地址。


所以什么这个怪诞的语法?

int chess(int rows, int cols, int array[rows][cols])

啊。有一些有趣的事情。您的编译器支持VLA s (variable length arrays)。编译此函数的代码时,编译器会生成适当的逻辑以执行对传递数组的适当访问。即它知道这一点:

array[1][0] 

cols许多int值越过数组的开始。如果没有VLA的功能(并且有些C编译器没有这些功能),那么您必须亲自进行这种逐行数学计算。不是不可能的,但乏味的无路可走。我只简单地提到C++不支持VLA; C是C++中没有的少数几个特性之一。


摘要

数组由转交地址,因为当谈到自己的“价值”,这是所有他们真的是:一个地址

注:我很努力避免使用单词“衰退”或短语“衰变为指针”,在此说明,正是因为这动词意味着某种神秘功能操作时,实际上并不存在。数组不会“衰减”到任何东西。他们只是;按照C标准,它们的“价值”是它们第一个要素的地址。期。你用那个地址做是另一回事。而作为一个地址,指针可以保存它们的“值”并且取消引用来访问所述相同的值(例如函数参数)。

个人问题:我曾经在这个论坛上询问过C语言工程师这个术语(衰减)多久,因为在C标准的600多页中,它看起来完全是0。任何人发现的最远的背景是1988年在一些显眼的在线杂志的年代。我总是好奇地注意到谁是从哪里开始的,并且说 - 追求仍然在逃避我。

无论如何,我希望这有助于,甚至一点。

+0

超级回答! :) – AkshaiShah

+0

不错的工作,除非你说“我经常投币的一个短语...”,因为你只能*硬币*一个短语一次;) – RobP

+0

@RobP *优秀* = P – WhozCraig

1

当处理数组时,你正在处理一个地址,所以如果你将一个数组传递给一个函数,并且你改变了函数中的数组,那么真实数组将会改变。 换句话说,如果你知道pointers一个数组是一个指针。 我没有读过这段代码,但是对于将数组传递给函数有一个明显的误解。

0

一个数组引用是一个地址(它是一个用词不当,但它会像这样)。它的工作原理是因为该函数被声明为接受一种类型的int [] [],它允许该函数与数组引用进行交互,就好像您已经传递了该函数的指针一样。

0

从参考手册:

当一个函数参数被声明为阵列,所述编译器将 声明作为指针到所述阵列的第一个元素。例如,对于 示例,如果x是一个参数并且旨在表示整数的数组,则可以将其声明为以下任何一种声明:

int x []; int * x; int x [10];

所以你传递了一个参考。编译器将你的声明变成一个带有一些大小限制的指针引用。

+0

我不会使用短语传递参考。你正在传递一个衰减到指针的数组。 – this