C++中的参数类型
数组
数组是相同类型数据的集合。引入数组就不需要在程序中定义大量的变量,大大减少程序中变量的数量,使程序精炼,而且数组含义清楚,使用方便,明确地反映了数据间的联系。许多好的算法都与数组有关。熟练地利用数组,可以大大地提高编程的效率,加强程序的可读性。
一个数组在内存中占用的存储单元是连续的,也就是说一个数组在内存中占用一片连续的存储单元。在32位的机器上,一个int类型的值占4Byte,如果a[0]的地址是2000,那么a[1]的地址就是2004,a[2]的地址就是2008,a[3]的地址就是2012……如此类推。
strlen()与sizeof()的区别如下所示:
- strlen()是函数,在运行时才能计算。参数必须是字符型指针(char*),且必须是以'\0'结尾的。当数组名作为参数传入时,实际上数组已经退化为指针了。它的功能是返回字符串的长度。
- sizeof()是运算符,而不是一个函数,在编译时就计算好了,用于计算数据空间的字节数。因此,sizeof不能用来返回动态分配的内存空间的大小。sizeof常用于返回类型和静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系。
指针
数据在内存中的存储:如果在程序中定义了一个变量,在编译时就给这个变量分配内存单元。系统根据程序中定义的变量类型,来分配一定长度的空间。例如,C++编译系统在32位机器上为整型变量分配4Byte,为单精度浮点型变量分配4Byte,为字符型变量分配1Byte。内存区的每一个字节有一个编号,这个编号就是地址。程序经过编译以后已经将变量名转换为变量的地址,对变量值的存取都是通过地址进行的。
这种按变量地址存取变量值的方式称为直接存取方式,或直接访问方式。还可以采用另一种称为间接存取(间接访问)的方式,在程序中定义一种特殊的变量,专门用来存放地址。由于通过地址能找到所需的变量单元,因此可以说,地址指向该变量单元。因此将地址形象化地称为“指针”,一个变量的地址称为该变量的指针。如果有一个变量是专门用来存放另一变量地址(即指针)的,则它称为指针变量。指针变量的值(即指针变量中存放的值)是地址(即指针)。
指针也是一种变量,普通的变量存放的是实际的数据,而指针变量包含的是内存中的一块地址,这块地址指向某个变量或者函数。指针的内容包括:指针的类型、指针所指向的类型、指针的值以及指针本身所占的内存区。
数组与指针:
数组指针,也称行指针,假设有定义int(*p)[n];且()优先级高,首先说明p是一个指针,且指向一个整型的一维数组。这个一维数组的长度是n,也可以说是p的步长,也就是说执行p+1时,p要跨过n个整型数据的长度。
指针数组,假设有定义int*p[n];且[ ]优先级高,可以理解为先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里若执行p+1操作则是错误的,p=a这样赋值也是错误的,因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量,只用来存放变量地址。但可以这样*p=a赋值,这里*p表示指针数组第一个元素的值,a的首地址的值。
数组指针和指针数组两者的区别:
- 数组指针只是一个指针变量,可以认为是C语言里专门用来指向二维数组的,它占用内存中一个指针的存储空间;
- 指针数组是多个指针变量,以数组形式存在内存当中,占用多个指针的存储空间。还需要说明的一点就是,同时用来指向二维数组时,其直接引用和用数组名引用都是一样的。
字符串与指针:
(1)字符串指针变量本身是一个变量,用于存放字符串的首地址。定义指针时,编译器并不为指针所指向的对象分配空间,它只是分配指针本身的空间。
(2)字符串本身是存放在以该首地址为首的一块连续的内存空间中,并以'\0'作为字符串的结束标志。
(3)字符数组是由于若干个数组元素组成的,每个元素中存放字符串的一个字符。在定义一个字符数组时,编译后就会分配一个内存单元,每个元素都有确定的地址。
函数与指针:
函数指针是指向函数的指针变量。所以,函数指针首先是个指针变量,而且这个变量指向一个函数。C++在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,就可以用该指针变量调用函数了。
函数指针的声明方法是:
返回值类型 (*指针变量名)([形参列表]);
其中,返回值类型说明函数的返回值类型,(*指针变量名)这句的括号不能省略。
引用
引用是一种变量类型,它用于为一个变量起一个别名。
引用的声明方法是:
类型标识符 &引用名=目标变量名;
定义引用r,它是变量a的引用,即别名。经过这样的声明后,a和r的作用都一样,都代表着同一变量。a和r占用内存的同一个存储单元,即具有同一地址。在声明一个引用变量时,必须同时使之初始化,即声明它代表哪个变量。函数执行期间,不可以将其再作为其他变量的引用。
引用一个重要的作用就是作为函数的参数。
引用作为函数的参数举例:
#include<iostream>
using namespace std;
void Mmin1(int a,int b)
{
int temp;
if(a>b)
{
temp=a;
a=b;
b=temp;
}
}
void Mmin2(int &a,int &b) // 引用作为函数的参数
{
int temp;
if(a>b)
{
temp=a;
a=b;
b=temp;
}
}
int main()
{
int a=30,b=20;
Mmin1(a,b);
cout<<a<<" "<<b<<endl; // a、b的值保持不变。
Mmin2(a,b);
cout<<a<<" "<<b<<endl; // a的值是20,b的值是30. a、b的值被修改了
return 0;
}
程序的执行结果是:
30 20
20 30
将一般变量作为函数的参数,传给形参的是变量的值,传递是单向的。如果在执行函数期间形参的值发生变化,并不传回给实参。因为在调用函数时,形参和实参不是同一个存储单元。
使用引用传递函数的参数时,在内存中并没有产生实参的副本,而是对实参直接操作。当使用一般变量传递函数的参数时,当函数发生调用,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率更高,所占空间更少。
使用指针作为函数的参数虽然也能达到与使用引用同样的效果,但是在被调函数中同样要给形参分配存储单元,且需要重复使用“*指针变量名”的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参,这些都不太方便。
常引用
如果既要提高程序的效率,又要使传递给函数的数据不在函数中被改变,就应该使用常引用。
常引用的声明方式是:
const 类型标识符 &引用名=目标变量名;
用这种方式声明的引用,不能通过引用对目标变量的值进行修改,在程序中使引用的目标成为const类型,从而保证了引用的安全性。