1、关于函数原型:
首先,函数的原型说明了函数在调用时候要注意的规则,比如参数的类型和数量,还有一个比较重要的就是函数的返回类型。在函数返回值的时候,他将这个值返回到指定的寄存器或者内存中,然后调用者根据这个返回值的类型才知道在内存中或者寄存器中通过偏移多少来获取到返回值。
并且C++中的风格是不喜欢把函数的定义直接定义在main函数的前面的,所以还是需要写函数原型的。并且在声明函数原型的时候,函数的参数连别中可以不包括变量名,但是要包括类型。并且及时参数名和实际定义的时候不一样也没有关系。
函数原型在C语言中,我没怎注意,一直都是把函数定义在调用者的前面。但是实际上函数原型在C++中有着很重要的角色。他可以帮助调用者在内存中找寻返回值,也可以帮助检查参数列表。
C++中如过定义了一个函数的参数列表是空的话,那么和这个参数列表里面有void是一个意思,表明函数没有任何参数。但是在ANSIC中这就表示现在不指出参数。如果函数是有参数的,但是调用的时候没有给出任何参数,C++将会根据函数原型检查出来这是个错误。
在ANSIC中如果函数的参数要求一个int值,但是传递给他的是一个double值,那么编译器只会在double中的前16位截取下来传递给函数。但是C++因为有了原型,他会在传递之前将传递的参数转化成原型中和参数列表相对应的类型。
通过函数原型对函数的检查一般在函数的编译阶段进行,被称为静态类型检查。
局部变量分为两种,一种是在函数里面所定义的变量,还有一种就是形参,也就是函数的参数。
2、函数与数组
函数名和指向数组的指针基本是相同的,都是一个数组,一断连续内存的首地址。
但是还是有一些略微的不同,这个不同我特意写了一个博文
http://blog.csdn.net/xr_acmer/article/details/38843671
int test[]和int *test只有在函数头和函数的声明部分意义才想通,都代表一个地址。对指针加1的作用是加上了一个和指针指向元素大小相等的值。
3、指针和const
指针和const有两种组合,第一种是将指针指向常量,防止指针改变它所指向的值,第二个就是把指针本身声明为一个常量,因为指针其实也是一个值,这样就不能改变这个指针指向的位置。
但是,这里面有一点要注意的是,pt如果是一个指向常量的指针,但是pt指向的这个值不一定就是一个常量,指针指向的这个值是常量是相对于指向它的指针来说的,实际上是什么样都无所谓。总之,如果一个指针被声明为一个指向常量的指针的话,那么这个值是不可能通过这个指针来修改的。
C++中可以把常量的地址复制给指向常量的指针,这样一来,常量和这个指针都是不能改动那个数值的。但是,如果你把一个常量的地址赋值给了一个普通的指针,C++是不允许这样的操作出现的。因为这样一来就证明你可以用指针改动数值,但是同时那个数值又被声明为const,这就很矛盾。
声明一个指向常量的指针,不能改变的仅仅是不能通过这个指针去修改指向的那个数组,但是指针的值本身是可以修改的,因为指针的值没有声明为一个常量。所以可以随时改变这个指针的指向,但是,即使指针指向了其他的数据,那么依然会保持不能用这个指针修改数据的特性。
const在声明指针的时候有两种形式。
第一种,const int * p; 这样就声明了一个指向常量的指针。
第二种, int * const p ; 这样就声明了一个指向整型数组的常量指针,也就是说此时不是指针指向的数据是常量而是指针本身是常量,这也就说明了,指针只能指向他被第一次赋值的那个数据,之后就再也不能改动了。但是允许这个指针去修改他所指向的数据。
关于数组和const,要注意的是,const最好只在一级间接结构上使用,超过一级则会出问题
在传递二维数组的指针的时候就不能再指定形参为const,因为这已经不是一级引用了。会出现错误
4、字符串和函数
字符串的表现形式在C语言中有三种
char 数组,并且最后一位要用\0
双引号引起来的字面量。(在传递字符串字面量实际上传递的是这个字符串的地址)
一个指向char数组的指针。
在传递字符串的时候,不用传递这个字符串的长度,因为无论是什么形式的字符串,他的最后一个字符都是空字符。按顺序查找每个字符就行。并且大多数在传递一个字符串的时候,如果不希望他更改,那么要限定为const.
5、函数指针
函数指针存储的是函数机器码在内存中的首地址,也就是函数名。
在声明一个指针的时候,必须要声明这个指针指向数据的类型,在声明指向函数的指针的时候,必须要声明一下函数的详细信息。详细信息包括函数的返回值类型还有参数列表,当然,这里的参数列表不用写函数名,仅仅写出类型即可。
例如
double pam(int y);
声明一个指向这个函数的指针
double (*p) (int)
*p就相当于pam函数,那么p就是指向这个函数的指针。
声明完成之后便可以把相应的函数名赋值给这个指针。赋值的成功与否,取决于这个函数指针的类型和参数列表与实际函数的返回类型和参数列表是否对应。
在声明了函数指针之后,通过这个指针来调用函数有两种方式
一种是(*pf)(),这样的调用强调了我们正在使用指针。因为pf是指向函数的指针,那么*pf就是这个函数。
另一种是pf(),因为函数名就是这个函数机器代码的首地址,那么指向函数的指针也是地址,所以,就可以直接把指针当作函数名来用。
在声明函数指针的时候,其实只要记住一点,就是把函数原型中的函数名变成*指针名即可。
而在声明一个指向函数的指针的数组的时候也很简单,double (*p[4])(int);这就声明了一个指向返回类型为double,参数是int的函数指针的数组,数组内有4个元素。数组名为p.
在声明一个指向数组的指针的时候,首先要做的就是(*p)[4],把*和p进行结合,这样的话就是一个指向有四个元素的数组的指针。相当于double (*p) (int)中 的p。所以在正式声明一个指向函数指针数组的指针的时候可以做如下声明。
double (*(*p)[4])(int);第一种解释:这里(*p)就是指向这个数组的指针,*(*p)[i]就可以访问到数组中指向函数的指针,再加*就可以访问到函数的返回值。
第二种解释:p是指向数组的指针,*p就是数组,可以通过(*p)[i]来访问数组中第i个指向函数的指针。
即使是指向函数的指针,或者是指向指针数组的指针,也有p 和&p之分
两者虽然数值一样,都是首地址,但是一个是数组第一个元素的地址,另一个是整个数组的首地址。
+1之后的结果截然不同,并且想访问数组的第一个元素,对p解除一次引用,但是对&p要接触两次才行。
在传递一个数组的时候,数组的长度可以单独传递,也可以通过传递两个开头和结尾的指针来限制。
C++提供了三种形式来表示C风格的字符串,他们都是char *的类型,也就是说都是一个指针,里面存放了字符串的首地址。使用空字符来检测是否到了字符串的结尾处。