C語(yǔ)言獲得命令行參數(shù)的方法 每當(dāng)你運(yùn)行一個(gè)DOS或Windows程序時(shí),都會(huì)生成一個(gè)程序段前綴(Program SegmentPrefix,簡(jiǎn)稱PSP)。當(dāng)DOS程序的裝入程序把程序復(fù)制到RAM中來(lái)執(zhí)行時(shí),信謹(jǐn)它先把256個(gè)字節(jié)分配給PSP,然后把可執(zhí)行代碼復(fù)制到緊接著PSP的內(nèi)存區(qū)域中。PSP中包含了DOS為了執(zhí)行一個(gè)程序所需要的各種各樣的信息,其中的一部分?jǐn)?shù)據(jù)就是命令行。PSP中偏移量為128的那個(gè)字節(jié)中存放著命令行中的字符個(gè)數(shù),接下來(lái)的127個(gè)字節(jié)中存放著命令行本身。這也正是DOS把你能在其提示行中輸入的字符個(gè)數(shù)限制在127個(gè)之內(nèi)的原因——因?yàn)樗鼮槊钚蟹峙涞拇鎯?chǔ)空間只有那么多。遺憾的是,PSP的命令行緩沖區(qū)中并沒(méi)有存放可執(zhí)行程序的名字——而只存放著在可執(zhí)行程序名后鍵入的字符(包括空格符)。例如,如果你在DOS提示行中鍵入以下命令: XCOPY AUTOEXEC.BAT AUTOEXEC.BAK 假設(shè)XCOPY.EXE存放在c驅(qū)動(dòng)器的DOS目錄下,則李坦薯XCOPY.EXE的PSP命令行緩沖區(qū)中將包含以下信息: AUTOEXEC.BAT AUTOEXEC.BAK 注意,命令行中緊接著"XCOPY"的空格符也被復(fù)制到PSP的緩沖區(qū)中。 除了不能在PSP中找到可執(zhí)行程序名外,PSP還有一個(gè)不足之處——在命令行中能看到的對(duì)于輸出或輸入的重定向,在PSP的命令行緩沖區(qū)中是無(wú)法看到的,也就是說(shuō),你無(wú)法從PSP中得知你的程序是否被重定向過(guò)。 到現(xiàn)在為止,你應(yīng)該熟悉在C程序中可以通過(guò)argc和argv來(lái)獲取一些有關(guān)信息,但是,這些信息是怎樣從DOS的裝入程序傳給argv指針的呢?這是由程序的啟動(dòng)代碼來(lái)完成的。啟動(dòng)代碼在main()函數(shù)的第一行代碼之前被執(zhí)行,在其執(zhí)行期間,它調(diào)用一個(gè)名為__setargv()的函數(shù),把程序名和命令行從PSP和DOS環(huán)境中復(fù)制到mai‘n()函數(shù)的argv指針?biāo)赶虻木彌_區(qū)中。你可以在xLIBCE.LIB文件中找到_setargv()函數(shù),對(duì)于Small,Medium和Large這三種存儲(chǔ)模式,這里的“x”分別為“S”,“M”和“L”。在生成可執(zhí)行程序時(shí),上述庫(kù)文件會(huì)自動(dòng)被連接進(jìn)來(lái)。除了復(fù)制argv參數(shù)的內(nèi)容外,c的啟動(dòng)代碼還要完成其它一些工作。當(dāng)啟動(dòng)代碼執(zhí)行完畢后,main()函數(shù)中的代碼就開始執(zhí)行了。 在DOS中的情況是這樣的,那么在Windows中的情況又是怎樣的呢?實(shí)際上,在Windows中的情況大致上和在DOS中的一樣。當(dāng)執(zhí)行一個(gè)Windows程序時(shí),與DOS的裝入程序一樣哪者,Windows的裝入程序也會(huì)建立一個(gè)PSP,其中包含了與DOS的PSP中相同的信息。主要的區(qū)別是此時(shí)命令行被復(fù)制到lpszCmdLine參數(shù)中,它是WinMain()函數(shù)的參數(shù)表中的第三個(gè)(也是倒數(shù)第二個(gè))參數(shù)。在Windows C的xLIBCEW.LIB庫(kù)文件中包含了啟動(dòng)函數(shù)setargv(),它負(fù)責(zé)把命令行信息復(fù)制到lpszCmdLine緩沖區(qū)中。同樣,這里的“x”也表示程序所使用的存儲(chǔ)模式。在Quick c中,函數(shù)_setargv()包含在庫(kù)文件xLIBCEWQ.LIB中。 盡管DOS程序和Windows程序的命令行信息的管理方式基本相同,但是傳給你的C程序的命令行的格式在安排上稍有不同。在DOS中,啟動(dòng)代碼獲得以空格符為分隔符的命令行后,就把每個(gè)參數(shù)轉(zhuǎn)換為其自身的以NULL為終止符的字符串。因此,你可把a(bǔ)rgv原型化為一個(gè)指針數(shù)組(char* argv[]),并通過(guò)從O到n這些下標(biāo)值來(lái)訪問(wèn)每個(gè)參數(shù),其中n等于命令行中的參數(shù)個(gè)數(shù)減去1。你也可以把a(bǔ)rgv原型化為一個(gè)指向指針的指針(char **argv),并通過(guò)增減argv的值來(lái)訪問(wèn)每一個(gè)參數(shù)。 在Windows中,傳給c程序的命令行是一個(gè)LPSTR類型或char_far*類型,其中的每一個(gè)參數(shù)都用空格符隔開,就象你在DOS提示行中鍵入這些字符后所看到的那樣(實(shí)際上,在Windows中不可能真正鍵入這些字符,而是通過(guò)雙擊應(yīng)用程序圖標(biāo)這樣的方式來(lái)啟動(dòng)一個(gè)程序)。為了訪問(wèn)Windows命令行中的各個(gè)參數(shù),你必須人工地訪問(wèn)lpszCmdLine所指向的存儲(chǔ)區(qū),并分隔存放在該處的參數(shù),或者使用strtok()這樣的函數(shù),每次處理一個(gè)參數(shù)。 如果你富于探索精神,你可以仔細(xì)地研究PSP本身,并從中獲取命令行信息。為此,你可以像下面這樣來(lái)使用DOS中斷21H(此處使用Microsoft C): # include stdio. h # incIude dos. h main(int argc,char **argv){union REGS regs ; / * DOS register access struct * / char far * pspPtr; / * pointer to PSP * / int cmdLineCnt; / *num of chars in cmd line * / regs. h. ah=0x62; /*use DOS interrupt 62 *; int86(0x21 ,regs,egs) ; / *call DOS * / FP-SEG(pspPtr) =regs. x. bx ; / *save PSP segment * / FP_OFF(pspPtr)=0xS0; / * set pointer offset * / / * * pspPtr now points to the command-line count byte * / cmdLineCnt== * pspPtr ; 需要注意的是,在Small存儲(chǔ)模式下,或者在只有一個(gè)代碼段的匯編程序中,由DOS返回到BX寄存器中的值就是程序代碼段的地址值;在Large模式的c程序中,或者在多個(gè)代碼段的匯編程序中,所返回的值是程序中包含PSP的那個(gè)代碼段的段地址值。如果你已經(jīng)建立了一個(gè)指向這個(gè)數(shù)據(jù)的指針,你就可以在程序中使用這個(gè)數(shù)據(jù)了。 今天,通常你可以認(rèn)為你的程序可以使用命令行參數(shù)。但是,在DOS 2.O版以前,存儲(chǔ)在PSP中的命令行信息與現(xiàn)在稍有不同(它不能從命令行中分離出輸入或輸出重定向數(shù)據(jù)),而 且由argv[O]所指向的數(shù)據(jù)中并不一定包含可執(zhí)行程序的路徑名。直到DOS發(fā)展到3.o版,它才提供了(或者說(shuō)至少公開了)用來(lái)檢索PSP的中斷62H。因此,你至少可以認(rèn)為,在運(yùn)行DOS3.0或更高版本的PC上,你的程序總是可以獲得命令行參數(shù)的。 如果你的程序運(yùn)行在DOS 3.0或更高的版本下,你基本上就可以任意處理命令行參數(shù)了,因?yàn)檫@些信息已存入棧中供你使用。顯然,適用于棧中數(shù)據(jù)的常規(guī)的數(shù)據(jù)操作規(guī)則同樣也適用于存入棧中的命令行參數(shù)。然而,如果你的編譯程序不提供argv參數(shù),例如當(dāng)你用匯編語(yǔ)言或者某種不提供argv參數(shù)的編譯程序編寫程序時(shí),真正的問(wèn)題就出現(xiàn)了。在這種情況下,你將不得不自己找出檢索命令行參數(shù)的方法,而使用DOS中斷62H就是一種很方便的方法。 如果你要用DOS中斷62H來(lái)檢索指向命令行的指針,你必須明白該指針?biāo)赶虻臄?shù)據(jù)是供DOS使用的,并且正在被DOS使用。盡管你可以檢索這些數(shù)據(jù),但你不可以改變它們。如果在程序中需要隨時(shí)根據(jù)命令行參數(shù)作出決定,那么在使用這些數(shù)據(jù)之前應(yīng)該先把它們復(fù)制到一個(gè)局部緩沖區(qū)中,這樣就可以隨意處理這些數(shù)據(jù),而不用擔(dān)心會(huì)與DOS發(fā)生沖突了。實(shí)際上,這種技巧同樣適用于帶argv參數(shù)的c程序。位于main()函數(shù)之外的函數(shù)需要使用命令行參數(shù)的情況并不少見(jiàn),為了使這些函數(shù)能引用這些數(shù)據(jù),main()函數(shù)必須把這些數(shù)據(jù)存為全局型,或者通過(guò)(再次)入棧把它們傳遞給需要使用它們的函數(shù)。
創(chuàng)新互聯(lián)是專業(yè)的鹽山網(wǎng)站建設(shè)公司,鹽山接單;提供做網(wǎng)站、成都網(wǎng)站建設(shè),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行鹽山網(wǎng)站開發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
這個(gè)看你是怎么調(diào)用的
一般都是約定個(gè)數(shù) 或者根據(jù)第一個(gè)參數(shù),決定個(gè)數(shù)。
你這個(gè)寫法,看起來(lái)是兩個(gè)參數(shù)調(diào)用,然后都是char* ?如果是這樣
要改成
#include?stdio.h
#include?stdarg.h
void?print(char*?value,...)
{
char?*t;
printf(value);
va_list?val;
va_start(val,value);
t=va_arg(val,char*);//獲取下一個(gè)參數(shù)需要賦值的。
printf(t);
va_end(val);
}
C語(yǔ)言輸入輸出函數(shù)有很多,標(biāo)準(zhǔn)I/O函數(shù)中包含了如下幾個(gè)常用的函數(shù):
scanf,printf,getc,putc,getchar,putchar,gets,puts,fgets,fputs,fgetc,fputc,fscanf,fprintf等.
int
scanf(const
char
*format,
arg_list)
scanf主要從標(biāo)準(zhǔn)輸入流中獲取參數(shù)值,format為指定的參數(shù)格式及參數(shù)類型,如scanf("%s,%d",str,icount);
它要求在標(biāo)準(zhǔn)輸入流中輸入類似"son
of
bitch,1000"這樣的字符串,同時(shí)程序會(huì)將"son
of
bitch"給str,1000給icount.
scanf函數(shù)的返回值為int值,即成功賦值的個(gè)數(shù),在上例中如果函數(shù)調(diào)用成功,則會(huì)返回2,所以我們?cè)趯懗绦驎r(shí),可以通過(guò)
語(yǔ)句if(scanf("%s,%d",str,icount)
!=
2){...}來(lái)判斷用戶輸入是否正確.
int
printf(const
char
*format,
arg_list)
printf主要是將格式化字符串輸出到標(biāo)準(zhǔn)輸出流中,在stdio.h頭文件中定義了標(biāo)準(zhǔn)的輸入和輸出,分別是stdin,stdout.
arg_list可以是變量名,也可以是表達(dá)式,但最終都會(huì)以值的形式填充進(jìn)format中.
int
getc(FILE
*fp)
getc主要是從文件中讀出一個(gè)字符.常用的判斷文件是否讀取結(jié)束的語(yǔ)句為:(ch
=
getc(fp))
!=
EOF.EOF為文件結(jié)束標(biāo)志,
定義在stdio.h中,就像EXIT_SUCCESS,EXIT_FAILURE定義在stdlib.h中一樣,文件也可以被理解為一種流,所以當(dāng)fp為stdin
時(shí),getc(stdin)就等同于getchar()了.
int
putc(int
ch,FILE
*fp)
putc主要是把字符ch寫到文件fp中去.如果fp為stdout,則putc就等同于putchar()了.
int
getchar(void)
getchar主要是從標(biāo)準(zhǔn)輸入流讀取一個(gè)字符.默認(rèn)的標(biāo)準(zhǔn)輸入流即stdio.h中定義的stdin.但是從輸入流中讀取字符時(shí)又
涉及到緩沖的問(wèn)題,所以并不是在屏幕中敲上一個(gè)字符程序就會(huì)運(yùn)行,一般是通過(guò)在屏幕上敲上回車鍵,然后將回車前的字符
串放在緩沖區(qū)中,getchar就是在緩沖區(qū)中一個(gè)一個(gè)的讀字符.當(dāng)然也可以在while循環(huán)中指定終止字符,如下面的語(yǔ)句:
while
((c
=
getchar())
!=
'#')這是以#來(lái)結(jié)束的.
int
putchar(int
ch)
putchar(ch)主要是把字符ch寫到標(biāo)準(zhǔn)流stdout中去.
char
*
gets(char
*str)
gets主要是從標(biāo)準(zhǔn)輸入流讀取字符串并回顯,讀到換行符時(shí)退出,并會(huì)將換行符省去.
int
puts(char
*str)
puts主要是把字符串str寫到標(biāo)準(zhǔn)流stdout中去,并會(huì)在輸出到最后時(shí)歷明添加一個(gè)換行符.
char
*fgets(char
*str,
int
num,
FILE
*fp)
str是存放讀入的字符數(shù)組指針,num是最大允許的讀入字符數(shù),fp是文件指鎮(zhèn)鎮(zhèn)針.fgets的功能是讀一行字符,該行的字符數(shù)
不大于num-1.因?yàn)閒gets函數(shù)會(huì)在末尾加上一個(gè)空字符以構(gòu)成一個(gè)字符串.另外fgets在讀取到換行符后不會(huì)將其省略.
int
fputs(char
*str,
file
*fp)
fputs將str寫入fp.fputs與puts的不同之處是fputs在打印時(shí)并不添加換行符.
int
fgetc(FILE
*fp)
fgetc從fp的當(dāng)前位置讀取一個(gè)字符.
int
fputc(int
ch,
file
*fp)
fputc是將ch寫入fp當(dāng)前指定位置.
int
fscanf(FILE
*fp,
char
*format,...)
fscanf按照指定格式御爛粗從文件中出讀出數(shù)據(jù),并賦值到參數(shù)列表中.
int
fprintf(FILE
*fp,
char
*format,...)
fprintf將格式化數(shù)據(jù)寫入流式文件中.
C語(yǔ)言中,定義數(shù)組后可以用sizeof命令獲得數(shù)組的長(zhǎng)度(可容納元素個(gè)數(shù)),通過(guò)數(shù)組占內(nèi)存總空間/單個(gè)元素占內(nèi)存空間大小,即可得到數(shù)組的元素個(gè)數(shù)
例如
但是,通過(guò)將數(shù)組作為函數(shù)參數(shù)胡戚衫傳遞到函數(shù)中,以獲仔基得數(shù)組長(zhǎng)度是不可行的
例如
原因:數(shù)組arr是函數(shù)參數(shù),在函數(shù)中褲腔,arr只是一個(gè)指針(地址,系統(tǒng)在本函數(shù)運(yùn)行時(shí),是不知道arr所表示的地址有多大的數(shù)據(jù)存儲(chǔ)空間,這里只是告訴函數(shù):一個(gè)數(shù)據(jù)存儲(chǔ)空間首地址),所以,sizoef(arr)的結(jié)果是指針變量arr占內(nèi)存的大小,一般在32位機(jī)上是4個(gè)字節(jié)。arr[0]是int類型,sizeof(arr[0])也是4個(gè)字節(jié),所以,結(jié)果永遠(yuǎn)是1。
如果想要在被調(diào)用的函數(shù)中,得知原數(shù)組的大小,可以再給函數(shù)添加一個(gè)參數(shù),用于指定數(shù)組的大小,讓外界調(diào)用函數(shù)前就講數(shù)組的大小傳遞進(jìn)來(lái)