NOIP学习小站
西安交通大学附属中学航天学校

函数参数传递

一、值传递

来看一个例子,使用函数交换两个变量的值:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
using namespace std;
void swap(int x,int y){
int t = x;
x = y;
y = t;
}
int main()
{
int a,b;
cin>>a>>b;
cout<<a<<" "<<b<<endl;
swap(a,b);
cout<<a<<" "<<b<<endl;
return 0;
}
#include<iostream> using namespace std; void swap(int x,int y){ int t = x; x = y; y = t; } int main() { int a,b; cin>>a>>b; cout<<a<<" "<<b<<endl; swap(a,b); cout<<a<<" "<<b<<endl; return 0; }
#include<iostream>
using namespace std; 
void swap(int x,int y){
	int t = x;
	x = y;
	y = t;
}
int main()
{
    int a,b;
    cin>>a>>b;
    cout<<a<<" "<<b<<endl;
    swap(a,b);
    cout<<a<<" "<<b<<endl;
    return 0;
}

运行程序会发现,调用swap(a,b)并不能交换a、b两个变量的值!原因很简单,执行swap函数时,会将实际参数a、b的值赋值(拷贝)给swap函数的形式参数x、y,而 x、y是swap函数的局部变量,a、b是main函数的局部变量,在内存里a与x,b与y不是同一个存储单元,swap函数能够交换x、y的值,但并不能影响到main函数中调用swap函数的实际参数a、b的值。这样的将实际参数的值赋值(拷贝)给函数的形式参数的传递方式称为值传递。值传递的函数体中修改形式参数的值不会影响到实际参数的值。

二、引用传递

我们将swap函数作一点小小的改动:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
using namespace std;
void swap(int &x,int &y){
int t = x;
x = y;
y = t;
}
int main()
{
int a,b;
cin>>a>>b;
cout<<a<<" "<<b<<endl;
swap(a,b);
cout<<a<<" "<<b<<endl;
return 0;
}
#include<iostream> using namespace std; void swap(int &x,int &y){ int t = x; x = y; y = t; } int main() { int a,b; cin>>a>>b; cout<<a<<" "<<b<<endl; swap(a,b); cout<<a<<" "<<b<<endl; return 0; }
#include<iostream>
using namespace std; 
void swap(int &x,int &y){
	int t = x;
	x = y;
	y = t;
}
int main()
{
    int a,b;
    cin>>a>>b;
    cout<<a<<" "<<b<<endl;
    swap(a,b);
    cout<<a<<" "<<b<<endl;
    return 0;
}

其实就是在形式参数x、y前添加了一个特殊的符号&,表示引用传参,这个时候形式参数x和实际参数a是同一个存储单元(x相当于a的别名),形式参数y与实际参数b也是同样的关系,那么在函数体中修改形式参数x、y的值,就会影响到实际参数a、b的值。

可以利用引用传递的特点,设计函数来直接改变实际参数的值,例如下面的将字符串转大写的程序,大家仔细阅读并对比两段程序代码:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
#include<string>
using namespace std;
//值传递参数
//函数返回值为string,返回转大写后的字符串
string convert(string s){
//修改参数s中的小写字母为大写
for(size_t i=0;i<s.length();i++){
//元素为小写字母,改为对应大写字母
if(s[i]>='a' && s[i]<='z')
s[i] -= 32;
}
return s; //返回修改后的字符串
}
int main()
{
string ss = "Hello World";
cout<<ss<<endl;
cout<<convert(ss)<<endl;
return 0;
}
#include<iostream> #include<string> using namespace std; //值传递参数 //函数返回值为string,返回转大写后的字符串 string convert(string s){ //修改参数s中的小写字母为大写 for(size_t i=0;i<s.length();i++){ //元素为小写字母,改为对应大写字母 if(s[i]>='a' && s[i]<='z') s[i] -= 32; } return s; //返回修改后的字符串 } int main() { string ss = "Hello World"; cout<<ss<<endl; cout<<convert(ss)<<endl; return 0; }
#include<iostream>
#include<string>
using namespace std;
//值传递参数
//函数返回值为string,返回转大写后的字符串
string convert(string s){
	//修改参数s中的小写字母为大写
	for(size_t i=0;i<s.length();i++){
		//元素为小写字母,改为对应大写字母
		if(s[i]>='a' && s[i]<='z')
			s[i] -= 32;
	}
	return s;  //返回修改后的字符串
}

