C++控制台程序的命令行参数输入-且支持参数opts扩展
C++控制台程序的命令行参数输入
1. C/C++语言中的main函数,经常带有参数argc,argv,如下:
int main(int argc, char** argv) int main(int argc, char* argv[])
argc(第一个形参)必须是整型变量,标识该控制台命令调用中接收到的参数个数,注意,包括该命令程序名字itself。
argv( 第二个形参)必须是指向字符串的指针数组,用于保存argc个参数的具体数据。注意数组起始索引为0开始,到argc-1结束。即:argv[0]为命令行中可执行程序名本身,argv[1]为命令行中第二个参数的内容,依次类推。
加上形参说明后,因此C程序中的main函数的函数头应写为:
main (int argc,char *argv[])
2. 控制台程序参数获取
由于main函数不能被其它函数调用,因此不可能在程序内部取得实际值。那么,在何处把实参值赋予main函数的形参呢? 实际上,main函数的参数值是从操作系统命令行上获得的。
如何在操作系统命令行获取参数呢?
(1)在VS中设置时右键项目->属性->调试->命令参数,在命令参数中添加所需参数,字符串之间用空格分开即可。如果是.txt文件,要放在当前目录下(.cpp所在目录)【实质为exe生成目录位置】,不然找不到。
(2)或者:假如你的程序是hello.exe,如果在命令行运行该程序,(首先应该在命令行下用 cd 命令进入到 hello.exe 文件所在目录) 运行命令为:
hello.exe data.txt //.txt也在.exe所在目录下
注意:调用控制台程序命令行中输入的参数在位置上,并没有与控制台程序main函数中 的两个形参 一 一 对应的。 因为,main的形参只有二个,而命令行中的参数个数原则上未加限制。argc参数表示了命令行中参数的个数(注意:文件名本身也算一个参数),argc的值是在输入命令行时由系统按实际参数的个数自动赋予的,即,argv[0]为命令行中可执行程序名本身,argv[1]为命令行中第二个参数的内容,依次类推。
在调用一个可执行程序时,某些情况下需要向程序传递参数。如我们可以在控制台中键入notepad.exe,回车后将执行记事本程序。
如果我们希望在打开notepad时同时打开一个文本文件,可以在notepad.exe 。后面跟上文件的路径和名字,如notepad.exe example.txt(文件在当前路径)
那么程序中如何能得到这些输入参数呢?这个工作是编译器帮我们完成的,编译器将输入参数的信息放入main函数的参数列表中。
main函数的参数列表保存了输入参数的信息,第一个参数argc记录了输入参数的个数, 第二个参数是字符串数组的,字符串数组的每个单元是char*类型的,指向一个c风格字符串。
例子如下:
notepad.exe example.txt data.txt train.txt
第一个参数 第二个参数 第三个参数 第四个参数
因此:argc = 4
控制台执行上面程序后,程序读取main函数参数为: argc是4,就是说argv数组中有四个有效单元
argv数组中的第一个单元指向的字符串总是可执行程序的名字,以后的单元指向的字符串依次是程序调用时的参数。
第一单元argv[0]指向的字符串是"notepad.exe"
第二单元argv[1]指向的字符串是"example.txt"
第三单元argv[2]指向的字符串是"data.txt"
第四单元argv[3]指向的字符串是"train.txt"
`上述这个赋值过程是编译器自动完成的,我们只需要利用argc,argv[]读出数据就可以了。
3. 简单示例,控制台程序的不同调用方法,及输出结果:
int main(int argc, char* argv[]) { cout << "参数个数:" << argc << endl; cout << "参数内容:"; for (int i = 0; i < argc; ++i) { cout << argv[i] << endl; } //std::cout << "Hello World!\n"; system("pause"); }
(1) 控制台调用:
1、按住Shift键,鼠标右键快捷方式,先打开Powershell窗口。
2、输入 start cmd 回车
3、这样就可以打开cmd窗口了,并且cmd的工作目录就是当前的目录。输入命令行:
ProjectTest.exe 1111 zhongguo renmin 传见过 中国人民解放拒绝
输出:
(2)利用VSIDE中的控制台参数进行调用:
程序:
#include <iostream> int main(int argc, char **argv) { while (argc-- > 0) { //printf("argv[%d]:%s\n", argc, argv[argc]); printf("argc:%d,*argv++:%s\n", argc,*argv++); //printf("argc:%d,*++argv:%s\n", *++argv); } }
在VS中设置设置 comant argument:
不进行设置时:
设置参数时:
(3)批处理脚本中.bat文件中,调用可执行文件
编辑“main测试.bat”文件内容为:
ProjectTest Jack 中国 boin747 1.234 3.3333 8888 zhongguo pause
在cmd运行.bat文件
双击:
好像识别汉字出现了问题,这里只是测试,能达到示意main函数的传参即可,我就不深因了。
如果把汉字改为数字和字母,则运行效果如预期:
4. 较为复杂的命令行程序,规范化输入,编写规范
下面摘录一个例程,该程序用于取出在argv中的命令行选项。在例子中,将支持下列用法:
//C/C++处理main()函数命令行 #include <iostream> #include <vector> #include <string> #include <ctype.h>//调用atoi函数 using namespace std; const char* const prog_name = "prog"; const char* const prog_version = "version 1.0 (2011/8/24)"; //退出函数 inline void usage(int exit_value = 0){ cerr<<prog_name<<" usage!"<<endl; exit(exit_value); } int main(int argc,char* argv[]){ //声明用于记录用户指定选项的变量 bool debug_on = false; bool ofile_on = false; bool limit_on = false; string ofile_name;//记录出现的输出文件名 int limit = -1;//限制值 vector <string> file_names;//记录文件名 cout<<"argc:"<<argc<<endl; for(int i = 1;i < argc; ++i){//读取argv中的每个选项 //输出第i+1个参量 cout<<"argv["<<i<<"]:"<<argv[i]<<endl; char *pchar = argv[i]; switch(pchar[0]){//确定选项类型:-h,-d,-v,-l,-o;或者其他 case '-':{ cout<<"case \'-\' found"<<endl; switch(pchar[1]){//确定用户指定的选项:h,d,v,l,o case 'd'://处理调试: cout<<"-d found:debugging turned on!"<<endl; debug_on = true; break; case 'v'://处理版本请求 cout<<"-v found:version info displayed!"<<endl; cout<<prog_name<<":"<<prog_version<<endl; return 0; case 'h'://处理帮助 cout<<"-h found:help info!"<<endl; usage(); case 'o'://处理输出文件 cout<<"-o found:output file!"<<endl; ofile_on = true; break; case 'l'://处理限制量 cout<<"-l found:resorce limit!"<<endl; limit_on = true; break; default://无法识别的选项 cerr<<prog_name<<":error:unrecognition option -:"<<pchar<<endl; usage(-1); } break; } default://不以'-'开头,是文件名 if(ofile_on){//输出文件名 cout<<"file name:"<<pchar<<endl; ofile_name = pchar; ofile_on = false;//复位 } else if(limit_on){//限制值 limit_on = false; limit = atoi(pchar); if(limit<0){ cerr<<prog_name<<":error:negative value for limit!"<<endl; usage(-2); } } else{//文件名 file_names.push_back(pchar); } break; } } if(file_names.empty()){ cerr<<prog_name<<":error:no file for processing!"<<endl; usage(3); } else{ cout<<(file_names.size() == 1 ? "File":"Files")<< " to be processed are the followed:"<<endl; for(int i = 0;i < file_names.size();++i){ cout<<file_names[i]<<"\t"<<endl; } } if(limit != -1){ cout<<"user-specified limit:"<<limit<<endl; } if(!ofile_name.empty()){ cout<<"user-specified ofile:"<<ofile_name<<endl; } }