C++启蒙笔记(4)---函数

本篇目录

  • 写在前面
  • 一、基本函数体
    • 1.模板
    • 2.特性
    • 3.内联函数
  • 二、函数与数组
    • 1.函数原型(main外)
    • 2.函数调用(main内)
    • 3.函数定义(main外)
  • 三、函数与字符串
  • 四、函数与结构
  • 五、函数与指针
    • 1.函数指针
    • 2. 数组与指针
    • 3. 函数指针数组

写在前面

  • 功能:函数作为编程的模块存在于所有编程语言中,可以调用库函数,也可以自己编写特定功能函数
  • 库函数:IDE已经定义和编译好的函数,源代码一般是不可见的,使用标准头文件提供其原型,只需正确调用即可

一、基本函数体

1.模板

示例:求两数乘积

#include 
using namespace std;
	
double cube(double x, double y);	// 函数原型:double cube为返回值类型,double x为形参(parameter)类型
/*************************************************************************************/
int main() 
{
	//....其他语句
	double a = b = 3.14;
	double side = cube(a, b);		// 函数调用:x,y为实参(argument),类型要与形参匹配,否则进行转换
	//...
}
/*************************************************************************************/
double cube(double x, double y)		// 函数定义:伴随特定功能的实现
{
	return x * y;					// return不可为数组
}

2.特性

  • 按值传参:方法调用时,传递的参数是实参值的拷贝(double x = a;double y = b;),传递后(x、y和a、b)就互不相关了,通过return语句将函数值带回到临时内存块中,主调函数从中取出数据,随后形参单元及函数体的内存被释放销毁
  • 返回值:return语句表明返回值,若函数无返回值,可省略return语句,若也无传入参数,函数原型为void cube();

3.内联函数

inline double square(double x) { return x * x}			// main外,声明(常规都是单语句),按值传递

double num = square( 3.14 );							// main内,调用(牺牲内存来提高调用速度)

二、函数与数组

1.函数原型(main外)

// 方法1
void arr(int * begin, int * end);				// 传入数组起始指针和结尾指针,在原数组上读写
void arr(const int * begin, const int * end);	// 同上,函数体不可修改数组的值
	
// 方法2
void arr(int * begin, int num);					// 传入数组起始指针和元素个数,在原数组上读写
void arr(const int * begin, int num);			// 同上,函数体不可修改数组的值

2.函数调用(main内)

int week = {1,3,5,7};
int * pweek = week;							// 数组的首地址:&week[4],数组首元素的地址week或&week[0]

// 方法1
arr(pweek, pweek+4);						// 也可以局部传入arr(pweek, pweek+2)

// 方法2
arr(pweek, 4);								// 也可以局部传入arr(pweek, 2)

3.函数定义(main外)

void arr(const int * begin, int num)
{
	for(int i = 0; i < num; i++)
	{
		cout << *(begin + i) << endl;			// 可以begin++,但不可(*begin)++,因为const
	}											// 因为直接操作数组,所以没有返回值
}

三、函数与字符串

  • 字符串:不以空‘\0’字符结尾的char数组只是数组,不是字符串
  • 示例(将字符串竖着输出)
    #include 
    using namespace std;
    void fun(const char * pt);					// 函数原型
    /*************************************************************************************/
    int main()
    {
    	const char * pchar = "this is a bird";	// 声明及定义字符串指针pchar
    	fun(pchar);								// 函数调用
    }
    /*************************************************************************************/
    void fun(const char * pt)					// 函数定义
    {
    	while(*pt)								// 功能:按字符扫描字符串,遇到尾部空字符退出
    	{
    		cout << *pt<< endl;
    		pt++;		
    	}
    }
    

四、函数与结构

  • 按地址传递(点坐标操作)
    #include 
    using namespace std;
    
    struct point									// 结构模板
    {
    	int x;
    	int y;
    };
    void fun(const point * pt_in, point * pt_out);	// 函数原型需要在结构模板之后
    /*************************************************************************************/
    int main()
    {
    	point pt_1 = { 3,4 };
    	point pt_2 = {};
    	fun(&pt_1, &pt_2);
    	cout << pt_2.x << endl;
    }
    /*************************************************************************************/
    void fun(const point * pt_in, point * pt_out)	// 此处传递的是结构指针,pt_in只读,pt_out修改的是实参
    {
    	cout << pt_in->x << endl;
    	pt_out->x = pt_in->x; 						// 把pt_in的x坐标给pt_out的x坐标
    }
    
  • 按值传递(返回结构)
    point pt_3 = fun(pt_1);							// 函数调用:这里就是对副本的操作了
    
    point fun(point pt_in)							// 函数定义:返回结构
    {
    	point total = {};
    	total.x = pt_in.x;
    	return total;
    }
    

五、函数与指针

个人总结:涉及到指针声明的同时赋值的语句,可以这样理解,例如int * pt = &x;等号左侧除指针pt外,其他所有都是在声明指针pt的数据类型,等号右侧是进行初始化的工作,即将&x的值放到指针pt里,若遇非同类型赋值,则会进行隐式转换或报错

