C++ Primer学习笔记(五)

-1.void func(para) 代表没返回值的函数

2.函数的返回数不可以是数组,可以是其他类型比如整型,浮点型,指针甚至是结构和对象

3.函数计算完成时将返回值放置在指定位置,有可能是在cpu寄存器有可能是在内存中,然后调用函数从这个位置获得返回值。

4.为什么要有函数原型:函数原型也叫函数声明,将函数的返回值和参数的类型和数量告诉编译器,即实现函数可以先被调用,后被实现。

5.在函数原型的参数列表中,只用包括类型就可以了,可以包括变量名,也可以不包括;原型中的变量名相当于占位符,因此不必与函数定义中的变量名相同。

6.假设cube的函数原型是 doube cube(dobule x),调用时double volume = cube(side);cube()使用的是side的副本,在cube函数修改形参不会对size进行改变;cube函数在执行时,side的值被传给cube函数,然后会创建一个 名为x的double变量,将传递的值赋给x。

7.函数中声明的变量是该函数私有的,函数被调用时分配内存,函数结束时内存被释放,这样的变量叫做局部变量。不同的函数的局部变量可以存在变量名一样的情况。

8.数组名被解释为数组的第一个元素的地址;对数组名使用sizeof得到是整个数组的长度,对元素sizeof得到的是元素的长度;将&运用于数组名时返回的是整个数组的地址。
将指针(包括数组名)+1,实际上加了一个与指针指向类型的长度相等的值

9.c++按值传递数据,使用普通参数时,函数使用的是数据的副本,而使用数组时,函数使用的是原始数据;可以用const保护数组不被修改,比如void show_array(const double ar[],int n);这种方式可以保护原始数组不被修改,但是并不意味着原始数组必须是常量。

10.c++中使用数组须获得数组的数据种类,数组的起始位置和数组元素数量,一般有两种方法:1.将数组起始处的指针作为一个参数,数组的长度作为另一个参数;2.指定元素区间:传递两个指针,一个标识数组的开头,另一个标识数组的尾部。

11.const 与指针:

int age = 39;
const int *pt = &age;
// pt的声明不意味着它指向的值实际上是一个常量,而只是意味着对于pt来说这个值时常量,即不能通过pt来更改这个值。
*pt = 20; //不被允许
age = 20;//被允许
---------------------------------------------------------------------------------
const float g_earth = 9.80;
const float *pe = &g_earth;//被允许

const float g_moon = 1.63;
float *pm = &g_moon;//不被允许
//对于第一种情况,既不能直接修改g_earth的值,也不能通过pe修改g_earth的值
//第二种情况c++是禁止的;c++禁止将const变量的地址赋给非const指针,如果非要这样做,可以用强制类型转换突破这个限制。
---------------------------------------------------------------------------------
//只有一级间接关系时,允许将非const指针赋给const指针
int age = 39;
int *pd = &age;
const int *pt = pd;

//有两级间接关系时,将不再允许将const和非const指针混合赋值的方式。
---------------------------------------------------------------------------------
// 可以将const数据和非const数据的地址赋给const指针,但是不能将const数据的地址赋给非const指针(因为这样违背了定义const指针的初衷)。
const int months[12] = {......}
int sum(int arr[],int n);
int j = sum(months,12)//不被允许,试图将const指针赋给非const指针。
----------------------------------------------------------------------------------
//常量指针可以防止通过指针来改变所指向的变量的值,但是不能防止改变指针的值。
int age = 39;
const int *pt = &age;
int sage = 80;
pt = &sage;//被允许

//可以声明指针常量使得无法修改指针的值。
int sloth = 3;
const int *ps = &sloth;  // 不允许通过ps修改sloth的值但是可以改变ps的值
int * const finger = &sloth;//finger 只能指向sloth,但是允许通过finger改变sloth的值

//还可以声明指向const对象的const指针
double trouble = 2.0E30;
const trouble *const stck = &trouble;//stick只能指向trouble,而且不能通过stick改变trouble的值

12.函数和二维数组:

int array[m][n];
int total = sum(array,m);

sum的原型可以是 int sum(int (*arr)[n],int m):array是一个数组名,它的第一个元素本身是一个个数为n,类型为整型的数组,所以data的类型是指向一个四个int类型组成的数组的指针。

sum的原型也可以是 int sum(int arr[][n],int m)

二维数组元素的表示方法:arr[r][c] == *(*(arr+r)+c)

