C++基础语法学习(五):函数

本文深入探讨C++中的函数定义、原型、调用过程,以及函数与数组、结构、string对象的交互方式。详细解析函数指针、内联函数和引用变量的使用技巧,为C++开发者提供全面的函数应用指南。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于C++primer plus(6th)

函数

使用函数有三步:

  1. 函数定义
  2. 函数原型
  3. 调用函数

函数定义

典型的函数定义如下:

type functionName (parameterlist){
	body;
	return data;
}

除了void函数没有返回值,其他函数都有返回语句。

  • 返回值类型应该与定义一致,或可强制转换类型。
  • 返回值可以是整数、浮点、指针及结构等,但是不能为数组

函数原型

原型描述了函数到编译器的接口,所以在main()函数之前需要进行原型的声明。
函数原型最简单的声明方法就是复制函数定义的函数头,但是函数原型只需要提供参数类型,不需要提供参数名(当然带着无妨,Ctrl+V更方便)。

函数参数

参数调用与定义均用,来分隔,即使参数类型一致也需要分别定义声明,函数定义的参数列表里即形参,函数调用时传入的变量等数据对象即实参。
函数中声明的变量是局部变量,函数调用时生成在函数里,调用结束即销毁。

函数与数组

大多数情况下C++将数组名视为指针,即将数组名解释为第一个元素的地址:array = &array[0],指针也可以用方框表达式去索引地址。因此还可以得到两个等式:

  1. arr[i] == *(ar + 1)
  2. &arr[i] == ar + 1

当然,只是视为指针,他们还有一些不同之处:

  • sizeof(数组名)得到整个数组的长度
  • &数组名,将得到整个数组的地址

数组用于参数调用

在函数定义中,数组的解释有一些新的变化:

  1. 在参数列表里,int arr[]int *poi等价,也就是说在参数列表里时,我们可以用指针代表数组,也可以直接使用数组名,代表传入一个数组的首元素地址,即指针指向的位置。
  2. 要注意,仅在函数头里可以等价使用,其他地方仍然不同于指针。

使用指针的优先级应当是最高的,毕竟数组拷贝与操作消耗资源更多,而使用指针访问地址更灵活高效。

数组其他操作

  • 数组显示:用数组名/指针+方框表示法。
  • 数组填充:因为参数调用时并没有创建数组副本,而只是传入数组地址,所以可以在函数里进行数组填充。

数组保护:为了保护数组元素,可以在形参声明处加入const,例如void show(const int arr[],int size)。但是要格外注意,const只是表示数组元素对指针是常量,也就是说不能通过指针来修改数组元素,但是我们可以不通过指针,直接对数组进行元素的修改,那是可行的。const只是保证不能通过指针修改数组。(有守门员就不能射门了么?天真)
那再想想,就是const指针可以指向常规变量和const变量,但是常规指针不能指向const变量。
当然,都是有转圜的余地的(待续)
这里再引入两种const的声明:

  • const int *arr这是const指针,表示不能通过指针修改指向地址数据对象的值,即不能通过指针修改数组元素等。
  • int* const arr表示指针地址为常量const,即不能修改指针指向的地址,但是可以通过指针修改指向位置元素的值。

  • 数组表示:除了上面’‘数组+长度’'的表示方式,我们还可以用两个指针表示区间。如(int* arr,int* arr+size)表示传入数组首地址和尾后一位地址(arr+size-1是数组最后一个元素地址)。

Tips:尽量使用const指针,避免函数调用可能对实参造成的数据篡改。

函数与结构

三种方式:

  1. 结构当作参数传递,会产生副本传入,所以如果结构过大资源消耗就会变多。
  2. 结构地址当作参数传入,要知道结构名只代表结构,和数组名不同,所以需要&来获得地址,用指针去取值。
  3. 引用变量。

第一种方式按值传递,传入结构。

polar rect_to_polar(rect xypos){
    polar answer;

    answer.distance =
        sqrt( xypos.x * xypos.x + xypos.y * xypos.y);
    answer.angle = atan2(xypos.y, xypos.x);
    return answer;      // returns a polar structure
}

第二种方式传入指针,参数定义为指针,也通过指针将函数处理返回结构。

void rect_to_polar(const rect * pxy, polar * pda){
    pda->distance =
        sqrt(pxy->x * pxy->x + pxy->y * pxy->y);
    pda->angle = atan2(pxy->y, pxy->x); 
}
rect_to_polar(&rplace, &pplace); //调用

函数与string对象

int main(){
    string list[SIZE];     // an array holding 5 string object
    cout << "Enter your " << SIZE << " favorite astronomical sights:\n";
    for (int i = 0; i < SIZE; i++){
        cout << i + 1 << ": ";
        getline(cin,list[i]);
    }
    cout << "Your list:\n";
    display(list, SIZE);
	return 0; 
}
void display(const string sa[], int n){
    for (int i = 0; i < n; i++)
        cout << i + 1 << ": " << sa[i] << endl;
}

关键就是声明一个string类型的数组,存放n个字符串。

函数指针

函数定义需要声明指针,那函数怎么作为指针呢

  • 获取函数地址,函数名即函数地址
  • 声明指针,只需要把待声明的函数名替换为(*pointer)即可

如:

double pam(int){
	body;}
double (*poi)(int)即函数指针
poi = pam	//赋地址

指针数组

const double* f1 (double ar[],int n);//函数原型
const double* (*poi1)(double [],int);//指针声明亦可初始化
auto poii = f1;//自动将poi声明为以上const double*指针
(*poi)(ar1,4);poii(ar1,4);//此时这两个函数调用等效,返回类型均为地址,如果需要获得函数返回值,则*(*poi)(ar1,4);
const double* (*poi[3])(double [],int)={f1,f2,f3};//包含三个指针的数组
//即三个指针,均指向需要double*和int参数且返回double*的几个函数,若要调用其中的函数,例如:
const double* px1 = poi[2](ar1,4);//此时px1即为调用ar1函数的指针


内联函数

函数调用两种方法:函数调用时跳转地址且参数入heap,调用完跳回原指令地址;内联函数直接复制副本,不执行地址跳转(亦按值传递,与常规函数无二)。
显然因为有复制副本的操作,所以一般只把代码量很小的函数作内联,且通常省略原型直接把函数定义在头部。

内联函数不能递归

实例:

inline double squa(double x){return x*x;}

引用变量

C++用&来声明引用,注意在声明的时候&不作为地址运算符,其他时候才是地址运算。
声明引用变量后,变量及它的引用变量指向同样的地址及值,即一个变量有两个名字。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值