tft每日頭條

 > 圖文

 > c語言函數程序設計的思路

c語言函數程序設計的思路

圖文 更新时间:2024-11-25 22:59:19

c語言函數程序設計的思路(一起學C程序設計第七課)1

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語言函數程序設計的思路(一起學C程序設計第七課)2

練習目錄結構

在源文件目錄下創.c結尾的源文件,程序運行的入口文件是main.c,從main()函數開始執行。筆者把每一章節的程序練習單獨建立對應的源文件如lesson7.c,在lesson7.c裡再創建lesson7()函數,這個函數相當于它所在源文件的主函數,然後在main()函數裡調用lesson7(),具體結構如下:

c語言函數程序設計的思路(一起學C程序設計第七課)3

c語言函數程序設計的思路(一起學C程序設計第七課)4

注意,這裡的單個源文件中定義的練習函數都加了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. n位數直接對10取餘,得到個位上的數字
  2. n位數除以10取整,然後再對10取餘,得到十位上的數字
  3. n位數除以100取整,然後再對10取餘,得到百位上的數字

總結一下這個算法就是:對于輸入的數據算出末位數字并輸出,然後把輸入數據的末位截掉變成下次調用的輸入值,隻要當前數據不是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”。

總結

函數的定義和設計參考以下幾點:

  1. 複用性,在項目裡有很多模塊,如果模塊1中要按照某種算法計算兩個數的關聯性,模塊2中也要用同樣的算法計算兩個數的關聯性,這樣我們就可以把計算兩個數關聯性的代碼提取出來作為單獨的函數,再去供不同的模塊調用。
  2. 可擴展,一個函數根據用戶數據做商品推薦,随着用戶行為的不斷豐富,函數體的推薦算法也不斷的優化,在不改變函數的輸入和輸出的前提下去做功能性的擴展和補充。
  3. 解耦合,一個函數A處理輸入的時候又要用函數B來預處理輸入,或者經過計算後再用函數C去輸出,這裡A依賴其他函數B和C,使它們之間耦合性增強,牽一發而動全身,這樣的函數設計是不提倡的。
  4. 抽象,在之前的文章也提到過“要把業務問題抽象成數學問題”,這一點在後面做實際的項目中才能有深刻的認知。

在熟練掌握C語言函數的用法和一些特性之後,就可以組織構建模塊進行常規的項目開發了,後續筆者會做一些簡單的但是模塊體系相對完善的項目演練,我們一起通過具體項目的開發練習來把C語言這門工具用起來。

往期文章

一起學《C程序設計》第六課——數組、字符串及實戰練習

一起學《C程序設計》第五課——循環控制及實戰練習

一起學《C程序設計》第四課——if語句、switch語句及實戰練習

一起學《C程序設計》第三課——數據結構、運算符、表達式和語句

一起學《C程序設計》第二課——算法

一起學《C程序設計》第一課——C語言概述和學習前的準備、意識

C程序設計(譚浩強)——第五版和第三版對比

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关圖文资讯推荐

热门圖文资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved