複製鏈接
請複製以下鏈接發送給好友

main函數

鎖定
main函數,又稱主函數,是程序執行的起點,main是相對來説的,如同音學理論之主調於泛音,泛音即程序中的除main之外的其他函數,迎合人們的思考方式而生成的而非必定的模式。有主有次,執行起來條清縷析,既可將程序模塊化又實現了一個閉合的整體。
中文名
函數
外文名
function main
用    途
函數調用
返回值類型
c語言一般要求int(整數類型)
參數類型
無參和帶參
編程語言
C/C++、Java、C#等

main函數簡介

程序執行總是從main函數開始,如果有有其他函數,則完成對其他函數的調用後再返回到主函數,最後由main函數結束整個程序。在執行程序時,由系統調用main函數 [1]  。main 函數是在程序啓動中完成對具有靜態存儲期的非局部對象的初始化之後被調用的。它是程序在有宿主 (hosted)環境(亦即有操作系統)中所指定的入口點。自立程序(啓動加載器,操作系統內核,等等)的入口點則是由實現定義的。
主函數的兩個形參形式中的形參,允許從執行環境中傳遞任意的多字節字符串(它們通常被稱為命令行參數),各個指針 argv[1] .. argv[argc-1] 指向每個這些字符串的第一個字符。argv[0] 是指向一個表示用於執行該程序自身的名字的空結尾多字節字符串(或者當執行環境不支持時,為空字符串 "")的開頭字符的指針。這些字符串是可以改動的,雖然對它們的改動並不會被傳回給執行環境:比如可以用 std::strtok 來使用它們。由 argv 所指向的數組的大小至少為 argc+1,其最後一個元素 argv[argc] 保證為一個空指針。

main函數參數

模塊化程序設計方法是把整個程序劃分為若干功能較為單一的程序模塊,然後分別予以實現,最後再把所有的程序模塊像搭積木一樣裝配起來。利用函數可以實現程序的模塊化,可以大大地減輕編碼工作量。在函數內部或複合語句塊內部定義的 auto 類型變量稱為局部變量。局部變量的作用域從該局部變量定義的位置開始到本函數或複合語句結束處。局部變量的生存期較短暫。當局部變量所在的函數被調用時,局部變量內存空間被分配,函數調用結束後,局部變量內存空間被釋放。函數的形參和實參均屬於局部變量,調用函數時,形參內存空間被分配。函數調用結束後,形參內存空間被釋放。C語言函數參數傳遞可分為三種情況:簡單變量作為函數參數、數組名作為函數參數以及指針作為函數參數 [2] 
C程序最大的特點就是所有的程序都是用函數來裝配的。main()稱之為主函數,是所有程序運行的入口。其餘函數分為有參或無參兩種,均由main()函數或其它一般函數調用,若調用的是有參函數,則參數在調用時傳遞。
int main(void)//整數類型 主函數(無類型)
{
...
y1=f1(x1,x2);//賦值過程
...
}

