C语言值传递怎么用,引用传递怎么用?
以表格来简要说明并区分这几种传递到底在做什么:
类型 | 传递对象 | 传递行为 | 内存关系 | 适用情况 | 区别与联系 | 举例 |
---|---|---|---|---|---|---|
值传递 | 数值 | 将实参的数值拷贝到另一块独立的内存上,在新的内存上操作 | 形参和实参占用不同的内存 | 函数内部需要修改参数,并且希望此改变的作用域不涉及调用者 | 传递是单向的,实参->形参 | 函数调用时,参数为数值 |
地值传递 | 地址 | 直接在实参所在的内存上操作 | 形参指向的和实参所在的是一块内存 | 内部对变量进行操作,并且希望此操作的作用域包括调用者;返回值传递 | 传递是双向的,实参<->实参 | 函数调用时,参数为地址 |
引用传递 | 别名 | 同上 | 形参和实参是同一个变量的不同名字,拥有相同的内存 | 同上 | 同上 | 实参代替了形参 |
具体说来,引用/地址传递在返回值传递上的应用是指:
假设函数需要有多个返回值,而显式上不能有返回值或者只能有一个返回值,则此时可利用指针/引用传递,对其他需要返回的变量进行修改,并将修改返回给调用者,完成隐式的返回值传递。
下面我们用代码来直接证明这三种传递在做什么:
#include<iostream>
#include<stdlib.h>
using namespace std;
void swap_value(int a, int b){
cout << "swap 前,形参的数值和地址:" << endl;
cout << "value(a) = " << a << "," << "变量a的地址:" << &a << endl;
cout << "value(b) = " << b << "," << "变量b的地址:" << &b << endl;
int tmp;
tmp = a;
a = b;
b = tmp;
cout << "swap 后,形参的数值和地址:" << endl;
cout << "value(a) = " << a << "," << "变量a的地址:" << &a << endl;
cout << "value(b) = " << b << "," << "变量b的地址:" << &b << endl;
}
void swap_adress_value(int *a, int *b){
cout << "swap 前,形参的地址和指向的数值:" << endl;
cout << "value(a) = " << a << "," << "*a:" << *a << endl;
cout << "value(b) = " << b << "," << "*b:" << *b << endl;
int *tmp;
tmp = a;
a = b;
b = tmp;
cout << "swap 后,形参的地址和指向的数值:" << endl;
cout << "value(a) = " << a << "," << "*a:" << *a << endl;
cout << "value(b) = " << b << "," << "*b:" << *b << endl;
}
void swap_pointer(int *a, int *b){
cout << "swap 前,形参的地址和指向的数值:" << endl;
cout << "value(a) = " << a << "," << "*a:" << *a << endl;
cout << "value(b) = " << b << "," << "*b:" << *b << endl;
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
cout << "swap 后,形参的地址和指向的数值:" << endl;
cout << "value(a) = " << a << "," << "*a:" << *a << endl;
cout << "value(b) = " << b << "," << "*b:" << *b << endl;
}
void swap_reference(int &a, int &b){
cout << "swap 前,形参的地址和指向的数值:" << endl;
cout << "value(a) = " << a << "," << "a存储地址:" << &a << endl;
cout << "value(b) = " << b << "," << "b存储地址:" << &b << endl;
int tmp;
tmp = a;
a = b;
b = tmp;
cout << "swap 后,形参的地址和指向的数值:" << endl;
cout << "value(a) = " << a << "," << "a存储地址:" << &a << endl;
cout << "value(b) = " << b << "," << "b存储地址:" << &b << endl;
}
int main(){
cout << "值传递:" << endl;
int x = 10;
int y = -1;
cout << "swap 前,实参的数值和地址:" << endl;
cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;
swap_value(x, y);
cout << "swap 后,实参的数值和地址:" << endl;
cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;
system("pause");
cout << endl;
cout << endl;
cout << endl;
cout << "传递地址且对地址进行修改:" << endl;
x = 10;
y = -1;
cout << "swap 前,实参的数值和地址:" << endl;
cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;
swap_adress_value(&x, &y);
cout << "swap 后,实参的数值和地址:" << endl;
cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;
system("pause");
cout << endl;
cout << endl;
cout << endl;
cout << "指针传递:" << endl;
x = 10;
y = -1;
cout << "swap 前,实参的数值和地址:" << endl;
cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;
swap_pointer(&x, &y);
cout << "swap 后,实参的数值和地址:" << endl;
cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;
system("pause");
cout << endl;
cout << endl;
cout << endl;
cout << "引用传递:" << endl;
x = 10;
y = -1;
cout << "swap 前,实参的数值和地址:" << endl;
cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;
swap_reference(x, y);
cout << "swap 后,实参的数值和地址:" << endl;
cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;
system("pause");
cout << endl;
cout << endl;
cout << endl;
}
再来看执行结果:
值传递:
swap 前,实参的数值和地址:
value(x) = 10,变量x的地址:0046FD4C
value(y) = -1,变量y的地址:0046FD40
swap 前,形参的数值和地址:
value(a) = 10,变量a的地址:0046FC68
value(b) = -1,变量b的地址:0046FC6C
swap 后,形参的数值和地址:
value(a) = -1,变量a的地址:0046FC68
value(b) = 10,变量b的地址:0046FC6C
swap 后,实参的数值和地址:
value(x) = 10,变量x的地址:0046FD4C
value(y) = -1,变量y的地址:0046FD40
请按任意键继续. . .
传递地址且对地址进行修改:
swap 前,实参的数值和地址:
value(x) = 10,变量x的地址:0046FD4C
value(y) = -1,变量y的地址:0046FD40
swap 前,形参的地址和指向的数值:
value(a) = 0046FD4C,*a:10
value(b) = 0046FD40,*b:-1
swap 后,形参的地址和指向的数值:
value(a) = 0046FD40,*a:-1
value(b) = 0046FD4C,*b:10
swap 后,实参的数值和地址:
value(x) = 10,变量x的地址:0046FD4C
value(y) = -1,变量y的地址:0046FD40
请按任意键继续. . .
指针传递:
swap 前,实参的数值和地址:
value(x) = 10,变量x的地址:0046FD4C
value(y) = -1,变量y的地址:0046FD40
swap 前,形参的地址和指向的数值:
value(a) = 0046FD4C,*a:10
value(b) = 0046FD40,*b:-1
swap 后,形参的地址和指向的数值:
value(a) = 0046FD4C,*a:-1
value(b) = 0046FD40,*b:10
swap 后,实参的数值和地址:
value(x) = -1,变量x的地址:0046FD4C
value(y) = 10,变量y的地址:0046FD40
请按任意键继续. . .
引用传递:
swap 前,实参的数值和地址:
value(x) = 10,变量x的地址:0046FD4C
value(y) = -1,变量y的地址:0046FD40
swap 前,形参的地址和指向的数值:
value(a) = 10,a存储地址:0046FD4C
value(b) = -1,b存储地址:0046FD40
swap 后,形参的地址和指向的数值:
value(a) = -1,a存储地址:0046FD4C
value(b) = 10,b存储地址:0046FD40
swap 后,实参的数值和地址:
value(x) = -1,变量x的地址:0046FD4C
value(y) = 10,变量y的地址:0046FD40
请按任意键继续. . .
我们结合运行结果来分析一下:
调用swap_xxx函数之前,变量x,y分别有自己的地址和数值。
调用函数swap_value时,相当于做了以下2个赋值操作:
a = x;b = y;
这只是说把x、y的value分别赋给a、b。
可以通过结果看出,a、b有自己的内存,内存地址与x、y不同。且调出swap_value之后,发生数值交换的仅是内部变量而已,外部变量x、y的地址和数值并没受到影响。
调用swap_adress_value/swap_pointer时,相当于做了以下2个赋值操作:
*a = &x;*b = &y;
这里&是取地址的意思,是把x、y的地址分别赋给指针变量a、b,也就是说a有自己的内存地址,这块内存存储的就是x的地址,也即a指向了x。
只不过,在函数swap_adress_value内部,只是将指针变量a和b的value做了交换。所以外部变量x、y不受任何影响,而内部变量a、b有自己的内存地址,a和b的地址未发生改变,但是a和b的value改变了,a和b指向的变量改变了。
而在swap_pointer里面,则是将a和b指向的内容作了交换,a和b的value未发生改变,依然指向之前的内存,但是它们指向的内存里面所存储的内容作了交换。同时在外部,x和y依然对应着原来的内存,所以x和y的地址都没有改变,但是里面写入的值却发生了改变。也就是说内部变量交换的时候,是在外部变量所对应的同一块内存空间上进行的。
调用swap_reference时,相当于做了以下2个赋值操作:
&a = x;&b = y;
这里&是引用的意思,是说a和x对应着同一块内存,对其中任何一个的修改,另一个都会受到影响,a和x相当于同一个变量的两个名字。所以内部变量a和x的地址一样,数值一样。交换之后,a和x的数值、地址依然一样。
#define
#ifdef的用途
#include的作用
#include是文件包含指令,在程序编译时,把#include后面指定文件的内容包含进当前的文件中。主要有2种形式:
1、#include<file.h>
从标准库中寻找file.h文件,是系统库头文件,根据一定的规则查找filh.h。
2、#include”file.h”
从工程目录下开始寻找file.h文件,是自定义的头文件,在源文件所在位置查找filh.h。
typedef
C语言工程的编译过程
如下图所示: