2014-04-08 59 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