C語言函數的調用 - 百度經驗

2020-12-08 百度經驗

在一個程序的編寫過程中,隨著代碼量的增加,如果把所有的語句都寫到 main 函數中,一方面程序會顯得的比較亂,另外一個方面,當同一個功能需要在不同地方執行時,我們就得再重複寫一遍相同的語句。此時,如果把一些零碎的功能單獨 寫成一個函數,在需要它們時只需進行一些簡單的函數調用,這樣既有助於程序結構的清晰條理,又可以避免大塊的代碼重複。

在實際工程項目中,一個程序通常都是由很多個子程序模塊組成的,一個模塊實現一個特定的功能,在 C 語言中,這個模塊就用函數來表示。一個 C 程序一般由一個主函數和若干個其他函數構成。主函數可以調用其它函數,其它函數也可以相互調用,但其它函數不能調用主函數。在我們的 51 單片機程序中,還有中斷服務函數,是當相應的中斷到來後自動調用的,不需要也不能由其它函數來調用。

函數調用的一般形式是:    函數名 (實參列表);函數名就是需要調用的函數的名稱,實參列表就是根據實際需求調用函數要傳遞給被調用函數的參數列表,不需要傳遞參數時只保留括號就可以了,傳遞多個參數時參數之間要用逗號隔開。

那麼我先舉例看一下函數調用使程序結構更加條理清晰方面的作用。回顧一下圖 6-1 所示的程序流程圖和為實現它而編寫的程序代碼,相對來說這個主函數的結構就比較複雜了,

很難一眼看清楚它的執行流程。那麼如果我們把其中最重要的兩件事——秒計數和數碼管動態掃描功能都用單獨的函數來實現會怎樣呢?來看程序。

#include <reg52.h>sbit ADDR0 = P1^0;sbit ADDR1 = P1^1;sbit ADDR2 = P1^2;sbit ADDR3 = P1^3;sbit ENLED = P1^4;unsigned char code LedChar[] = {  //數碼管顯示字符轉換表0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E};unsigned char LedBuff[6] = {  //數碼管顯示緩衝區,初值 0xFF 確保啟動時都不亮0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};void SecondCount();void LedRefresh();

void main(){ENLED = 0;  //使能 U3,選擇控制數碼管ADDR3 = 1;  //因為需要動態改變 ADDR0-2 的值,所以不需要再初始化了TMOD = 0x01;  //設置 T0 為模式 1TH0 = 0xFC;  //為 T0 賦初值 0xFC67,定時 1msTL0 = 0x67;TR0 = 1;  //啟動 T0while (1){if (TF0 == 1){  //判斷 T0 是否溢出TF0 = 0;  //T0 溢出後,清零中斷標誌TH0 = 0xFC;  //並重新賦初值TL0 = 0x67;SecondCount();  //調用秒計數函數LedRefresh();  //調用顯示刷新函數}}}/* 秒計數函數,每秒進行一次秒數+1,並轉換為數碼管顯示字符 */void SecondCount(){static unsigned int cnt = 0;  //記錄 T0 中斷次數static unsigned long sec = 0;  //記錄經過的秒數cnt++;  //計數值自加 1if (cnt >= 1000){  //判斷 T0 溢出是否達到 1000 次cnt = 0;  //達到 1000 次後計數值清零sec++;  //秒計數自加 1LedBuff[0] = LedChar[sec%10];LedBuff[1] = LedChar[sec/10%10];LedBuff[2] = LedChar[sec/100%10];LedBuff[3] = LedChar[sec/1000%10];LedBuff[4] = LedChar[sec/10000%10];LedBuff[5] = LedChar[sec/100000%10];}}

/* 數碼管動態掃描刷新函數 */void LedRefresh(){static unsigned char i = 0; //動態掃描的索引switch (i){case 0: ADDR2=0; ADDR1=0; ADDR0=0; i++; P0=LedBuff[0]; break;case 1: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=LedBuff[1]; break;case 2: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=LedBuff[2]; break;case 3: ADDR2=0; ADDR1=1; ADDR0=1; i++; P0=LedBuff[3]; break;case 4: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=LedBuff[4]; break;case 5: ADDR2=1; ADDR1=0; ADDR0=1; i=0; P0=LedBuff[5]; break;default: break;}}

看一下,主函數的結構是不是清晰的多了——每隔 1ms 就去幹兩件事,至於這兩件事是什麼交由各自的函數去實現。還請大家注意一點:原來程序中的 i、cnt、sec 這三個變量在放到單獨的函數中後,都加了 static 關鍵字而變成了靜態變量。因為原來的 main()永遠不會結束所以它們的值也總是得到保持的,但現在它們在各自的功能函數內,如不加 static 修飾那麼每次函數被調用時它們的值就都成了初值了,藉此也把靜態變量再加深一下理解吧。當然,這是我們刻意把程序功能做了這樣的劃分,主要目的還是來講解函數的調用,對於這個程序即使你不劃分函數也複雜不到哪裡去,但繼續學下去你就能領會到劃分功能函數的必要了。現在我們還是把注意力放在學習函數調用上,有以下幾點需要大家注意:1) 函數調用的時候,不需要加函數類型。我們在主函數內調用 SecondCount()和LedRefresh()時都沒有加 void。

2) 調用函數與被調用函數的位置關係,C 語言規定:函數在被調用之前,必須先被定義或聲明。意思就是說:在一個文件中,一個函數應該先定義,然後才能被調用,也就是調用函數應位於被調用函數的下 方。但是作為一種通常的編程規範,我們推薦 main 函數寫在最前面(因為它起到提綱挈領的作用),其後再定義各個功能函數,而中斷函數則寫在文件的最後。那麼主函數要調用定義在它之後的函數怎麼辦呢?我們 就在文件開頭,所有函數定義之前,開闢一塊區域,叫做函數聲明區,用來把被調用的函數聲明一下,如此,該函數就可以被隨意調用了。如上述例程所示。3) 函數聲明的時候必須加函數類型,函數的形式參數,最後加上一個分號表示結束。函數聲明行與函數定義行的唯一區別就是最後的分號,其它的都必須保持一致。這 點請尤其注意,初學者很容易因粗心大意而搞錯分號或是修改了定義行中的形參卻忘了修改聲明行中的形參,導致程序編譯不過。

