一個C程序可以由若幹個源程序文件組成,每一個源文件可以由若幹個函數和預處理命令以及全局變量聲明部分組成,每一個函數由函數首部和函數體組成。c程序的結構如圖所示。
作為一名程序開發人員,不可能每次編寫都從最底層開發。比如在上例中,要輸入一串字符到輸出設備上,我們需要做的僅是調用printf()函數,至于"Hello C! "是怎樣顯示的,我們并不關心。我們認識printf()函數,在編寫程序時調用它,更需要讓程序認識它,這樣才能使用printf()函數提供的功能,這就需要使用#include <stdio.h>,包含标準輸入輸出頭文件,這樣程序就能夠認識printf()函數,并執行其功能。
C提供有豐富的函數集,我們稱之為标準函數庫。标準函數庫包括15個頭文件,借助這些函數可以完成不同的功能。
例如, 【範例2-1】中有#include<math.h>時,就可以使用該數學函數庫頭文件提供的如開平方函數sqrt(),求出半徑radius為2時的開平方值1.414;又如,當程序包含頭文件"malloc.h"時,就可以完成對内存申請和釋放等功能。
2.2.2函數聲明
标準C語言引入了新的更好的函數聲明方法,即用函數原型指定函數更多的信息,通過函數原型可以将函數的名字和函數類型以及形式參數的個數、類型、順序通知編譯系統,以便在調用函數時,系統可以對照檢查。
函數聲明由函數返回類型、函數名和形參列表組成。形參列表必須包括形參類型,但是不必對形參命名。這3個元素被稱為函數原型,函數原型描述了函數的接口。定義函數的程序員提供函數原型,使用函數的程序員就隻需要對函數原型編輯即可。
函數聲明的一般形式為:
函數返回類型函數名(參數類型1,參數類型2,......);
函數聲明包括函數的返回類型和函數名,來看下面這個例子。
01 int fun (int a, int b);
02 void display();
03 float fn (float x);
其中, int, void和float都是函數返回類型,也屬于數據類型。fun, display和fn是所調用的函數名。也就是說, fun()函數返回的數據類型為整型int; display()函數返回的類型為void型,指函數無返回值; fn()返回的數據類型為浮點型float。
fun (int a, int b)數内部的a和b為形參,其參數類型都為int型。fn (float x )函數内部參數x的類型為float型。函數聲明中的形參名往往被忽略,如果聲明中提供了形參的名字,也隻是用作輔助文檔。另外要注意函數聲明是一個語句,後面不可漏分号!
進一步對函數做解釋,需要注意的有以下幾點。
(1)函數名稱後面必須有小括号,不能省略,這是函數的特征。
(2)函數結束必須有分号,不能省略。
(3)字符串結尾有這樣的内容"\n" ,它叫做轉義符,表示的合義是把光标移動到下一行的行首,也就是回車換行,因為我們無法直接通過鍵盤輸入換行的指令,所以需要使用轉義符;又比如輸出内容後希望返回該行的行首,重新輸出内容,鍵盤上也沒有對應的功能鍵,我們就可以使用回車符轉義符"\r"來代替。當然,轉義還包含其他内容,後續拿節中會詳細講達。
2.2.3變量聲明
在大多數語言中,在使用一個變量之前,都要對這個變量進行聲明, C語言同樣如此。那麼,什麼是變量的聲明呢?有什麼作用呢?變量的聲明其實就是在程序運行前,告訴編譯器程序使用的變量以及與這些變量相關的屬性,包括變量的名稱、類型和長度等。這樣,在程序運行前,編譯器就可以知道怎樣給變量分配内存空間,可以優化程序。
變量的聲明語句的形式如下:
變量類型名變量名
變量的聲明包括變量類型名和變量名兩個部分。來看下面的例子:
01 int num
02 double area
03 char ppt
其中, int、double和char是變量類型名, num、area和ppt是變量名。其實,變量類型名也是數據類型的一種,就是說變量num是int類型, area是double類型, ppt是char類型。
變量類型名是C語言自帶的數據類型和用戶自定義的數據類型。C語言自帶的數據類型包括整型、字符型、浮點型、枚舉型和指針類型等。
變量名其實就是一個标識符,當然,标識符的命名規則在此處同樣适用。除此之外,變量命名的時候還需要注意以下幾點。
(1) 變量名區分大小寫,變量Num和num是兩個不同的變量。
(2) 變量的命名最好與實際應用有關聯,例如: num一般表示數量, area表示面積等。
(3)變量的命名必須在變量使用之前。
提示
如果變量沒有經過聲明而直接使用,則會出現編譯器報錯的現象。
下面用一個例子來驗證聲明必須在變量使用的前面。
【範例2-2】驗證未聲明的标識符不可用。
(1) 在Visual C 6.0中,新建名為"undeclaredvar.c"的【Text File】文件。
(2)在編輯窗口中輸入以下代碼(代碼2-2.txt) 。
01 #include<stdio.h>
02 int main(void)
03{
04 print ("output undeclaredvar num-%d\n",num);
05 return 0:
06}
【運行結果】
編譯後顯示出錯,信息如下:
undeclaredvar.c(4): error C2065: ‘num': undeclared identifier
【範例分析】在此例子中,沒有對标識符num進行聲明就直接引用,編譯器不知道num是什麼,所以調試時編譯器就會報錯。
【拓展訓練】
在第3句和第4句之間插入語句:
04 int num=10;
或者:
04 int num;
05 num=10;
檢驗一下程序能否運行,是否還報錯。
2.3主函數
每個C程序必須有而且隻有一個主函數,也就是main()函數,它是程序的入口。main()函數有時也作為-種驅動,按次序控制調用其他函數, C程序是由函數構成的,這使得程序容易實現模塊化; main()函數後面的"()"不可省略,表示函數的參數列表; "{"和"}"是函數開始和結束的标志,不可省略。
下圖是對主函數調用其他函數的說明。
主函數main()在程序中可以放在任何位置,但是編譯器都會首先找到它,并從它開始運行。它就像汽車的引擎,控制程序中各部分的執行次序。下圖是對主函數各部分名稱的說明。
在前面的兩個範例中,主函數main()的部首都是int類型, int是整數integer單詞的縮寫,表示返回給系統的數據類型是整型數據,返回值是0,在return句中體現了出來。
2.4函數定義區
C語言編譯系統是由上往下編譯的。一般被調函數放在主調函數後面時,前面就該有聲明,不然C語言由上往下的編譯系統将無法識别。正如變量必須先聲明後使用一樣,函數也必須在被調用之前先聲明,否則無法調用!函數的聲明可以與定義分離,要注意的是一個函數隻能被定義一次,但可以聲明多次。
函數定義:
返回類型函數名(參數類型1參數名1,...,參數類型n參數名n)
{
函數體...
}
例如
int fun(int a,intb)
{
int c;
c=a b;
return c;
}
在程序中,如果main()函數在前,必須在mian()中寫函數聲明;如果函數在main()前面,可以不在main()中寫函數聲明!
下面看一個有關函數聲明和函數定義的綜合例子,比較一下它們有何不同。
#include<stdio.h>
int add(intx,int y);//函數聲明語句
Main()
{
int a,b,c;
c=add(a,b);
printf("%d",c);
}
Intadd(int x,int y)//函數定義
{
int z;
z=x y;
return z;
}
2.5注程
讀者可能已經注意到,很多語句後面都跟有"/*"和"*/"符号,它們表示什麼含義呢?
在前文已經說過,我們在編輯代碼的過程中,希望加上一些說明的文字,來表示代碼的含義,這是很有必要的。
費了很大精力,絞盡腦汁編寫的代碼,如果沒有寫注釋或者注釋得不夠清楚,一年後又要使用這段代碼時,當年的思路全部記不得了,無奈之中,隻得重分析、重理解。試問,因為當初一時的懶散造成了今日的結局,值得嗎?又比如,一個小組共同開發程序,别人需要在該小組寫的代碼上進行二次開發,如果代碼很複雜、沒有注釋,恐怕隻能用4個字形容組員此時的心情:欲哭無淚。所以,編寫代碼時最好書寫注釋,這樣做有百利而無一弊。
注釋的要求如下。
(1)使用"/*"和"*/"表示注釋的起止,注釋内容寫在這兩個符号之間,注釋表示對某語句的說明,不屬于程序代碼的範疇,比如【範例1-1】和【範例2-1】代碼中"/*"和"*/"之間的内容。
(2) "/"和"*"之間沒有空格。
(3)注釋可以注釋單行,也可以注釋多行,而且注釋不允許嵌套,嵌套會産生錯誤,比如:
/*這樣的注釋/*特别*/有用*/
這段注釋放在程序中不但起不到說明的作用,反而會使程序産生錯覺,原因是“這樣”前面
的"/*"與“特别”後面的"*/"匹配,注釋結束,而“有用*/"就被編譯器認為是違反語法規則的代碼。
2.6代碼的規矩
從書寫代碼清晰,便于閱讀、理解、維護的角度出發,在書寫程序時應遵循以下規則。
(1)一個說明或一個語句占一行。我們把空格符、制表符、換行符等統稱為空白符。除了字符串、函數名和關鍵字, C忽略所有的空白符,在其他地方出現時,隻起間隔作用,編譯程序對它們忽略不計。因此在程序中使用空白符與否,對程序的編譯不産生影響,但在程序中适當的地方使用空白符,可以增加程序的清晰性和可讀性。
例如下面的代碼:
int
main(
){
printf( "Hello C!\n”
);
}/*這樣的寫法也能運行,但是太亂,很不妥*/
(2)用“{"和"}"括起來的部分,通常表示程序某一層次的結構。"{"和“}"一般與該結構語句的第1個字母對齊,并單獨占一行。
例如下面的代碼:
int main()
{
printf( "Hello C!\n");
return 0;}/*這樣的寫法也能運行,但是閱讀起來比較費事*/
(3)低一層次的語句通常比高一層次的語句留有一個縮進後再書寫。一般來說,縮進指的是存在兩個空格或者一個制表符的空白位置。
例如下面的代碼:
int main()
{
print( "Hello C!\n" );
{
printf( "Hello C!\n" );
}
return 0;
}
(3) 在程序中書寫注釋,用于說明程序做了什麼,同樣可以增加程序的清晰性和可讀性。
(4) 以上介紹的4點規則,大家在編程時應力求遵循,以養成良好的編程習慣。
2.7高手點撥
文件中聲明函數,就像變量可以在頭文件中聲明,而在源文件中定義一樣,函數也可以在頭文件中聲明,在源文件中定義。把函數聲明直接放在每個使用該函數的源文件中是大多數新手習慣并喜愛的方式,這是合法的。但是這種方式古闆且易出錯。解決方法就是把函數的聲明放在頭文件中,這樣可以确保指定函數的所有聲明保持一緻。如果函數接口發生變化,則隻需修改其唯一的聲明即可。
将提供函數聲明的頭文件包含在定義該函數的源文件中,可使編譯器能檢查該函數的定義和聲明是否一緻。特别地,如果函數定義和函數聲明的形參列表一緻,但返回類型不一緻,編譯器會發出警告或出錯信息來指出差異。
那麼學過了函數聲明與函數定義,它們到底有什麼不同呢?我們知道函數的定義是一個完整的函數單元,它包含函數類型、函數名、形參及形參類型、函數體等,并且在程序中,函數的定義隻能有一次,函數首部與花括号間也不加分号。而函數聲明隻是對定義函數的返回值類型進行說明,以通知系統在本函數中所調用的函數是什麼類型。它不包含函數體,并且調用幾次該函數就應在各個主調函數中作相應聲明,函數聲明是一個說明話句,必須以分号結束!
學習了這一堂的内容,讀者是不是對C語言有更好的理解呢?下面了解一下我們在使用函數時,需要注意的一些問題。
1、函數聲明可以省略形參名,但是函數定義的首部必須寫出所有形參名并給出其對應的數據類型。
2、函數原型的主要目的是為了聲明函數返回值類型以及函數期望接受的參數的個數、參數類型和參數順序。
3、如果程序中沒有某個函數的函數原型(沒有說明) ,編譯系統就會用第一次出現的這個函數(函數定義或函數調用)構造函數原型。
4、在默認下,編譯系統默認函數返回值為int。
在編寫函數時的常見錯誤:當調用的函數與函數原型不相匹配時,程序會提示語法錯誤,并且當函數原型和函數定義不一緻時,也會産生錯誤。
本文節選自《C語言從入門到精通(第2版)》
本書面向C語言的零基礎讀者,介紹基礎入門知識和實際操作技巧。全書緊貼軟件開發的實際需求,首先向讀者展示語言的背景知識和應用範圍,之後通過實例和自測,系統講解相關知識點,同時兼顧實際開發項目經驗。為了增強實用性,光盤中還特别贈送了精選的考試認證、求職面試等題庫,供讀者研究學習。最後,為幫助初入職場的從業者順利進入角色,還在光盤中贈送了職業規劃建議及相關開發文檔。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!