函数参数:指针参数
如果需要传递大型数据结构,可以传递指针而不是整个数据结构,避免复制数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <iostream> int Add (int * x, int * y) { (*x) *= 100 ; (*y) *= 10 ; return (*x) + (*y); } int main () { int x = 2 , y = 1 ; int c = Add (&x, &y); std::cout << "c=" << c << "x=" << x << "y=" << y; }
应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <iostream> struct Role { int Hp; int Mp; }; int Exp (Role* r1) { return r1->Hp + r1->Mp; } int main () { Role r1{500 ,200 }; c = Exp (&r1); std::cout << c; }
避免修随意修改值,使用常量指针限定只读操作
游戏小程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> struct Role { int Hp; int Mp; int damage; }; bool Act (const Role* Acter, Role* beActer) { beActer->Hp -= Acter->damage; return beActer->Hp <= 0 ; } int main () { Role User{ 1000 ,1500 ,2222220 }; Role Monster{ 1500 ,100 ,100 }; if (Act (&Monster, &User)) std::cout << "角色死亡!!" ; else if (Act (&User, &Monster)) std::cout << "怪物死亡!获得屠龙宝刀!" ; }
数组参数
数组参数两种方式(等价,汇编代码也一样)
1 2 3 4 5 6 7 8 9 10 11 void Sort (int ary[], unsigned count) { for (int i = 0 ; i < count; i ++ ) std::cout << ary[i]; } void Sort (int * ary. unsigned count) { for (int i = 0 ; i < count; i ++ ) std::cout << ary[i]; }
1 2 3 4 5 6 7 8 9 10 11 void Sort (int ary[]) { std::cout << sizeof (ary); } void Sort (int ary[]) { std::cout << sizeof (ary); }
二维数组
1 2 3 4 5 6 7 8 9 10 11 void Sort (int ary[][2 ] unsigned count) { } int main () { int a[3 ][2 ]{{1 ,2 },{3 ,4 },{5 ,6 }}; Sort (a,3 ); }
作业,改造Sort函数
引用参数
可以像指针一样,设定只能读不能写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 struct Role { int hp; int mp; int damage; }; bool Act (const Role& Acter, Role& beAct) { beAct.hp -= Acter.damage; return beAct.hp < 0 ; } int main () { Role user{200 ,300 ,850 }; Role monster{800 ,300 ,50 }; if (Act (user,monster)) std::cout << "怪物死亡,获得。。。。" ; }
指针和引用的区别
1 2 3 4 5 6 7 8 9 10 11 12 bool Act (Role& Acter, Role& beAct) { return true ; } bool Act (Role* Acter, Role* beAct) { return true ; } Act (nullptr , nullptr );
*&
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 bool Act (const Role& Acter, Role* beAct) { beAct->hp -= Acter.damage; bool bEnd = beAct->hp<0 ; beAct = (Role*)&Acter; return beAct->hp < 0 ; } int main () { Role user{"奥特曼" ,200 ,300 ,500 }; Role monster{"小怪兽" ,800 ,300 ,50 }; Role* pRole = &monster; if (Act (user, pRole)) std::cout << pRole->Name << "怪物死亡。。。" ; } bool Act (const Role& Acter, Role*& beAct) ;
完整的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <iostream> struct Role { char Name[0x20 ]; int Hp; int Mp; int damage; }*PROLE; bool Act (const Role* Acter, PROLE& beActer) { beAct->hp -= Acter->damage; bool bEnd = beAct->hp<0 ; beAct = (Role*)&Acter; return beAct->hp < 0 ; } int main () { Role user{"奥特曼" ,200 ,300 ,500 }; Role monster{"小怪兽" ,800 ,300 ,50 }; PROLE pRole = &monster; if (Act (user, pRole)) std::cout << pRole->Name << "怪物死亡。。。" ; }
按值传递 vs 按引用传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 bool Act (const Role* Acter, PROLE beActer) { beActer = (Role*)&Acter; return beActer->Hp < 0 ; } bool Act (const Role* Acter, PROLE& beActer) { beActer = (Role*)&Acter; return beActer->Hp < 0 ; }
1 2 3 4 5 6 int Add (int * x, int * y) { (*x) *= 100 ; (*y) *= 10 ; return (*x) + (*y); }
上面这个例子也是值传递,但因为通过指针解引用(*x 和 *y)修改了指针所指向的变量的值,所以下面的代码实际上是修改了原始变量的内容。所以,尽管是值传递,但是通过指针传递数据导致的效果是修改了原始数据。
指针本身是值传递 (函数内的指针 x
和 y
是原始指针的副本)。
指针所指向的内容是通过解引用修改的 (因此修改了原始数据)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <iostream> void swap (int & a, int & b) { int tmp = ary[i]; ary[i] = ary[i - 1 ]; ary[i - 1 ] = tmp; } void Sort (int ary[], unsigned count, bool BigSort) { for (int i = 1 ; i < count; i ++ ) for (int i = 1 ; i < count; i ++ ) { bool bcase = BigSort?ary[i] > ary[i - 1 ] : ary[i] < ary[i - 1 ]; if (bcase) swap (ary[i], ary[i - 1 ]); } }
默认实参
用户不指定值的时候,就使用默认的值
1 void Sort (int ary[], unsigned count, bool BigSort = true )
默认参数只能放在最后
1 2 3 4 int Add (int a = 100 , b = 200 ) ; int Add (int a = 100 , int b) ; int Add (int a, int b = 100 , int c = 250 ) ; int Add (int a, int & b = 100 ) ;
不定量参数
main: 处理命令行选项 ,有时候需要给main传递实参,一种常见的情况是用户通过设置一组选项来确定函数所要执行的操作。假定main函数位于可执行文件prog之内,向程序传递下面的选项
prog -d -o ofile data0
这些命令行通过两个可选的形参传递给main函数
1 int main (int argc, cahr* argv[]) {...}
第二个形参是一个数组,它的元素是指向C风格字符串的指针:第一个形参argc表示数组中字符串的数量。因为第二个形参是数组,所以main函数也可以定义成:
1 int main () (int argc, char **argv) {...}
其中 argv 指向char* 。。
当实参传给main函数之后,argv的第一个元素指向程序的名字或者一个空字符串,接下来的元素一次传递命令行提供的实参。最后一个指针之后的元素保证为0 。
argv[0] = "prog";
argv[1] = "-d";
argv[2] = "-o";
argv[3] = "ofile";
argv[4] = "data0";
argv[5] = 0;
例题:输出程序名字和路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <iostream> #include <cstring> int main (int argc, char * argv[]) { std::cout << "程序名字" << argv[0 ] << std::endl; const char * programName = strrchr (argv[0 ], '\\' ); if (programName != nullptr ) { programName++; std::cout << "程序名称:" << programName << std::endl; } else std::cout << "程序名称:" << argv[0 ] << std::endl; return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <iostream> #include <string> int main (int argc, char * argv[]) { if (argc > 0 ) std::string programPath = argv[0 ]; std::cout << "程序路径:" << programPath << std::endl; std::size_t lastSlash = programPath.rfind ('\\' ); if (lastSlash == std::string::npos) lastSlash = programPath.rfind ('/' ); if (lastSlash != std::string::npos) { std::string programName = programPath.substr (lastSlash + 1 ); std::cout << "程序名称: " << programName << std::endl; } else std::cout << "程序名称: " << programPath << std::endl; return 0 ; }
可变形参的函数
使用 ...
语法(C 风格的可变参数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <iostream> #include <cstdarg> void printNumbers (int count, ...) { va_list args; va_start (args, count); for (int i = 0 ; i < count; ++i) { int num = va_arg (args, int ); std::cout << num << " " ; } va_end (args); std::cout << std::endl; } int main () { printNumbers (3 , 10 , 20 , 30 ); printNumbers (5 , 1 , 2 , 3 , 4 , 5 ); return 0 ; }
使用 std::initializer_list
(C++11之后)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <iostream> #include <initializer_list> void printNumbers (std::initializer_list<int > nums) { for (int num : nums) { std::cout << num << " " ; } std::cout << std::endl; } int main () { printNumbers ({10 , 20 , 30 }); printNumbers ({1 , 2 , 3 , 4 , 5 }); return 0 ; }
使用 std::vector
或者其他容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <iostream> #include <vector> void printNumbers (const std::vector<int >& nums) { for (int num : nums) { std::cout << num << " " ; } std::cout << std::endl; } int main () { printNumbers ({10 , 20 , 30 }); printNumbers ({1 , 2 , 3 , 4 , 5 }); return 0 ; }
使用 std::function
和 Lambda 表达式(高级用法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <iostream> #include <functional> void applyFunction (std::function<void ()> func) { func (); } int main () { applyFunction ([]() { std::cout << "Lambda with no arguments!" << std::endl; }); return 0 ; }
一个小作业
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <iostream> #include <string> const char * ReadRef (const char * ref, const char * cmds) { for (int i = 0 ; cmds[i]; i ++ ) { if (cmds[i] == ref[0 ]) { bool found = true ; int x; for (x = 0 ; ref[x]; x ++ ) { if (ref[x] != cmds[i + x]) { found = false ; break ; } } if (found) return &cmds[i + x]; } } return nullptr ; } int main (int argc, char * argv[]) { const char * id = nullptr ; const char * pass = nullptr ; const char * country = nullptr ; for (int i = 1 ; i < argc; i++) { if (!id) id = ReadRef ("id:" , argv[i]); if (!pass) pass = ReadRef ("pass:" , argv[i]); if (!country) country = ReadRef ("country:" , argv[i]); } if (id && pass && country) { std::cout << "注册成功!\n" ; std::cout << "账号:" << id << "\n" ; std::cout << "密码:" << pass << "\n" ; std::cout << "国家:" << country << "\n" ; } else { std::cout << "参数不足!请按以下格式调用程序:\n" ; std::cout << "./program id:<your_id> pass:<your_pass> country:<your_country>\n" ; } return 0 ; }