f1(int a,int b)//f1(整數類型 a,整數類型 b)
{
//百度百科示例代碼.....
Y2=f2(x3,x4);//賦值過程
//百度百科示例代碼
}
f2(int m,int n)//f2(整數類型 m,整數類型 n)
{
//百度百科示例代碼
}
在前面課程的學習中,對main()函數始終作為主調函數處理,也就是説,允許main()調用其它函數並傳遞參數。事實上,main()函數既可以是無參函數,也可以是有參的函數。對於有參的形式來説,就需要向其傳遞參數。
我們先看一下main()函數的帶參的形式:
int main(int argc,char **argv)//整數類型 主函數(整數類型 統計參數個數,字符類型 **指針至字符)
{
//百度百科示例代碼......
}
從函數參數的形式上看,包含一個整型和一個指向字符指針的指針。當一個C的源程序經過編譯、鏈接後,會生成擴展名為.EXE的可執行文件(對windows操作系統而言),這是可以在操作系統下直接運行的文件,換句話説,就是由系統來啓動運行的。由系統在啓動運行時傳遞參數。
在操作系統環境下,一條完整的運行命令應包括兩部分:命令與相應的參數。其格式為:
命令參數1參數2....參數nt;
此格式也稱為命令行。命令行中的命令就是可執行文件的文件名,其後所跟參數需用空格分隔,併為對命令的進一步補充,也即是傳遞給main()函數的參數。
命令行與main()函數的參數存在如下的關係:
設命令行為:program str1 str2 str3 str4 str5
其中program為文件名,也就是一個由program.c經編譯、鏈接後生成的可執行文件program.exe,其後各跟5個參數。對main()函數來説,它的參數argc記錄了命令行中命令與參數的個數,共6個,指針數組的大小由參數argc的值決定,即為char*argv[6],指針數組的取值情況如圖6-15所示。
圖6-15 圖6-15
數組的各指針分別指向一個字符串。應當引起注意的是接收到的指針數組的各指針是從命令行的開始接收的,首先接收到的是命令,其後才是參數。
下面用實例來説明帶參數的main()函數的正確使用。
[例6-29] 利用圖形庫函數繪製一個變化的環。它是把一個半徑為R 1的圓周分成n份,然後以每個等分點為圓心,以R s為半徑畫n個圓(關於作圖的詳細理論本教材第9章第1節作了專門介紹,這裏只作簡單分析)。利用main()函數的帶參數形式,我們可以從鍵盤以命令行的方式輸入R 1和R s及屏幕的背景色。
#include <graphics.h>//包含圖形庫函數的頭文件
#include <math.h>
#define pi 3.1415926
intmain(int argc,char **argv)
{
int x,y,r1,rs,color;
double a;
int gdriver=DETECT,gmode;
initgraph(&gdriver,&gmode,"..\\bgi")//啓動圖形工作方式
r1=atoi(argv[1]);//計算基礎圓半徑
rs=atoi(argv[2]);//計算同心圓半徑
color=atoi(argv[3]);//背景色
cleardevice();//清除圖形屏幕
setbkcolor(color);//設置背景色
setcolor⑷;//設置圖形顯示顏色
for(a=0;a<=2*pi;a+=pi/18)//繪製同心圓
{
x=r1*cos(a)+320;
y=r1*sin(a)+240;
circle(x,y,rs);//以圓心座標為x、y,半徑為rs畫圓
}
getch();//等待按鍵繼續
closegraph();//關閉圖形工作方式
return 0;
}
圖6-16
若程序名為L6-29.c,經編譯、連結生成可執行文件L6-29.exe。在操作系統的環境下運行程序,命令行方式為:
具體步驟:
1、Win + R打開運行;
2、輸入cmd打開命令行;
3、進入到要執行的exe文件所在目錄,如要要執行E:\程序設計\Ctest.exe文件,則輸入E:回車(注意:如果要更改其他盤目錄必須首先進入要進入盤的根目錄,例如進入E盤則輸入E:不用輸入cd E:)進入E盤根目錄,再輸入cd E:\程序設計 則進入了當前目錄,最後就可以輸入參數了,例如Ctest yishi weban回車即可(Ctest為要執行的可執行文件,後面兩個也為要傳遞給main函數的參數);
l6-29 40 20 3
則命令行與main()函數的參數有如圖6-16所示的關係
圖6-16中,argv[0]是程序名,argv[1]是r1的值,
argv[2]是rs的值,argv[3]是屏幕的背景色。
由於指針數組均存放字符串,所需的圓半徑及背景
色彩通過atoi()函數轉換為整型。
通過帶參數的main()函數,我們可以為自己的程序設置口令,在運行程序的命令行中給出所需的口令,正確則繼續,否則退出。程序圖形輸出如圖6-17所示。
圖6-17 圖6-17
[例6-30]將上述程序作修改,在程序的入口處添置密碼,若給定密碼正確,則顯示圖形。
#include<graphics.h>
#include<math.h>
#definepi3.1415926
int main(int argc, char **argv)
{
intx,y,r1,rs,color;
doublea;
intgdriver=DETECT,gmode;
if(strcmp(argv[1],"pass")!=0)//設置口令的比較
{printf("passworderror!\n");
exit(0);
}
initgraph(&gdriver,&gmode,"..\\bgi");
r1=atoi(argv[2]);
rs=atoi(argv[3]);
color=atoi(argv[4]);
cleardevice();
setbkcolor(color);
setcolor⑷;
for(a=0;a<=2*pi;a+=pi/18)
{
x=r1*cos(a)+320;
y=r1*sin(a)+240;
circle(x,y,rs);
}
getch();
closegraph();
return0;
}
在操作系統的環境下運行程序, 命令行中增加口令“pass”,命令行方式為:
l6-30 pass 20 40 3
指針數組的存儲字符串如圖6-18所示。
圖6-18 圖6-18
若給定字符串argv[1]的值是pass,則程序正確運行,否則程序退出。口令正確的情況下,顯示的圖形為圖6-17中的一個。

main函數函數分類

  1. 從用户使用的角度看,函數有兩種:
1、標準函數,即庫函數。這是由系統提供的。
2、用户自定義的函數。可以解決用户的專門需要。
二、從函數的形式看,函數分兩類:
1、無參函數。printstar和print_message就是無參函數。在調用無參函數時,主調函數並不將數據傳送被調用函數,一般用來執行指定的一組操作。
2、有參函數。在調用函數時,在主調函數和被調用函數之間有數據傳遞。也就是説,主調函數可以將數據傳遞給被調用函數使用,被調用函數中的數據也可以帶回來供主調函數使用。

main函數一般形式

