扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
C语言获得命令行参数的方法 每当你运行一个DOS或Windows程序时,都会生成一个程序段前缀(Program SegmentPrefix,简称PSP)。当DOS程序的装入程序把程序复制到RAM中来执行时,信谨它先把256个字节分配给PSP,然后把可执行代码复制到紧接着PSP的内存区域中。PSP中包含了DOS为了执行一个程序所需要的各种各样的信息,其中的一部分数据就是命令行。PSP中偏移量为128的那个字节中存放着命令行中的字符个数,接下来的127个字节中存放着命令行本身。这也正是DOS把你能在其提示行中输入的字符个数限制在127个之内的原因——因为它为命令行分配的存储空间只有那么多。遗憾的是,PSP的命令行缓冲区中并没有存放可执行程序的名字——而只存放着在可执行程序名后键入的字符(包括空格符)。例如,如果你在DOS提示行中键入以下命令: XCOPY AUTOEXEC.BAT AUTOEXEC.BAK 假设XCOPY.EXE存放在c驱动器的DOS目录下,则李坦薯XCOPY.EXE的PSP命令行缓冲区中将包含以下信息: AUTOEXEC.BAT AUTOEXEC.BAK 注意,命令行中紧接着"XCOPY"的空格符也被复制到PSP的缓冲区中。 除了不能在PSP中找到可执行程序名外,PSP还有一个不足之处——在命令行中能看到的对于输出或输入的重定向,在PSP的命令行缓冲区中是无法看到的,也就是说,你无法从PSP中得知你的程序是否被重定向过。 到现在为止,你应该熟悉在C程序中可以通过argc和argv来获取一些有关信息,但是,这些信息是怎样从DOS的装入程序传给argv指针的呢?这是由程序的启动代码来完成的。启动代码在main()函数的第一行代码之前被执行,在其执行期间,它调用一个名为__setargv()的函数,把程序名和命令行从PSP和DOS环境中复制到mai‘n()函数的argv指针所指向的缓冲区中。你可以在xLIBCE.LIB文件中找到_setargv()函数,对于Small,Medium和Large这三种存储模式,这里的“x”分别为“S”,“M”和“L”。在生成可执行程序时,上述库文件会自动被连接进来。除了复制argv参数的内容外,c的启动代码还要完成其它一些工作。当启动代码执行完毕后,main()函数中的代码就开始执行了。 在DOS中的情况是这样的,那么在Windows中的情况又是怎样的呢?实际上,在Windows中的情况大致上和在DOS中的一样。当执行一个Windows程序时,与DOS的装入程序一样哪者,Windows的装入程序也会建立一个PSP,其中包含了与DOS的PSP中相同的信息。主要的区别是此时命令行被复制到lpszCmdLine参数中,它是WinMain()函数的参数表中的第三个(也是倒数第二个)参数。在Windows C的xLIBCEW.LIB库文件中包含了启动函数setargv(),它负责把命令行信息复制到lpszCmdLine缓冲区中。同样,这里的“x”也表示程序所使用的存储模式。在Quick c中,函数_setargv()包含在库文件xLIBCEWQ.LIB中。 尽管DOS程序和Windows程序的命令行信息的管理方式基本相同,但是传给你的C程序的命令行的格式在安排上稍有不同。在DOS中,启动代码获得以空格符为分隔符的命令行后,就把每个参数转换为其自身的以NULL为终止符的字符串。因此,你可把argv原型化为一个指针数组(char* argv[]),并通过从O到n这些下标值来访问每个参数,其中n等于命令行中的参数个数减去1。你也可以把argv原型化为一个指向指针的指针(char **argv),并通过增减argv的值来访问每一个参数。 在Windows中,传给c程序的命令行是一个LPSTR类型或char_far*类型,其中的每一个参数都用空格符隔开,就象你在DOS提示行中键入这些字符后所看到的那样(实际上,在Windows中不可能真正键入这些字符,而是通过双击应用程序图标这样的方式来启动一个程序)。为了访问Windows命令行中的各个参数,你必须人工地访问lpszCmdLine所指向的存储区,并分隔存放在该处的参数,或者使用strtok()这样的函数,每次处理一个参数。 如果你富于探索精神,你可以仔细地研究PSP本身,并从中获取命令行信息。为此,你可以像下面这样来使用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存储模式下,或者在只有一个代码段的汇编程序中,由DOS返回到BX寄存器中的值就是程序代码段的地址值;在Large模式的c程序中,或者在多个代码段的汇编程序中,所返回的值是程序中包含PSP的那个代码段的段地址值。如果你已经建立了一个指向这个数据的指针,你就可以在程序中使用这个数据了。 今天,通常你可以认为你的程序可以使用命令行参数。但是,在DOS 2.O版以前,存储在PSP中的命令行信息与现在稍有不同(它不能从命令行中分离出输入或输出重定向数据),而 且由argv[O]所指向的数据中并不一定包含可执行程序的路径名。直到DOS发展到3.o版,它才提供了(或者说至少公开了)用来检索PSP的中断62H。因此,你至少可以认为,在运行DOS3.0或更高版本的PC上,你的程序总是可以获得命令行参数的。 如果你的程序运行在DOS 3.0或更高的版本下,你基本上就可以任意处理命令行参数了,因为这些信息已存入栈中供你使用。显然,适用于栈中数据的常规的数据操作规则同样也适用于存入栈中的命令行参数。然而,如果你的编译程序不提供argv参数,例如当你用汇编语言或者某种不提供argv参数的编译程序编写程序时,真正的问题就出现了。在这种情况下,你将不得不自己找出检索命令行参数的方法,而使用DOS中断62H就是一种很方便的方法。 如果你要用DOS中断62H来检索指向命令行的指针,你必须明白该指针所指向的数据是供DOS使用的,并且正在被DOS使用。尽管你可以检索这些数据,但你不可以改变它们。如果在程序中需要随时根据命令行参数作出决定,那么在使用这些数据之前应该先把它们复制到一个局部缓冲区中,这样就可以随意处理这些数据,而不用担心会与DOS发生冲突了。实际上,这种技巧同样适用于带argv参数的c程序。位于main()函数之外的函数需要使用命令行参数的情况并不少见,为了使这些函数能引用这些数据,main()函数必须把这些数据存为全局型,或者通过(再次)入栈把它们传递给需要使用它们的函数。
创新互联是专业的盐山网站建设公司,盐山接单;提供做网站、成都网站建设,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行盐山网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
这个看你是怎么调用的
一般都是约定个数 或者根据第一个参数,决定个数。
你这个写法,看起来是两个参数调用,然后都是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*);//获取下一个参数需要赋值的。
printf(t);
va_end(val);
}
C语言输入输出函数有很多,标准I/O函数中包含了如下几个常用的函数:
scanf,printf,getc,putc,getchar,putchar,gets,puts,fgets,fputs,fgetc,fputc,fscanf,fprintf等.
int
scanf(const
char
*format,
arg_list)
scanf主要从标准输入流中获取参数值,format为指定的参数格式及参数类型,如scanf("%s,%d",str,icount);
它要求在标准输入流中输入类似"son
of
bitch,1000"这样的字符串,同时程序会将"son
of
bitch"给str,1000给icount.
scanf函数的返回值为int值,即成功赋值的个数,在上例中如果函数调用成功,则会返回2,所以我们在写程序时,可以通过
语句if(scanf("%s,%d",str,icount)
!=
2){...}来判断用户输入是否正确.
int
printf(const
char
*format,
arg_list)
printf主要是将格式化字符串输出到标准输出流中,在stdio.h头文件中定义了标准的输入和输出,分别是stdin,stdout.
arg_list可以是变量名,也可以是表达式,但最终都会以值的形式填充进format中.
int
getc(FILE
*fp)
getc主要是从文件中读出一个字符.常用的判断文件是否读取结束的语句为:(ch
=
getc(fp))
!=
EOF.EOF为文件结束标志,
定义在stdio.h中,就像EXIT_SUCCESS,EXIT_FAILURE定义在stdlib.h中一样,文件也可以被理解为一种流,所以当fp为stdin
时,getc(stdin)就等同于getchar()了.
int
putc(int
ch,FILE
*fp)
putc主要是把字符ch写到文件fp中去.如果fp为stdout,则putc就等同于putchar()了.
int
getchar(void)
getchar主要是从标准输入流读取一个字符.默认的标准输入流即stdio.h中定义的stdin.但是从输入流中读取字符时又
涉及到缓冲的问题,所以并不是在屏幕中敲上一个字符程序就会运行,一般是通过在屏幕上敲上回车键,然后将回车前的字符
串放在缓冲区中,getchar就是在缓冲区中一个一个的读字符.当然也可以在while循环中指定终止字符,如下面的语句:
while
((c
=
getchar())
!=
'#')这是以#来结束的.
int
putchar(int
ch)
putchar(ch)主要是把字符ch写到标准流stdout中去.
char
*
gets(char
*str)
gets主要是从标准输入流读取字符串并回显,读到换行符时退出,并会将换行符省去.
int
puts(char
*str)
puts主要是把字符串str写到标准流stdout中去,并会在输出到最后时历明添加一个换行符.
char
*fgets(char
*str,
int
num,
FILE
*fp)
str是存放读入的字符数组指针,num是最大允许的读入字符数,fp是文件指镇镇针.fgets的功能是读一行字符,该行的字符数
不大于num-1.因为fgets函数会在末尾加上一个空字符以构成一个字符串.另外fgets在读取到换行符后不会将其省略.
int
fputs(char
*str,
file
*fp)
fputs将str写入fp.fputs与puts的不同之处是fputs在打印时并不添加换行符.
int
fgetc(FILE
*fp)
fgetc从fp的当前位置读取一个字符.
int
fputc(int
ch,
file
*fp)
fputc是将ch写入fp当前指定位置.
int
fscanf(FILE
*fp,
char
*format,...)
fscanf按照指定格式御烂粗从文件中出读出数据,并赋值到参数列表中.
int
fprintf(FILE
*fp,
char
*format,...)
fprintf将格式化数据写入流式文件中.
C语言中,定义数组后可以用sizeof命令获得数组的长度(可容纳元素个数),通过数组占内存总空间/单个元素占内存空间大小,即可得到数组的元素个数
例如
但是,通过将数组作为函数参数胡戚衫传递到函数中,以获仔基得数组长度是不可行的
例如
原因:数组arr是函数参数,在函数中裤腔,arr只是一个指针(地址,系统在本函数运行时,是不知道arr所表示的地址有多大的数据存储空间,这里只是告诉函数:一个数据存储空间首地址),所以,sizoef(arr)的结果是指针变量arr占内存的大小,一般在32位机上是4个字节。arr[0]是int类型,sizeof(arr[0])也是4个字节,所以,结果永远是1。
如果想要在被调用的函数中,得知原数组的大小,可以再给函数添加一个参数,用于指定数组的大小,让外界调用函数前就讲数组的大小传递进来
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流