C++primer学习笔记之函数

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 *的类型,也就是说都是一个指针,里面存放了字符串的首地址。使用空字符来检测是否到了字符串的结尾处。

时间: 2024-12-28 20:43:58

C++primer学习笔记之函数的相关文章

c++ primer 学习笔记(2): 函数 function

类:简单来说就是数据和它的操作的一种封装,内部提供接口函数 1." 定义 "在类内部的函数是隐式inline的. 2.this 成员函数通过一个名为this的额外的隐式参数来访问调用它的那个对象.用请求该函数的对象的地址来初始化this. 仍何对类成员的访问都被看作this的隐式引用. [cpp] view plain copy std::string isbn( ) { return bookNo; } std::string isbn( ) { return this->bo

C++ Primer 学习笔记_34_面向对象编程(5)--虚函数与多态(二):纯虚函数、抽象类、虚析构函数、动态创建对象

C++ Primer 学习笔记_34_面向对象编程(5)--虚函数与多态(二):纯虚函数.抽象类.虚析构函数.动态创建对象 一.纯虚函数 1.虚函数是实现多态性的前提 需要在基类中定义共同的接口 接口要定义为虚函数 2.如果基类的接口没办法实现怎么办? 如形状类Shape 解决方法 将这些接口定义为纯虚函数 3.在基类中不能给出有意义的虚函数定义,这时可以把它声明成纯虚函数,把它的定义留给派生类来做 4.定义纯虚函数: class <类名> { virtual <类型> <函

C++ Primer 学习笔记33_面向对象编程(4)--虚函数与多态(一):多态、派生类重定义、虚函数的访问、 . 和-&gt;的区别、虚析构函数、object slicing与虚函数

C++ Primer学习笔记33_面向对象编程(4)--虚函数与多态(一):多态.派生类重定义.虚函数的访问. . 和->的区别.虚析构函数.object slicing与虚函数 一.多态 多态可以简单地概括为"一个接口,多种方法",前面讲过的重载就是一种简单的多态,一个函数名(调用接口)对应着几个不同的函数原型(方法). 更通俗的说,多态行是指同一个操作作用于不同的对象就会产生不同的响应.或者说,多态性是指发出同样的消息被不同类型的对象接收时有可能导致完全不同的行为. 多态行分

C++ Primer 学习笔记_24_类与数据抽象(10)--static 与单例模式、auto_ptr与单例模式、const成员函数、const 对象、mutable修饰符

C++ Primer 学习笔记_24_类与数据抽象(10)--static 与单例模式.auto_ptr与单例模式.const成员函数.const 对象.mutable修饰符 前言 [例]写出面向对象的五个基本原则? 解答:单一职责原则,开放封闭原则,依赖倒置原则,接口隔离原则和里氏替换原则 里氏替换原则:子类型必须能够替换他们的基类型. 设计模式分为三种类型:创建型模式.结构型模式和行为型模式 一.static 与单例模式 1.单例模式 单例模式的意图:保证一个类仅有一个实例,并提供一个访问它

C++ Primer 学习笔记_70_面向对象编程 --纯虚函数、容器与继承

面向对象编程 --纯虚函数.容器与继承 I.纯虚函数 在函数形参后面写上 =0 以指定纯虚函数: class Disc_item : public Item_base { public: double net_price(size_t) const = 0; //指定纯虚函数 }; 将函数定义为纯虚函数能够说明,该函数为后代类型提供了可以覆盖的接口,但是这个类的版本绝不会调用.重要的是,用户将不能创建Disc_item类型的对象. Disc_item discount; //Error Bulk

C++ Primer 学习笔记_26_操作符重载与转换(1)--可重载/不可重载的操作符、成员函数方式重载、友元函数方式重载

C++ Primer 学习笔记_26_操作符重载与转换(1)--可重载/不可重载的操作符.成员函数方式重载.友元函数方式重载 引言: 明智地使用操作符重载可以使类类型的使用像内置类型一样直观! 一.重载的操作符名 像任何其他函数一样,操作符重载函数有一个返回值和一个形参表.形参表必须具有操作符数目相同的形参.比如赋值时二元运算,所以该操作符函数有两个参数:第一个形参对应着左操作数,第二个形参对应右操作数. 大多数操作符可以定义为成员函数或非成员函数.当操作符为成员函数时,它的第一个操作数隐式绑定

C++ Primer 学习笔记_28_操作符重载与转换(3)--成员函数的重载、覆盖与隐藏、类型转换运算符、*运算符重载、-&gt;运算符重载

C++ Primer 学习笔记_28_操作符重载与转换(3)--成员函数的重载.覆盖与隐藏.类型转换运算符.*运算符重载.->运算符重载 一.成员函数的重载.覆盖与隐藏 对于类层次的同名成员函数来说,有三种关系:重载.覆盖和隐藏,理清3种关系,有助于写出高质量的代码. 1.成员函数的重载 重载的概念相对简单,只有在同一类定义中的同名成员函数才存在重载关系,主要特点时函数的参数类型和数目有所不同:但不能出现函数参数的个数和类型均相同,仅仅依靠返回值类型不同来区分的函数,这和普通函数的重载是完全一致

C++ Primer学习笔记(三) C++中函数是一种类型!!!

C++中函数是一种类型!C++中函数是一种类型!C++中函数是一种类型! 函数名就是变量!函数名就是变量!函数名就是变量! 重要的事情要说三遍... 接 C++ Primer学习笔记(二) 类的构造函数 与类同名,且无返回类型. 同类的成员函数一样,也可以在类中声明,在类外定义. 格式: 类名(): 成员1(成员1初始化值), 成员2(成员2初始化值) { } 以上,冒号至大括号中间的部分,称为构造函数的初始化列表,用于调用类成员的构造函数来初始化. 没有在初始化列表中显式指定初始化的成员,将会

C++ Primer 学习笔记_86_模板与泛型编程 --重载与函数模板

模板与泛型编程 --重载与函数模板 引言: 函数模板可以重载:可以定义有相同名字但参数数目或类型不同的多个函数模板,也可以定义与函数模板有相同名字的普通非模板函数. 但是,声明一组重载函数模板不保证可以成功调用它们,重载的函数模板可能会导致二义性. 一.函数匹配与函数模板 如果重载函数中既有普通函数又有函数模板,确定函数调用的步骤如下: 1.为这个函数名建立候选函数集合,包括: a.与被调用函数名字相同的任意普通函数. b.任意函数模板实例化,在其中,模板实参推断发现了与调用中所用函数实参相匹配