int main()
{
	string ss = "Hello World";
	cout<<ss<<endl;
	cout<<convert(ss)<<endl;
    return 0;
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
#include<string>
using namespace std;
//引用传递参数
//在函数体中修改引用参数字符串中的小写字母为大写
void convert(string &s){
for(size_t i=0;i<s.length();i++){
//元素为小写字母,改为对应大写字母
if(s[i]>='a' && s[i]<='z')
s[i] -= 32;
}
}
int main()
{
string ss = "Hello World";
cout<<ss<<endl;
convert(ss);
cout<<ss<<endl;
return 0;
}
#include<iostream> #include<string> using namespace std; //引用传递参数 //在函数体中修改引用参数字符串中的小写字母为大写 void convert(string &s){ for(size_t i=0;i<s.length();i++){ //元素为小写字母,改为对应大写字母 if(s[i]>='a' && s[i]<='z') s[i] -= 32; } } int main() { string ss = "Hello World"; cout<<ss<<endl; convert(ss); cout<<ss<<endl; return 0; }
#include<iostream>
#include<string>
using namespace std;
//引用传递参数
//在函数体中修改引用参数字符串中的小写字母为大写
void convert(string &s){
	for(size_t i=0;i<s.length();i++){
		//元素为小写字母,改为对应大写字母
		if(s[i]>='a' && s[i]<='z')
			s[i] -= 32;
	}
}

int main()
{
	string ss = "Hello World";
	cout<<ss<<endl;
	convert(ss);
	cout<<ss<<endl;
    return 0;
}

三、地址传递

另外还要注意到函数参数是数组的情况,看下面的程序:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
using namespace std;
void test(int a[]){ //参数是数组
a[0]++;
}
int main()
{
int s[5] = {1,2,3,4,5};
cout<<s[0]<<endl;
test(s);
cout<<s[0]<<endl;
return 0;
}
#include<iostream> using namespace std; void test(int a[]){ //参数是数组 a[0]++; } int main() { int s[5] = {1,2,3,4,5}; cout<<s[0]<<endl; test(s); cout<<s[0]<<endl; return 0; }
#include<iostream>
using namespace std; 
void test(int a[]){    //参数是数组
	a[0]++;
}
int main()
{
    int s[5] = {1,2,3,4,5};
    cout<<s[0]<<endl;
    test(s);
    cout<<s[0]<<endl;
    return 0;
}

运行程序会发现,执行test(s)后,s[0]的值发生了变化,也就是test函数中修改a[0]的值影响到了s[0]。其实,如果函数的参数是数组,形式参数和实际参数其实是同一个数组,数组形式参数就是数组实际参数的别名,在函数体中修改数组形式参数的元素当然会影响数组实际参数的元素。这样的实际参数传递到形式参数的方式称为地址传递

再来试试下面的程序,进一步体会数组作为函数参数时,地址传递的作用机制:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
using namespace std;
int a[1001];
//数组作为参数,一般还需要一个参数来说明数组实际存储元素的个数
void read(int arr[],int n){
for(int i=0;i<n;i++)
cin>>arr[i];
}
void exec(int arr[],int n){
for(int i=0;i<n;i++)
arr[i] *= arr[i];
}
void out(int arr[],int n){
for(int i=0;i<n;i++)
cout<<arr[i]<<" ";
cout<<endl;
}
int main()
{
int n;
cin>>n;
read(a,n);
out(a,n);
exec(a,n);
out(a,n);
return 0;
}
#include<iostream> using namespace std; int a[1001]; //数组作为参数,一般还需要一个参数来说明数组实际存储元素的个数 void read(int arr[],int n){ for(int i=0;i<n;i++) cin>>arr[i]; } void exec(int arr[],int n){ for(int i=0;i<n;i++) arr[i] *= arr[i]; } void out(int arr[],int n){ for(int i=0;i<n;i++) cout<<arr[i]<<" "; cout<<endl; } int main() { int n; cin>>n; read(a,n); out(a,n); exec(a,n); out(a,n); return 0; }
#include<iostream>
using namespace std;
int a[1001];
//数组作为参数,一般还需要一个参数来说明数组实际存储元素的个数
void read(int arr[],int n){
	for(int i=0;i<n;i++)
		cin>>arr[i];
}
void exec(int arr[],int n){
	for(int i=0;i<n;i++)
		arr[i] *= arr[i];
}
void out(int arr[],int n){
	for(int i=0;i<n;i++)
		cout<<arr[i]<<" ";
	cout<<endl;
}
int main()
{
    int n;
    cin>>n;
    read(a,n);
    out(a,n);
    exec(a,n);
    out(a,n);
    return 0;
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
using namespace std;
int n,a[1001];
//自定义函数中使用全局变量
void read(){
for(int i=0;i<n;i++)
cin>>a[i];
}
void exec(){
for(int i=0;i<n;i++)
a[i] *= a[i];
}
void out(){
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
cout<<endl;
}
int main()
{
cin>>n;
read();
out();
exec();
out();
return 0;
}
#include<iostream> using namespace std; int n,a[1001]; //自定义函数中使用全局变量 void read(){ for(int i=0;i<n;i++) cin>>a[i]; } void exec(){ for(int i=0;i<n;i++) a[i] *= a[i]; } void out(){ for(int i=0;i<n;i++) cout<<a[i]<<" "; cout<<endl; } int main() { cin>>n; read(); out(); exec(); out(); return 0; }
#include<iostream>
using namespace std;
int n,a[1001];
//自定义函数中使用全局变量 
void read(){
	for(int i=0;i<n;i++)
		cin>>a[i];
}
void exec(){
	for(int i=0;i<n;i++)
		a[i] *= a[i];
}
void out(){
	for(int i=0;i<n;i++)
		cout<<a[i]<<" ";
	cout<<endl;
}
int main()
{
    cin>>n;
    read();
    out();
    exec();
    out();
    return 0;
}

其实我们也可以自定义函数实现求字符串长度或者字符串所有字符转换成小写:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include<iostream>
using namespace std;
int strlen(char str[]){
int n = 0;
for(int i=0;str[i];i++) n++;
return n;
}
void strlwr(char str[]){
for(int i=0;str[i];i++){
if(str[i]>='A' && str[i]<='Z') str[i] += 'a'-'A';
}
}
int main()
{
cout<<strlen("")<<endl;
char str[] = "Hello World!";
strlwr(str);
cout<<str<<endl;
return 0;
}
#include<iostream> using namespace std; int strlen(char str[]){ int n = 0; for(int i=0;str[i];i++) n++; return n; } void strlwr(char str[]){ for(int i=0;str[i];i++){ if(str[i]>='A' && str[i]<='Z') str[i] += 'a'-'A'; } } int main() { cout<<strlen("")<<endl; char str[] = "Hello World!"; strlwr(str); cout<<str<<endl; return 0; }
#include<iostream>
using namespace std;
int strlen(char str[]){
	int n = 0;
	for(int i=0;str[i];i++) n++;
	return n;
}
void strlwr(char str[]){
	for(int i=0;str[i];i++){
		if(str[i]>='A' && str[i]<='Z') str[i] += 'a'-'A';	
	}
}
int main()
{
	cout<<strlen("")<<endl;
	char str[] = "Hello World!";
	strlwr(str);
	cout<<str<<endl;
    return 0;
}

函数使用地址传参更普遍的方式是使用指针作为函数的参数,具体的方法可以查阅这篇文章:指针

登录

注册