相關焦點

  • Python使用ctypes模塊調用DLL函數之C語言數組與numpy數組傳遞
    在Python語言中,可以使用ctypes模塊調用其它如C++語言編寫的動態連結庫DLL文件中的函數,在提高軟體運行效率的同時,也可以充分利用目前市面上各種第三方的DLL庫函數,以擴充Python軟體的功能及應用領域,減少重複編寫代碼、重複造輪子的工作量,這也充分體現了Python語言作為一種膠水語言所特有的優勢
  • 你知道C語言中函數調用和嵌套嗎?函數必學模塊,你不得不知!
    一、函數調用 什麼是函數調用呢?通常在C語言中,一個完整的項目程序是不可能在一個函數中實現所有的功能。而是由若干功能不同的函數來實現,並且函數之間會存在互相調用的情況。
  • C語言陷阱與技巧第15節,為什麼每調用一次函數,就需要一次if判斷...
    在C語言程序開發中,調用一個有返回值的函數時,一般要對函數的返回值做判斷,以確定函數是否按照預期執行。如果被調用函數沒有按照預期執行,最好加上相應的錯誤處理代碼,否則最終編譯得到的C語言程序穩定性就不夠好,遇到一點點意外,可能就不會正常工作了。沒有判斷C語言函數的返回值,會有什麼問題?
  • 很多C語言初學者都非常好奇的問題,怎樣定義可以可變參數函數?
    >隨著學習的推進,初學者逐步學會調用別的C語言函數,以及定義自己的函數,觀察力敏銳的會注意到 printf() 函數似乎與其他函數不太一樣——printf()函數沒有固定數目的參數,它似乎可以接收任意多的參數。
  • C語言中的main()函數可以有好幾種類型,為何都能做入口函數呢?
    基本上,幾乎每一個初學者在剛接觸C語言時,都會被告知C語言程序的默認入口是 main() 函數,程序總是從入口函數處開始運行。按照我之前文章中的討論,對於可變參數函數,例如 printf() 函數,或者未明確指定參數的函數,例如 void fun(); ,在被調用時,是允許傳入任意多參數的:printf("...");printf("...
  • Python使用ctypes模塊調用DLL函數之複數數組的參數傳遞
    這兒就涉及到了如何將C語言中的複數數組(Complex array)類型與Python中的數據類型進行交互的問題。在Python語言中,可以使用ctypes模塊調用其它如C++語言編寫的動態連結庫DLL文件中的函數,前面多篇文章中已經講了傳遞數值/指針/字符串參數、傳遞結構體參數、傳遞普通數組類型的例子,大家可以回看一下,這樣可以更好的理解本次要講的內容。
  • ARM中ADS環境下C語言和彙編語言混合編程及示例
    彙編語言是和CPU的指令集緊密相連的,作為涉及底層的嵌入式系統開發,熟練對應彙編語言的使用也是必須的。這裡主要討論C和彙編的混合編程,包括相互之間的函數調用。下面分四種情況來進行討論,不涉及C++語言。
  • DSP編程技巧之24---C/C++與彙編語言的交互之-(2)從C/C++代碼調用...
    在C/C++與彙編語言混合編程的情況下,一般我們都會選擇C/C++來實現所期待的大部分功能,對於少數和硬體關聯度高(例如操作某些CPU寄存器)以及對運算的實時性要求高(例如高速、多點的FFT)的功能才使用彙編來實現,這就使得大多數情況下,C/C++與彙編的交互都是從C/C++代碼調用彙編代碼中的函數與變量,所以在此我們就來看一下這種調用的規則。
  • C語言 main 函數到底為啥這麼寫?
    但 凡是學過C語言的人,都知道要先寫main函數,然而很多時候我們看到的main函數卻各有差異,這究竟是為啥? 哪種是對的呢? 今天我們就來聊聊main函數。 比較常見的寫法,這種寫法的形參為void,表明它在調用的時候不能傳入任何參數,那麼它也就不能獲取命令行參數了。 和上面第3種看起來好像沒啥區別,但是還是有些許不同。
  • C語言陷阱與技巧第2節,使用inline函數可以提升程序效率,但是讓...
    其實,從 inline 這個名字就應該能看出一點它的性質了——內聯函數會在它被調用的位置上展開,這一點表現的和 define 宏定義是非常相似的。將被調用的函數代碼展開,作業系統就無需再在為被調用函數做申請棧幀和回收棧幀的工作,而且,由於編譯器會把被調用的函數代碼和函數本身放在一起優化,所以也有進一步優化C語言代碼,提升效率的可能。
  • C語言中函數的形參與實參是什麼?
    在發生函數調用時,主調函數把實參的值傳送給被調函數的形參從而實現主調函數向被調函數的數據傳送。函數的形參和實參具有以下特點:1. 形參變量只有在被調用時才分配內存單元,在調用結束時,即刻釋放所分配的內存單元。因此,形參只有在函數內部有效。函數調用結束返回主調函數後則不能再使用該形參變量。
  • 第五篇:C語言中有關函數的相關知識點梳理
    函數是C語言中,組織程序的最基本的結構單元。我們最初學習C語言的第一個程序就是寫在主函數main()裡面的。在學習函數具體應用之前,我們只認識一個主函數,所有的代碼都必須寫在主函數裡面。01理解「函數」在C語言中,除了主函數、系統函數,還可以根據需要定製函數。
  • C語言程序設計試題及答案
    A) 程序行 B) 語句 C) 函數 D) 字符2、C語言規定,在一個源程序中main函數的位置( )。A) 必須在最開始 B) 必須在系統調用的庫函數的後面C) 可以任意 D) 必須在最後3、下列符號串中符合C語言語法的標識符是( )。
  • 自考「C語言程序設計」模擬試題十一
    「c」    B.『\\』『    C.』W『   D. 』『  14.若有代數式3ae/bc,則不正確的c語言表達式是(     )  A.a/b/c*e*3    B.3*a*e/b/c    C.3*a*e/b*c    D.a*e/c/c*3  15.在C語言中,要求運算數必須是整型的運算符是(   )  A./    B.++   C
  • 深入理解C語言
    導讀:Dennis Ritchie過世了,他發明了C語言,一個影響深遠並徹底改變世界的計算機語言。一門經歷40多年的到今天還長盛不訓的語言,今天很多語言都受到C的影響,C++,Java,C#,Perl,PHP,Javascript等等。但是,你對C了解嗎?相信你看過本站的《C語言的謎題》還有《誰說C語言很簡單?》。
  • C語言編程:以實例教你學指向函數的指針
    指針是C語言的精髓,對於初學者來講,指針是C語言語法學習中比較難的知識點,而這裡面指向函數的指針更是不太容易理解。下面給大家講下怎樣學習理解C語言中指向函數的指針及編程方法和使用例子。注意:這是一篇關於C語言編程的基礎語法內容,C語言大神請繞過。
  • r語言work_r語言work函數 - CSDN
    R的源起R是S語言的一種實現。S語言是由 AT&T貝爾實驗室開發的一種用來進行數據探索、統計分析、作圖的解釋型語言。最初S語言的實現版本主要是S-PLUS。S-PLUS是一個商業 軟體,它基於S語言,並由MathSoft公司的統計科學部進一步完善。
  • 定義只有一個數組成員的C語言結構體有什麼用?
    在C語言程序開發中,有經驗的程式設計師有時會定義只有一個數組成員的結構體,雖然語法簡單,但是卻常常讓初學者感到迷惑:這麼做有什麼好處嗎?struct ABC {unsigned long array[MAX];} abc;
  • C語言中的main函數參數,你了解嗎?
    小豆丁:今天我才發現,C語言中main函數還有參數,可是我不知道這個參數表示的是什麼含義,也不知道怎麼用。老張:就這點問題?小豆丁:嗯吶,我沒研究明白,好沮喪...老張:這個問題不難,別放棄哈,我教你!
  • 在C語言中如何高效地複製和連接字符串?
    就目前而言,在編程領域中,C語言的運用非常之多,它兼顧了高級語言的彙編語言的優點,相較於其它程式語言具有較大優勢。作者 | Martin Sebor譯者 | 蘇本如,責編 | 劉靜以下為譯文:在所有標準C語言<string.h>頭文件中聲明的字符串處理函數中,最常用的是那些用來複製和連接字符串的函數。