C語言函數
在使用visual studio練習編程的時候,可能會出現這樣的情況:做了很多的語法練習,既有單獨一行語句的練習,也有解決一個課後習題這樣一個完整的程序,它們都在同一個main()主函數中,在調試中可能要注釋掉一些代碼,單獨去看當前的一段代碼,這樣操作有點繁瑣,而且主函數越來越“臃腫”顯得結構混亂,那怎樣能解決這個問題呢?如果把要調試的這段代碼獨立出來,和其他代碼互不影響,需要的時候再去主函數裡調用,這樣就會使得練習調試方便的多,這段獨立代碼的形式就是今天的主題——函數。
注意,請認真學習完《C程序設計(第五版)》第七章後再閱讀本文會有更大的收獲。
函數我們可以把函數理解成一個迷你型的程序,它有輸入輸出,也實現了某些算法邏輯。
函數輸入——參數
一般基礎類型參數,如整型、浮點、字符等,實參的值傳遞給形參,它們互不影響。
數組類型的參數,由于數組實參傳遞的是數組首個元素的存儲地址,所以形參實際上還是指向同一個數組的,如果形參的值發生變化,相應的實參也會受影響。
函數輸出——返回值
通常,我們會統一函數定義的數據類型和return值的數據類型,應該避免“強制數據類型轉換”的情況,讓程序更加的嚴謹。
當然,嚴謹也就意味着失去一些“自由度”,其他的語言比如PHP、Python沒有這樣的要求,它們甚至沒有函數數據類型這樣的定義。畢竟每種語言的設計初衷和理念都不太相同,在今後的學習使用中去體會設計者的思路。
函數體
函數體是函數的核心,函數功能的實現都在這裡進行編碼。在構建函數體的過程中,推薦的做法是先寫出框架,再補齊邏輯代碼。比如函數體内有一個for循環,那就先出for循環的框架,然後再寫continue以及break跳出循環的判斷節點,最後再來補齊這裡面的邏輯。
函數調用自定義函數調用
當前源文件調用,在自定義函數之前調用要聲明,之後則不用聲明。
其他源文件調用,要用extern進行聲明。
系統函數調用
使用系統函數前要包含進來相應的頭文件,比如使用數學函數sqrt()要在文件開頭包含math.h頭文件:#include <math.h>,前面還用過字符串相關的系統函數,以及最普遍的系統标準輸入輸出函數。
嵌套調用
函數A的函數體内調用函數B,函數B的函數體内調用函數C……需要注意的是不能“反調用”,比如A調用B,B又調用了A,或者A調用B,B調用C,C裡又調用A,這樣就形成了“死循環”。
遞歸調用
所謂函數的遞歸調用就是返回值裡有部分構成是函數自身。在寫遞歸函數需要注意的點是遞歸是有限的,一定要有終止的邏輯,讓遞歸函數不再調用自身從而結束遞歸;否則無限遞歸下去也是一種“死循環”。
如果遞歸過程中要存儲一些過程中的數據,這時候可以使用static局部變量使得靜态化存儲,或者以形參數組的形式在函數内部使用。
函數作用域C語言中,默認自定義的函數是外部函數,即全局函數,可以被其他源文件調用;而内部函數則是相對于函數所在的源文件來界定的,隻能在當前源文件内被調用。
所以,函數作用域最小範圍是其所在的源文件,除此之外就是作用于全局(所有源文件)。
變量作用域和存儲類型書中的表7.2總結得很全面,了解作用域和存儲類型,使得我們在寫程序的時候更加嚴謹規範,不随意定義全局的變量,使程序數據更加“安全”。
對于初學者來說,這些偏理論的知識往往都比較難理解,也很枯燥。筆者推薦在學習的過程中結合visual studio進行實操練習,通過代碼輔助增強對這些理論知識的理解;做到知其然也知其所以然,培養好的編程習慣,從底層了解變量的作用域和存儲特性,也為學習其他的高級語言做鋪墊。
static關鍵字static外部變量/外部函數
當static關鍵字作用在外部變量/外部函數上,意味着該外部變量/外部函數隻能在當前的源文件内進行使用,無法跨文件調用。
static局部變量
當static關鍵字作用在内部變量上,意味着該局部變量不随着所在函數調用完畢後釋放内存,即存儲方式由動态存儲變為靜态存儲。
實戰編程首先,看一下練習編程的目錄結構和多個源文件互相調用運行的規則,順便把剛學習的知識運用上。
練習目錄結構
在源文件目錄下創.c結尾的源文件,程序運行的入口文件是main.c,從main()函數開始執行。筆者把每一章節的程序練習單獨建立對應的源文件如lesson7.c,在lesson7.c裡再創建lesson7()函數,這個函數相當于它所在源文件的主函數,然後在main()函數裡調用lesson7(),具體結構如下:
注意,這裡的單個源文件中定義的練習函數都加了static關鍵詞表示僅在當前源文件中調用,這樣避免與其他源文件同名時造成沖突。
寫兩個函數分别求兩個整數的最大公約數和最小公倍數
這個題目在之前的練習中已經做過,具體算法不再分析,參考一下:
static int maxCommonDivisor(int a, int b) {
int divisor = 1;
for (int i = 1; i <= a; i )
{
if (a % i == 0 && b % i == 0) {
divisor = i;
}
}
return divisor;
}
static int minCommonMultiple(int a, int b) {
int multiple = 1;
int min = a > b ? b : a;
int i = 1;
while (1)
{
multiple = min * i;
if (multiple % a == 0 && multiple % b == 0) {
return multiple;
}
i ;
}
}
寫一個函數,使給定的一個3x3的二維數組轉置,即行列互換。
這個題目很簡單,比較直接的實現思路是把給定的數組拷貝一份,然後循環把數組的元素重新賦值即可,賦值邏輯為:array[i][j] = arrayCopy[j][i]。為了加深理解函數的嵌套調用,我們增加兩個函數:一個是輸出二維數組函數,做轉置前後的輸出對比;另一個是拷貝二維數組的函數,供轉置函數去調用,代碼參考如下:
static void transpose(int array[3][3]);
static void printfArray(int array[3][3]);
int array[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
printfArray(array, 3);
transpose(array);
printf("=====================\n");
printfArray(array, 3);
static void printfArray(int array[][3], int length) {
for (int i = 0; i < length; i ) {
for (int j = 0; j < length; j )
{
printf("%d\t", array[i][j]);
}
printf("\n");
}
}
static void transpose(int array[3][3]) {
int length = 3;
int array_copy[3][3];
static void copyArray(int dest_array[][3], int origin_array[][3], int length);
copyArray(array_copy, array, length);
for (int i = 0; i < length; i ) {
for (int j = 0; j < length; j )
{
array[i][j] = array_copy[j][i];
}
}
}
static void copyArray(int dest_array[][3], int origin_array[][3], int length) {
for (int i = 0; i < length; i ) {
for (int j = 0; j < length; j )
{
dest_array[i][j] = origin_array[i][j];
}
}
}
用遞歸法将一個整數n轉換成字符串。例如輸入483,應輸出字符串“483”。n的位數不确定,可以是任意位數的整數。
本題明确使用遞歸函數,函數的輸入是一個n位數,輸出是個位數(末位數)。算法的核心就是求每一位的數字:
總結一下這個算法就是:對于輸入的數據算出末位數字并輸出,然後把輸入數據的末位截掉變成下次調用的輸入值,隻要當前數據不是1位數,那就繼續遞歸調用下去。
遞歸調用的條件是至關重要的,這裡通過判斷對10取餘的結果是不是他自身來決定是否一直遞歸調用下去,代碼參考:
static void printLastnumber(long number) {
int n = number % 10;
if (n != number) {
printLastNumber(number / 10);
}
n = (n < 0 && n != number) ? -n : n;
printf("%d", n);
}
PS:如果輸入值為負數,則判斷一下不是取到最後一位就把負數轉成正數輸出,不判斷會把“-123”輸出成“-1-2-3”。
總結函數的定義和設計參考以下幾點:
在熟練掌握C語言函數的用法和一些特性之後,就可以組織構建模塊進行常規的項目開發了,後續筆者會做一些簡單的但是模塊體系相對完善的項目演練,我們一起通過具體項目的開發練習來把C語言這門工具用起來。
往期文章一起學《C程序設計》第六課——數組、字符串及實戰練習
一起學《C程序設計》第五課——循環控制及實戰練習
一起學《C程序設計》第四課——if語句、switch語句及實戰練習
一起學《C程序設計》第三課——數據結構、運算符、表達式和語句
一起學《C程序設計》第二課——算法
一起學《C程序設計》第一課——C語言概述和學習前的準備、意識
C程序設計(譚浩強)——第五版和第三版對比
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!