一、函数声明(函数原型)
1.需要函数原型的原因
(1)原型告诉编译器,函数有某个参数,如果如果程序没有提供这种参数,就提示报错。
(2)当函数完成计算时,将把返回值放在指定的位置,可能是CPU寄存器,也可能是内存,然后调用函数从这个位置取得返回值。
(3)原型指出了函数类型,编译器知道应该检索多少个字节
2.原型的功能
(1)编译器正确处理返回值
(2)编译器检查参数数目是否正确
(3)编译器检查参数类型是否正确,如果不正确就转化为正确的类型
二、函数与数组
多数情况下,数组名和指针灵活转换,C++将数组名解释为第一个元素的地址,但也有一些例外:
1.对数组名使用sizeof得到整个数组的长度
2.地址运算符&用于数组名,将返回整个数组的地址
#include <iostream>
using namespace std;
const int arsize=8;
int sum_arr(int arr[],int n);
/*
当且在函数头和函数原型中,int *arr 和int arr[]是相同的,arr是一个int指针
但是在函数体中,arr还是可以看作数组
将cookies的位置、元素类型、元素的数量传给sum_arr函数
*/
int sum_arr(int *arr,int n)
{
int total=0;
cout<<arr<<" arr"<<endl;
cout<< sizeof(arr)<<"=sizeof arr"<<endl;//指针的大小,为8
for (int i=0;i<n;i++)
total=total+arr[i];
return total;
}
int main(int argc, char* argv[])
{
int cookies[arsize]={1,2,3,4,5,6,7,8};
cout<<cookies<<" array address"<<endl;
cout<<sizeof(cookies)<<"=sizeof cookies"<<endl;//32,数组的大小
int sum=sum_arr(cookies,arsize);
cout<<sum<<endl;
return 0;
}
注意点:C++里,调用函数时要把数组类型和元素数量都通过参数传递
三、函数和二维数组
#include <iostream>
using namespace std;
const int arsize=8;
int sum(int (*arr)[4],int size)//int sum(int arr[][4],int size)也可以
'''
data是一个有三个元素的数组,每个元素是一个数组,有4和元素
通过指针传递时,指针指向的是由4个int组成的数组,因此指针需要指定列数4
也就是说sum只接受由4列组成的数组,而接受的行数由另一个参数指定
'''
{
int total=0;
for (int r=0;r<size;r++)
{
for (int c=0;c<4;c++)
total=total+arr[r][c];
}
return total;
}
int main(int argc, char* argv[])
{
int data[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int ans=sum(data,3);
cout<<ans;
}
四、常见的函数使用方法——值传递、引用传递、指针传递
1、值传递:形参时实参的拷贝,改变函数形参并不影响函数外部的实参,这是最常用的一种传递方式,也是最简单的一种传递方式。只需要传递参数,返回值是return考虑的;使用值传递这种方式,调用函数不对实参进行操作,也就是说,即使形参的值发生改变,实参的值也完全不受影响。
#include <iostream>
using namespace std;
void swap(int,int);
int main()
{
int a=1,b=2;
cout<<"a="<<a<<",b="<<b<<endl;
swap(a,b);
cout<<"a="<<a<<",b="<<b<<endl;//a和b的值不变
return 0;
}
void swap(int x,int y)
{
int p=x;
x=y;
y=p;
}
2、指针传递:指针传递其实是值传递的一种,它传递的是地址。值传递过程中,在函数的栈中有开辟了内存空间来存放主调函数放进来实参的值,从而成为一个副本。因为指针传递的是外部参数的地址,当调用函数的形参发生改变时,自然外部实参也发生改变。
#include <iostream>
using namespace std;
void swap(int *x,int *y);
int main()
{
int a=1,b=2;
cout<<"a="<<a<<",b="<<b<<endl;
cout<<"&a="<<&a<<",&b="<<&b<<endl;
cout<<"********1**********"<<endl;
swap(&a,&b);//a,b的值改变。指针在传参的时候,必须传变量的地址过去,否则不能改变变量的值。
cout<<"a="<<a<<",b="<<b<<endl;
cout<<"&a="<<&a<<",&b="<<&b<<endl;
cout<<"********3**********"<<endl;
return 0;
}
void swap(int *x,int *y)
{
int p=*x; //int p; p=*x;
*x=*y;
*y=p;
cout<<"x="<<x<<",y="<<y<<endl;
cout<<"*x="<<*x<<",*y="<<*y<<endl;
cout<<"&x="<<&x<<",&y="<<&y<<endl;
cout<<"********2**********"<<endl;
}
3、引用传递:被调函数的形参虽然也作为局部变量在栈中开辟了内存空间,但在栈中放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被间接寻址,即通过栈中的存放的地址访问主调函数中的中的实参变量(相当于一个人有两个名字),因此形参在任意改动都直接影响到实参,与指针类似。
#include <iostream>
using namespace std;
void swap(int &x,int &y);
int main()
{
int a=1,b=2;
cout<<"a="<<a<<",b="<<b<<endl;
cout<<"&a="<<&a<<",&b="<<&b<<endl;
cout << "*******1**********"<<endl;
swap(a,b);//引用在函数传参的时候,只需要传变量名过去,函数形参用引用接即可。
cout<<"a="<<a<<",b="<<b<<endl;
cout<<"&a="<<&a<<",&b="<<&b<<endl;
cout << "*******4**********"<<endl;
return 0;
}
void swap(int &x,int &y)
{
cout<<"x="<<x<<",y="<<y<<endl;
cout<<"&x="<<&x<<",&y="<<&y<<endl;
cout << "*******2**********"<<endl;
int p=x;
x=y;
y=p;
cout<<"x="<<x<<",y="<<y<<endl;
cout<<"&x="<<&x<<",&y="<<&y<<endl;
cout << "*******3**********"<<endl;
}
五、附指针和引用的区别
1.引用与指针的区别
(1)指针是一个实体,需要分配内存空间。引用只是变量的别名,不需要分配内存空间。
(2)引用在定义的时候必须进行初始化,并且不能够改变。指针在定义的时候不一定要初始化,并且指向的空间可变。(注:不能有引用的值不能为NULL)
(3)有多级指针,但是没有多级引用,只能有一级引用。
(4)指针和引用的自增运算结果不一样。(指针是指向下一个空间,引用时引用的变量值加1)
(5)sizeof 引用得到的是所指向的变量(对象)的大小,而sizeof 指针得到的是指针本身的大小。
(6)引用访问一个变量是直接访问,而指针访问一个变量是间接访问。
(7)不能引用数组
2.在函数中的使用指针和引用
(1)引用在函数传参的时候,只需要传变量名过去,函数形参用引用接即可。而指针在传参的时候,必须传变量的地址过去,否则不能改变变量的值。
2)引用没有分配内存空间,所以访问函数形参就是访问引用的变量,是直接访问。而指针分配了内存空间用来保存变量的地址,需要通过保存的地址找到指向的变量,是间接访问。
参考文献:
https://www.cnblogs.com/happying30/p/9484860.html