跳至內容

C語言中的多型資料結構/函式呼叫

來自華夏公益教科書,自由的教科書

所有C程式都包含函式呼叫。例如,在最簡單的“Hello World”程式中,使用了一個函式呼叫

#include <stdio.h>
int main( int argc , char *argv[] ) {
   printf( "Hello, world.\n" ) ;
   return 0 ;
}

函式printf()以字串“Hello, world.\n”作為引數,並將文字作為結果顯示在螢幕上。

簡單引數

[編輯 | 編輯原始碼]

當呼叫函式時,會為該函式的區域性變數分配記憶體空間,並將引數的值複製並放置到函式的記憶體空間中。這就是為什麼C語言有時被稱為“按值呼叫”語言的原因。一個簡單的檢驗這個原理的方法是使用一個名為“No Swap”的程式。

#include <stdio.h>

void noswap( int x , int y ) ;
int main( int argc , char *argv[] ) {

   int x , y ;
   x = 5 ;
   y = 9 ;

   printf( "The values of x and y are %d and %d before the function noswap.\n" , x , y ) ;
   noswap( x , y ) ;
   printf( "The values of x and y are %d and %d after the function noswap.\n" , x , y ) ;

   return 0 ;

}
void noswap( int x , int y ) {

   int temp ;

   temp = x ;
   x = y ;
   y = temp ;

}

該程式的輸出將是

The values of x and y are 5 and 9 before the function noswap.
The values of x and y are 5 and 9 after the function noswap.

該程式的目的是交換x和y的值,但顯然情況並非如此。這是因為實際的變數x和y沒有傳遞給函式noswap(),而是複製了變數的值並推入函式的執行時堆疊。可以透過操作這種行為以及給定函式的返回值來建立瞬時處理的錯覺。以下程式碼是一個簡單的加法程式,它演示了將兩個整數加在一起的能力。

#include <stdio.h>

int add( int x , int y ) ;
int main( int argc , char *argv[] ) {

   int x , y ;

   printf( "Please enter two integers to be added together: " ) ;
   scanf( "%d %d" , &x , &y ) ;
   printf( "The sum of %d and %d is %d.\n" , x , y , add( x , y ) ) ;

   return 0 ;

}
int add( int x , int y ) {

   return ( x + y ) ;

}

嘗試編輯add()函式使其進行減法、乘法或求冪運算(在不新增其他C庫的情況下最難),而不是加法。

C語言中的所有型別都可以按值傳遞,包括結構體、聯合體和陣列。

指標作為引數

[編輯 | 編輯原始碼]

使用指標作為引數是修改除宣告它的函式之外的函式中區域性變數的唯一方法。使用指標作為引數是一種被稱為“模擬按引用呼叫”的方法。它的用法相當簡單:程式不是傳遞變數值的副本,而是簡單地傳遞指向呼叫函式中實際值的指標。因此,必須在被呼叫函式中對變數進行解引用。讓我們再次研究“No Swap”,但現在它將被稱為“Swap”。

#include <stdio.h>

void swap( int *x , int *y ) ;
int main( int argc , char *argv[] ) {

   int x , y ;
   x = 5 ;
   y = 9 ;

   printf( "The values of x and y are %d and %d before the function swap.\n" , x , y ) ;
   swap( &x , &y ) ;
   printf( "The values of x and y are %d and %d after the function swap.\n" , x , y ) ;

   return 0 ;

}
void swap( int *x , int *y ) {

   int temp ;

   temp = *x ;
   *x = *y ;
   *y = temp ;

}

該程式的輸出將是

The values of x and y are 5 and 9 before the function noswap.
The values of x and y are 9 and 5 after the function noswap.

請注意,當呼叫swap()時,使用了取地址運算子 (&)。這是因為x和y都不是指標。在變數名後附加取地址運算子會導致傳遞變數的指標而不是副本。由於指標只是指向變數地址的引用,因此會建立一個指標的副本並傳遞給函式,這就是為什麼這種方法只是模擬按引用呼叫,而不是真正的按引用呼叫。

陣列作為引數

[編輯 | 編輯原始碼]

陣列的處理方式與其他變數不同。這是因為它們的名稱(沒有下標 [] 來表示特定值)只是一個指向陣列第一個專案的指標。因此,A&A[0] 相同。此外,像 *A 這樣的解引用將返回 A[0] 的值。

由於這種行為,將陣列傳遞給函式並修改它們非常容易。

#include <stdio.h>

void array_copy( int *A , int *B ) ;
int main( int argc , char *argv[] ) {

   int i ;
   int array[5] ;
   int other_array[5] ;

   printf( "Please enter five numbers, separated by a space: " ) ;
   for ( i = 0 ; i < 5 ; i++ ) scanf( "%d" , &array[i] ) ;
   for ( i = 0 ; i < 5 ; i++ ) printf( "%d " , array[i] ) ;
   printf( "\n" ) ;

   array_copy( array , other_array ) ;

   for ( i = 0 ; i < 5 ; i++ ) printf( "%d " , other_array[i] ) ;
   printf( "\n" ) ;

   return 0 ;

}
void array_copy( int *A , int *B ) {

   int i ;

   for ( i = 0 ; i < 5 ; i++ ) B[i] = A[i] ;

}

請注意,即使在呼叫array_copy()時沒有使用取地址運算子,兩行的輸出也是相同的。這是因為陣列基址已經是指標。

華夏公益教科書