C/C++函数参数的类型
来源:互联网 发布:淘宝店铺流失人数 编辑:程序博客网 时间:2024/06/13 01:42
函数传参问题一直是一个难点,很多地方没懂会导致很多的问题,所以这里我将总结一下
函数的参数类型
函数的参数类型有:值,地址,引用
首先我们要知道在main函数里调用其他函数时,会在栈里开辟一段空间,最开始入栈的是当前代码的下一行代码的地址,然后依次是形参,函数的局部变量,函数的代码在代码段,当函数返回时,释放栈空间,最后出栈的是下一行代码的地址,又回到了main函数里函数开始的地方继续执行,很多人这个时候回提出一个问题,为什么栈里的变量释放了,函数还可以返回呢?这是因为编译器会为函数生成一个临时变量,用来存放函数的返回值,这里后面会详细讲到
1.值传递
这是实参把值传给形参,先看下一个程序
#include <stdio.h>int fun(int a){ a++; printf("a=%d\n",a); return a;}int main(int argc, char const *argv[]){ int var=5; fun(var); printf("var=%d\n",var); return 0;}
结果为
[root@localhost gongxiang]# ./a.outa=6 var=5
这是一个很简单程序,fun函数的目的是var++,但是结果并没有让var++,而是形参a++,如果形参++,对于我们的程序是没有任何意义的,这是因为值传递时只是传递了实参的值给形参,用实参初始化形参,就相当于在调用fun函数时,首先进行的是 a=var;然后对a++,var的值当然不会有变化
2.地址传递
对于上面的程序可以改写
#include <stdio.h>int fun(int *a){ (*a)++; printf("*a=%d \n",*a); return *a;}int main(int argc, char const *argv[]){ int var=5; fun(&var); printf("var=%d\n",var); return 0;}
结果为
[root@localhost gongxiang]# ./a.out*a=6 var=6
地址传递本质也是值传递,只是它传递的是地址值,函数调用的时候有int* a=&var,把变量var的地址传给指针a,这个时候指针a指向变量var,对*a的操作即是对var的操作,函数返回时指针a会被释放,但是返回来此时a的地址
3.引用传递
在C++中还可以通过引用来改变var的值
#include <iostream>using namespace std;int fun(int& a){ a++; printf("a=%d \n",a); return a;}int main(int argc, char const *argv[]){ int var=5; fun(var); printf("var=%d\n",var); return 0;}
结果为
[root@localhost c++]# ./a.outa=6 var=6
引用即是给变量起一个别名,实际上是直接对变量进行操作,现在大家对函数参数有一点理解了吧
注意:函数不可以返回局部指针变量的值,因为函数返回时,就会释放栈,这句话很多人都容易误解,我之前也是,以为只要返回局部变量就是不行的,可是实际上不是的
请看下面一段代码
#include <iostream>using namespace std;char* fun(char* p){ return ++p;}int main(int argc, char const *argv[]){ char* str="1234567"; //“1234567”存放在字符串常量区 //char str[]="1234567"; //字符串和str都存放在栈 char* tmp=fun(str); //tmp存放在栈 printf("tmp=%s\n",tmp); return 0;}
结果如下:
[root@localhost c++]# g++ test.cpp[root@localhost c++]# ./a.outtmp=234567
这个地方有人会觉得不是说不可以返回局部变量指针的值吗?可是为什么可以返回呢!
回到前面说的地址传递的时候,传递指针的值,这个时候p与str指向同一个地址空间,函数里p++后指针向后移一位,指向字符‘2’,返回的时候,编译器会生成一个临时变量存放此时p的地址,返回给指针tmp,此时tmp指向常量区的字符串,自然可以输出啦!注意常量字符串区的值只读不可修改
再看下面的代码
#include <iostream>using namespace std;char* fun(){ char* p="abcdefg"; return ++p;}int main(int argc, char const *argv[]){ char* tmp=fun(); printf("tmp=%s\n",tmp); return 0;}
结果为:
[root@localhost c++]# ./a.outtmp=bcdefg
这里可以返回局部变量指针主要是因为给指针初始化的字符串“abcdefg”存放在常量区,函数释放后并没有释放常量区的内容
再修改一下
#include <iostream>using namespace std;char* fun(){ char p[]="abcdefg"; return ++p;}int main(int argc, char const *argv[]){ char* tmp=fun(); printf("tmp=%s\n",tmp); return 0;}
看看结果
[root@localhost c++]# g++ test.cpptest.cpp:14:2: 警告:文件未以空白行结束test.cpp: In function ‘char* fun()’:test.cpp:6: 错误:赋值运算中的左值无效test.cpp:5: 警告:返回了局部变量的 ‘p’ 的地址
这里出错了,是因为返回了局部指针变量的地址,字符串也存放在栈里,函数返回后,栈里的东西不存在了,即这时返回指针是错误的,解决办法可以分配堆内存,不需要用时再手动释放
以上讲的都是基础数据类型,在C++中函数参数可能是对象,之中又有很多注意的地方
下面看一下对象中值得注意的情况:
#include <iostream>using namespace std;class B{public: B() { cout<<"default constructor"<<endl; } ~B() { cout<<"destructed"<<endl; } B(int i) :data(i) { cout<<"constructed by para "<<data<<endl; }private: int data;};B play(B b){ return b;}//第一个main函数// int main(int argc, char const *argv[])// {// B t1=play(5);// B t2=play(t1);// return 0;// }//第二个main函数int main(int argc, char const *argv[]){ B t1=play(5); B t2=play(10); return 0;}
第一个main函数下执行的结果为
[root@localhost c++]# ./a.outconstructed by para 5(调用带参数的构造函数,在fun内生成临时对象)destructed (5传入fun时生成的临时对象析构)destructed (t1传入fun时产生的临时变量析构)destructed (t2析构)destructed (t1析构)
第二个main函数下执行的结果为
[root@localhost c++]# ./a.outconstructed by para 5 (调用带参数构造函数,在fun内生成临时对象)destructed (5传入fun时生成的临时对象析构)constructed by para 10(调用带参数构造函数,在fun内生成临时对象)destructed (10传入fun时生成的临时对象析构)destructed (t2析构)destructed (t1析构)
这里调用play()函数时,有两种参数类型的传递方式:
(1)如果传递的参数是整数,那么在函数栈中首先调用带参数的构造函数,然后产生一个临时变量,函数返回时调用复制构造函数,生成临时对象,最后这个临时对象会在函数返回后析构
(2)如果传递的是B类对象,首先会调用复制构造函数初始化形参对象,后面的步骤一样
可以看出,两种情况的不同就是调用不同的构造函数初始化形参,一个是调用带参数的构造函数,一个是调用复制构造函数
补充
什么是临时对象?临时对象正在什么情况下产生?
临时对象是看不见的,它不会出现在程序中,大多情况下它会影响程序的执行效率,所以有时想避免临时对象的产生
它通常在以下两种情况下产生:
1.参数按值传递
2.返回值按值传递
如何避免呢?
可以按引用传递代替值传递,引用必须有一个实在的,可引用的对象,否则引用是错误的
在产生临时对象的时候,需要调用复制构造函数
在什么情况下会调用复制构造函数呢?
1.一个对象以值传递的方式传入函数体
2.一个对象以值传递的方式从函数返回
3.一个对象需要另一个对象进行初始化
- C语言main函数的参数类型
- C/C++函数参数的类型
- C函数参数类型提升
- C函数参数类型提升 --- float类型
- c语言创建支持多参数多类型的函数
- 参数类型不同的函数重载(C++)
- C语言函数调用传递参数时的类型退化
- C 语言可变参数类型函数
- c++:结构体类型作为函数参数
- python调用c函数参数类型问题
- C++:Main函数参数列表及参数类型转换
- [C]main 函数的参数
- c函数的参数传递
- 可变参数的C函数
- c 不定参数的函数
- C函数的参数传递
- C函数的可变参数
- C语言的函数参数
- 217.leetcode Contains Duplicate(easy)[数组 查重]
- 滕王阁序
- 【HDU】-1869-六度分离(最短路)(floyd)
- android 下载之断点续传
- 开发一个hibernate项目的流程
- C/C++函数参数的类型
- c++学习笔记1
- 工厂模式学习笔记
- 对vector等STL标准容器进行排序操作
- java 创建xml 字符串
- 冒泡排序,可以排多种类型
- 虚拟化原理之KVM
- vb通过scriptcontrol调用VBScript相互传递参数
- HDU 1114:Piggy-Bank