無參函數
類型標示符 函數名()
{
函數體
}
有參函數定義
類型標示符 函數名 (形式參數列表)
{
函數體
}
可以有空函數
它的形式為
類型説明符 函數名()
{ }
例如:
dummy(){}
傳統方式
在老版本c語言中,對形參類型的聲明是放在函數定義的第二行,也就是不在第一行的括號內指定形參的類型,而在括號外單獨指定,例如上面定義的max函數可以寫成一下形式:
int max(x,y)/*整數類型max函數;並指定形式參數x,y*/
int x,y;/*整數類型x,y;形式參數xy是整數類型*/
{int z;/*整數類型z*/
z=x>y?x:y;
return(z);
}

main函數返回值

在 C89 標準中,main( ) 是可以接受的。Brian W. Kernighan 和 Dennis M. Ritchie 的經典鉅著 The C programming Language 用的就是 main( )。不過在最新的 C99 標準中,只有以下兩種定義方式是正確的:
int main(void){/*百度百科示例代碼*/}//整數類型主函數(無類型)
int main(int argc,char **argv)//整數類型主函數(整數類型 統計參數個數,字符類型*數組指針至字符[])
其中char **argv可以寫成char *argv[],兩者等價
main 函數的返回值類型必須是 int ,這樣返回值才能傳遞給程序的激活者(如操作系統)。
如果 main 函數的最後沒有寫 return 語句的話,C99 規定編譯器要自動在生成的目標文件中(如 exe 文件)加入return 0; ,表示程序正常退出。不過,我還是建議你最好在main函數的最後加上return 語句,雖然沒有這個必要,但這是一個好的習慣。
也就是説在最新的C語言標準中強制要求main函數的返回值類型為int,main函數的返回值是傳遞給操作系統,讓操作系統判斷程序的執行情況(是正常結束還是出現異常)
誤區
很多人甚至市面上的一些書籍,都使用了void main() ,其實這是錯誤的。C/C++中從來沒有定義過void main()。C++之父Bjarne Stroustrup在他的主頁上的FAQ中明確地寫着The definition void main() {/*...*/} is not and never has been C++, nor has it even been C.(void main() 從來就不存在於C++或者C)。
在C和C++中,不接收任何參數也不返回任何信息的函數原型為“void foo(void);”。可能正是因為這個,所以很多人都誤認為如果不需要程序返回值時可以把main函數定義成void main(void) 或void main()。然而這是錯誤的!main函數的返回值應該定義為int類型,C和C++標準中都是這樣規定的。雖然在一些編譯器中,void main可以通過編譯(如vc6),但並非所有編譯器都支持void main,因為標準中從來沒有定義過void main。g++3.2、dev C++等環境中如果main函數的返回值不是int類型,根本無法通過編譯。而gcc3.2則會發出警告。所以,如果你想你的程序擁有很好的可移植性,請一定要用int main。

main函數應用

C++中的main函數
C++繼承了C語言的大部分特性,因此保留了“程序總是從main函數開始執行,且總是默認從main函數的return語句或結尾處結束運行”這一傳統,但是要注意,C++中的main函數要想作為程序執行的出入口,必須寫在全局(Global)範圍,不能寫成某個結構體或某個的成員。雖然main函數可以作為結構體或者類的成員函數,但相應地會失去作為程序出入口的功能。
C++中全局main函數的書寫格式與C語言完全相同,功能也完全相同,且同一C++程序同樣只能有一個全局main函數。
Java中的main函數
Java同樣是以main函數作為程序執行出入口的,但Java作為“更純潔”的面向對象語言,它的main函數與C/C++有很大的不同。
首先,返回值的概念淡化,在Java Application中main不允許返回值,因此int main是被禁止的,必須使用void main,int main僅限在JavaBean中使用。
其次,Java中所有的函數必須屬於類,沒有什麼全局函數一説,因此main函數不能是全局成員,必須是某個類的成員。
第三,由於main函數變成了類的成員函數,因此要想直接被系統調用,還必須使用public static使其成為靜態函數並具有公開權限。
第四,main函數的參數被簡化,只需要提供字符串數組即可,不需要提供參數個數(這是由於Java的數組具有下標檢查功能的原因)
Java Application中的main函數一般格式如下(類名可以自定義,但保存為Java源碼時,主文件名必須與類名相同,否則可能無法運行)
public class MainDemo { 
    public static void main(String[] args){
        //TODO:在此處寫入主函數的內容
    }
}
Java Applet的運行機制與Java Application完全不同,因此不需要main函數
C#中的main函數
C#中的main函數與Java大同小異,同樣必須是類成員,同樣使用字符串數組作唯 一參數,同樣是靜態函數,同樣的void main,與之不同的是:main的首字母變成了大寫,即"Main函數“,且是否限定為public級別已經無所謂了(默認沒有public,但某些場合可能還是需要public)
另外,需要注意的是,C#中不再有”類名必須與主文件名同名“的限制,即使類名不和主文件名相同,程序照樣可以運行。
C#應用程序中的main函數默認是這樣的(注意main的首字母已是大寫)
C#和C/C++、java不同的是C#不在拘泥於必須從main()函數開始執行,C#是屬於事件觸發。
class Program {
    static void Main(string[] args){
                //TODO:在此處寫入主函數的內容
    }
}
參考資料