1.函数指针

  • 函数指针:函数名同时也为这个函数的指针(类型为函数,存储函数入口地址),可用来调用函数和做函数的参数
  • typedef:创建类型别名typedef double real;
  • 用途:
    • 封装:函数指针可以放在结构体里,不同结构体里可包含相同的函数名不冲突
    • 动态:可以动态设置内容,有灵活性。如:排序中可根据需要传入比较的函数指针,来确定排序规则
  • 示例
    #include 
    using namespace std;
    
    typedef void (*pfun)(int);		// 相当于声明了一个数据类型(函数指针pfun),声明时可仅保留参数的类型
    void pf1(int x);				// 此处声明pf1,若无此句,则无法在主函数给pf2赋值
    /*************************************************************************************/
    int main()
    {
    	pfun pf2 = pf1;				// pf1和pf2都是函数指针,且函数的返回值和参数都要相同才可以这样赋值
    	
    	(*pf2)(3);					// 推荐:函数指针pf2等于pf1,(*pf2)为函数名,使用函数名调用
    	pf2(3);						// 功能同上,函数指针pf2等于pf1,pf1函数指针和函数名相同,故pf2也可直接调用函数
    }	
    /*************************************************************************************/
    void pf1(int x)
    {
    	cout << x << endl;
    }
    

2. 数组与指针

  • 常规数组及指针
    int a[3] = {1,3,5};
    int * pt1 = &a[0];				// 返回首个元素的首地址,sizeof(a[0])等于4
    int * pt2 = &a;					// 返回整个数组的首地址,sizeof(a)等于12
    
    cout << &a << endl;				// 输出0x7fff7aa19bfc,此为数组的首地址
    cout << a << endl;				// 输出0x7fff7aa19bfc,此为首元素的地址
    cout << *a << endl;				// 输出1,*解的是首元素的地址
    
    注:上式指针pt1内存储的地址等于pt2,但pt1中存储的类型为数组特定的元素,pt2中存储的类型为整个数组,从sizeof的结果可见
  • 数组指针:又名指向数组的指针
    C++启蒙笔记(4)---函数_第1张图片
    int a[3] = {1,3,5};
    
    int (*pt)[3];					// 优先级() > [] > *
    pt = &a;						// pt为指向含有三个整型元素的数组的指针
    // int (*pt)[3] = &a;等同于上面两句
    
    cout << a << endl;				// 输出:0x7fff7aa19bfc
    cout << *pt << endl;			// 输出:0x7fff7aa19bfc
    cout << **pt << endl;			// 输出:1
    
  • 指针数组:数组的每个元素的数据类型都是指针
    C++启蒙笔记(4)---函数_第2张图片
    int x = y = z = {};
    int * pt[3];					// 优先级() > [] > *,数组的每个元素数据类型由 int * 确定
    pt[0] = &x;						// x等于*pt[0]
    pt[1] = &y;
    pt[2] = &z;
    
    cout << pt[0] << endl;			// 输出:0x7fffb3b2ca5c
    cout << pt[1] << endl;			// 输出:0x7fffb3b2ca58
    cout << pt[2] << endl;			// 输出:0x7fffb3b2ca54
    

3. 函数指针数组

  • 功能:集成多个函数指针到一个数组里,用数组指针调用各个函数
  • 建议:以下会常用,建议背下来,函数功能没啥意义,关注写法
    #include 
    using namespace std;
    
    typedef double(*pfun)(int);			// pfun为函数的指针,此类函数特点为返回double,参数为一个int
    double f1(int x);
    double f2(int x);
    /*************************************************************************************/
    int main()
    {
    	// 数组parr存的元素都为pfun这种数据类型,两个位置存放parr[0] = f1,parr[1] = f2
    	pfun parr[2] = { f1,f2 };		
    	
    	// 对parr_1同时声明及初始化,声明parr_1为含有两个pfun类型元素的数组指针,&parr为数组的首地址,parr为首元素的地址
    	pfun (*parr_1)[2] = &parr;	// 将数组的首地址&parr赋值给parr_1,parr_1指向数组parr[2]的首地址(非首元素)
    		
    	parr[0](9);					// 输出f1,parr[0] = f1
    	(*parr_1)[0](9);			// 输出f1,*parr_1等于parr,依据:parr_1的定义赋值语句确定的
    	(**parr_1)(9);				// 输出f1,**parr_1等于(*parr_1)[0],依据:数组的定义确定的
    	
    	parr[1](9);					// 输出f2,parr[1] = f2
    	(*parr_1)[1](9);			// 输出f2,*parr_1等于parr
    	(*(*parr_1+ 1))(9);			// 输出f2,(*parr_1)[1]等于(*(*parr_1+ 1))
    	
    }
    /*************************************************************************************/
    double f1(int x)
    {
    	cout << "f1" << endl;
    	return 0;
    }
    
    double f2(int x)
    {
    	cout << "f2" << endl;
    	return 0;
    }
    
    上一篇:C++启蒙笔记(3)—指针
    下一篇:C++启蒙笔记(5)—函数进阶

你可能感兴趣的:(#,C++)