C++中一个很重要也是最基本的概念,函数,这节我们来看看C++中函数在实际中的应用
1.函数的声明
这和大多数编程语言一样,访问修饰符 返回类型 函数名(参数)
2.函数的参数
这个很重要,函数的形参,基本数据类型就不说了,主要来看一下C++中特有的指针参数,引用形参,以及数组作为形参等
其实说到底,函数只有两种传递参数的方式:
1.按值传递,比如:传递基本数据类型 int这些都是按值传递的
2.另外就是传地址, 这个就是我们接下来要详细介绍的用指针引用数组等作为形参
2.1指针形参
#include<iostream>
using namespace std;
void testfunction(int* p);
void main()
{
int i=3;
int* p=&i;
testfunction(p);
cout<<"main:"<<*p<<endl;//Print: main:10
}
void testfunction(int* p)
{
*p=10;
cout<<"testfunction:"<<*p<<endl;//Print: testfunction:10
}
从上面代码段来看,形参的值改变之后,实参的值也改变了。我们在看一下下面的代码块:
#include<iostream>
using namespace std;
void testfunction(int* p);
void main()
{
int i=3;
int* p=&i;
testfunction(p);
cout<<"main:"<<*p<<endl;//Print: main:3
}
void testfunction(int* p)
{
int i=10;
p=&i;
cout<<"testfunction:"<<*p<<endl;//Print: testfunction:10
}
把形参的指向改变后,不影响实参,这个怎么解释呢?看图说明
这是第二份代码在内存中的示意图,从中可以看出指针也在内存中占据一块内存空间,至于第一份代码中为什么能改变 i 的值,那是因为形参和实参都同时指向一块内存空间
2.2数组形参
用数组作为形参:
#include<iostream>
using namespace std;
void testfunction(int p[]);
void main()
{
int i[]={1,2};
testfunction(i);
cout<<"main:"<<i<<endl;//Print: main:003CFC08
cout<<"main:"<<i[1]<<endl;//Print: main:10
}
void testfunction(int p[])
{
p[1]=10;
cout<<"testfunction:"<<p<<endl;//Print: testfunction:003CFC08
cout<<"testfunction:"<<p[1]<<endl;//Print: testfunction:10
}
这里可以看出输出数组的内存地址,形参和实参的地址是一模一样的,所以形参改变,实参也改变。这是为什么呢??
上诉代码等同于下面的代码:
#include<iostream>
using namespace std;
void testfunction(int* p);
void main()
{
int i[]={1,2};
testfunction(i);
cout<<"main:"<<i<<endl;//Print: main:003CFC08
cout<<"main:"<<i[1]<<endl;//Print: main:10
}
void testfunction(int* p)
{
*(p+1)=10;
cout<<"testfunction:"<<p<<endl;//Print: testfunction:003CFC08
cout<<"testfunction:"<<p[1]<<endl;//Print: testfunction:10
}
这样结合我们指针作为形参所在内存中分布的示意图就能够解释了。
2.3 引用形参
还记得我们说过,引用其实就是指针常量,指针常量里面的值是可以改变的,只是地址不能改变#include<iostream>
using namespace std;
void testfunction(int &p);
void main()
{
int i=2;
testfunction(i);
cout<<"main:"<<i<<endl;//Print: main:10
}
void testfunction(int &p)
{
p=10;
cout<<"testfunction:"<<p<<endl;//Print: testfunction:10
}
引用是特殊的指针,它由编译器自动解引用,如果我们自己手动解引用就是如下代码:
#include<iostream>
using namespace std;
void testfunction(int* const p);
void main()
{
int i=2;
testfunction(&i);
cout<<"main:"<<i<<endl;//Print: main:10
}
void testfunction(int* const p)
{
*p=10;
cout<<"testfunction:"<<*p<<endl;//Print: testfunction:10
}
3.4 采用const修饰形参
上面3.3中我已经使用了一种const修饰,上面的是指针常量,指向地址不能改变,那么我们如果希望形参的值不能改变,就应该使用常量指针。
#include<iostream>
using namespace std;
void testfunction(const int* p);
void main()
{
int i=2;
testfunction(&i);
cout<<"main:"<<i<<endl;//Print: main:10
}
void testfunction(const int* p)
{
int i=10;
p=&i;
cout<<"testfunction:"<<*p<<endl;//Print: testfunction:10
}
正在指针那节中已经介绍过了,可否理解
还有一些多变的,比如:
#include<iostream>
using namespace std;
int* const testfunction(int* const p);
void main()
{
int i=2;
int* const p=testfunction(&i);
cout<<"main:"<<*p<<endl;//Print: main:10
}
int* const testfunction(int* const p)
{
*p=10;
cout<<"testfunction:"<<*p<<endl;//Print: testfunction:10
return p;
}
只要理解了指针常量和常量指针的区别,然后结合他们在内存中的分布图,就算在怎么变化的复杂都可以理解了
4.C++可变参数
C++可变参数是一个重要的概念,具体使用方式如下
#include<iostream>
using namespace std;
int testfunction(int count,...);
void main()
{
cout<<testfunction(3,4,6,5)<<endl;
}
int testfunction(int count,...)
{
int sum=0;
va_list arg_ptr;
_crt_va_start(arg_ptr,count);
for (int i = 0; i < count; i++)
{
sum+=_crt_va_arg(arg_ptr,int);
}
_crt_va_end(arg_ptr);
return sum;
}
输出的结果是:4+6+5 15
第一个3表示有三个值
这里还有三个宏 _crt_va_start,_crt_va_arg,_crt_va_end 也可以导入头文件cstdarg后 va_start,va_arg,va_end 这三个宏的意思看名字就理解了
或者可以查看源码后,自己替换跟踪一下看看
#include<iostream>
using namespace std;
int testfunction(int count,...);
void main()
{
cout<<testfunction(3,7,6,5)<<endl;
}
int testfunction(int count,...)
{
int sum=0;
va_list arg_ptr;
//等同于_crt_va_start(arg_ptr,count)
arg_ptr=(va_list)_ADDRESSOF(count)+_INTSIZEOF(count);
/* 等同于for (int i = 0; i < count; i++){sum+=_crt_va_arg(arg_ptr,int);}*/
for (int i = 0; i < count; i++)
{
//等同于 sum+=_crt_va_arg(arg_ptr,int);
arg_ptr+=_INTSIZEOF(int);
sum+=*(int *)(arg_ptr-_INTSIZEOF(int));
}
//等同于_crt_va_end(arg_ptr);
arg_ptr=0;
return sum;
}
主要是还不懂位运算,搞半天还是不知道_INTSIZEOF宏在做什么,反正一直都是反回4来着