13.函数和c风格字符串
要将字符串作为参数传递给函数,表示字符串的方式有三种:char数组,字符串字面值,char类型指针。在函数原型内,上面三种选择的都是char型指针。
字符串中有内置的结束字符’\0’,所以不必将数组长度传递给函数。
函数返回一个字符串,返回的是char*

14.函数和结构
结构将其数据组合成单个实体或数据对象,该实体被视为一个整体。结构变量的行为接近基本类型的变量。如果将结构作为参数传递是按值传递的,如果结构非常大,则会增加内存要求,降低系统运行速度,所以许多程序员倾向于传递结构的地址。

15.函数和array对象
c++中,类对象是基于结构的,所以结构的编程方面考虑的因素也适用于类。类也可以按值传递给函数,函数处理的是原始对象的副本;类也可以传递指向对象的指针,让函数可以操作原始对象。

std::array<double,4> expenses // 使用一个array储存一年四季的开支

void show(std::array<double,4> da);   // da an object
void fill(std::array<double,4>* pa);   // pa a pointer
show(expenses);  //按值传递
fill(&expenses);

16.函数指针
函数的地址是储存其机器语言代码的内存的开始地址。

要将函数作为参数进行传递,必须传递函数名。注意要区分传递的是函数的地址还是函数的返回值。

process(think);  	//传递函数地址
thought(think());	 //传递函数的返回值

声明函数指针时应指定函数的返回类型以及函数的特征标(参数列表)
提供正确的运算符优先级,正确的声明函数指针(括号的优先级要比*高)。

double pam(int);    //函数原型
double (*pf)(int);		//pf是一个指向参数列表为一个int,返回类型为double的函数的指针。
double *pf1(int);		// pf1是一个参数列表为一个int,返回类型为一个double指针的函数。
pf = pam; 	//可以将函数的地址赋给pf

函数指针在赋值时,需要和用来赋值的函数的特征标和返回类型相同,否则编译器将拒绝这种赋值。

double ned(dobule);
int ted(int);
double (*pf)(int);
pf = ned;		//编译失败,特征标不同。
pf = ted;		//编译失败,返回类型不同。

使用指针来调用函数,使用(*pf)时,将它看做函数名即可。

double pam(int);
double (*pf)(int);
pf = pam;
double x= pam(4);		//通过函数名调用函数
double y = (*pf)(5);		//通过指针调用函数
double z = pf(5);		//通过指针调用函数
// 也就是说 (*pf)(5) 等价于 pf(5)

深入探讨函数指针

const double *f1(const double ar[],int n)//在函数原型中, const double ar[] 与 const double *ar意义相同
const double *f3(const double *,int n)  // 参数列表里可以将形参参数名省略
const double *f2(const double [],int n)// 参数列表里可以将形参参数名省略


const double *(*p1)(const double *,int) = f1;//声明一个函数指针p1指向f1,const double * 指返回值类型
auto p2 = f2;	//将f2的值赋给p2
cout <<(*p1)(av,3)<<":"<<*(*p1)(av,3)<<endl; 	//先输出一个double值得地址(函数返回值),后输出一个double值
cout <<p2(av,3)<<":"<<*p2(av,3)<<endl;		//先输出一个double值得地址(函数返回值),后输出一个double值


// 运算符 [] 的优先级高于*
const double *(*pa[3])(const double *,int) = {f1,f2,f3}	//声明数组pa,元素数量有三个,元素是指向返回值为const double*的函数的指针。
auto pb = pa;	//声明一个和pa同类型的数组
const double *px = pa[0](av,3);	//获取指针数组中的元素
const double *py = (*pb[1])(av,3);	//获取指针数组中的元素
double x = *pa[0](av,3);	//通过*获取指针指向的值
double y = *(*py)(av,3);	//通过*获取指针指向的值
//可以创建一个指向数组pa的指针
auto pc =&pa;
const double *(*(*pd)[3])(const double,int) = &pa;
//pa(数组名)是数组第一个元素的地址,即&pa[0];&pa是整个数组的地址。pa和&pa的值相同,但类型不同,例如+1的意义不同。要获得第一个元素的值: *pa == pa[0] == **&pa

17.使用typedef对复杂的声明定义简单的别名

typedef const double *(*p_fun)(const double *,int); //将指向特征标为(const double *,int),返回值类型为 const double *的函数的指针的别名定义为 p_fun
p_fun p1 = f1; //将f1的地址赋给 p1
p_fun pa[3] = {f1,f2,f3}; // 定义一个指针数组,元素为3,指针指向p_fun类型的函数
p_fun (*pd)[3] = &pa; // 定义一个指向数组pa的指针
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值