(一)定义:
C语言函数是一种函数,用来编译C语言,一般包括字符库函数,数学函数,目录函数,进程函数,诊断函数,操作函数等。一个固定的程序段,可供重复使用。
语法形式:
函数返回值类型 函数名(含类型说明的形式参数表)
{
语句;
……
}
①形式参数(简称形参):type name;type1 name1;……typen namen;//其中type ,type1……typen为类型标识符,表示形参类型。name ,name1……namen是形参名;如果一个函数的形参表为空,则表示它没有任何形参,通常main 函数都没有形参。main 函数也可以有形参,其形参也称命令行参圆,由操作系统在启动程序时初始化。不过命令行参数的数量和类型有特殊要求。函数在没有被调用时是静止的,此时的形参只是一个符号,它标志着在形参出现的位置应该有一个什么类型的数据。函数在被调用时才执行,也是在被调用时才由主调函数将实际参数(简称实参)赋予形参。
参数是有具体含义的,通常代表当前这个函数的功能需要具备的参数。
②函数返回值和返回值类型
函数可以有一个返回值,函数的返回值是需要返回给主调函数的处理结果。类型说明
符规定了函数返回值的类型。函数的返回值由return语句给出,格式如下,
return 表达式;
除了指定函数的返回值外,return 语句还有一个作用,就是结束当前函数的执行。例如,主函数main的返回值类型是int,主函数中的return0语句用来将0作为返回值,并且结束main函数的执行。main函数的返回值最终传递给操作系统。
一个函数也可以不将任何值返回给主调函数,这时它的返回值标识符为void可以不写return语句,但也可以写一个不带表达式的return语句,用于结束当前函数的调用,格式如下:return ;
(二)函数的调用
变量在使用之前需要首先声明,类似地,函数在调用之前也需要声明。函数声明的形式如下:
类型说明符 函数名(含类型说明的形式参数表) ;
函数参数:
//形参--->创建函数时用的参数(类型修饰的)
//实参--->调用函数时用的参数(没有类型修饰)
所有传参方式都是赋值方式
注意:声明函数时,形参表只要包含完整的类型信息,形参名可以省略;即原型声明的形参表可按下面格式书写:type,type1……typen
声明函数原型之后,可使用函数名(实参列表)调用子函数;
注意: 函数调用的时候,形参和实参类型必须一致;不一致会存在强制类型转换 ,如果转换不了程序直接崩掉
实参列表中应给出与函数原型形参个数相同、类型相符的实参,每个实参都是一个表达式,函数调用可以作为一条语句,这时函数可以没有返回值。函数调用也可以出现在表达式中,这时就必须有一个明确的返回值。
调用一个函数时,首先计算函数的实参列表中各个表达式的值,然后主调函数暂停执行,开始执行被调函数,被调函数中形参的初值就是主调函数中实参表达式的求值结果。当被调函数执行到return语句,或执行到函数末尾时,被调函数执行完毕,继续执行主调函数。
嵌套调用:函数允许嵌套调用。函数的调用可以通过用一个函数调用另一个函数来实现,这就形成了函数的嵌套调用。例子:求平方和
#include <stdio.h>
//求和
int HE(int a, int b)
{
return a + b;
}
//求平方
int PFang(int a)
{
return a * a;
}
int main() {
printf("%d", HE(PFang(3), PFang(4)));
return 0;
}
递归调用:函数可以直接或间接地调用自身,称为递归调用。
所谓直接调用自身,就是指在一个函数的函数体中出现了对自身的调用表达式,例如:
#include <stdio.h>
//求阶乘
int NN(int n){
if (n == 0 || n == 1)
return 1;
else return n * NN(n - 1);
}
int main()
{
printf("%d",NN(3));
return 0;
}
(三)函数参数传递
在函数未被调用时,函数的形参并不占有实际的内存空间,也没有实际的值。只有在函数被调用时才为形参分配存储单元,并将实参与形参结合。每个实参都是一个表达式,其类型必须与形参相符。函数的参数传递指的就是形参与实参结合(简称形实结合)的过程,形实结合的方式有值传递和引用传递。
函数参数一定要有意义,自己十分清楚参数的意义,如解释不了就别写。
注意
数组传参的特殊性:
数字类数组当做函数参数时,一定要传入输入长度。
二维数组传参列数不能缺省。
字符串当做函数参数,可以不需传入长度,因为字符串具有字符串结束标记'\0'
#include <stdio.h> //遍历操作 一维数组,需要传入数组长度; void Print(int c[], int d) //等价于void Print(int *c;int d) { for (int i = 0; i < d; i++) { printf("%d ", c[i]); } printf("\n"); } //遍历操作 二维数组,列数不能省 void Print1(int c[][3], int rol,int col)//等价于void Print1(int (*c)[3];int rol;int col) { for (int i = 0; i < rol; i++) { for (int k = 0; k < col; k++) { printf("%d ", c[i][k]); } printf("\n"); } } //字符数组 求数组长度 int my_strlen(char* str) { int cout=0; while (str[cout] != '\0') { cout++; } //while (*str != '\0') //{ // str++; // cout++; //两者等价} return cout; } int main() { //一维数字数组 int a[5] = { 1,2,3,4,5 }; //二维数组 int b[2][3] = { 2,3,4,5,6,7 }; Print(a, 5); Print1(b, 2, 3); char c[] = "ImissYou"; printf("%d", my_strlen(c)); return 0;
①值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。单向传递,形参值的改变对实参不起作用。
②地址传递:如果函数想要修改普通变量实参的值,需要传入地址,在函数修改的是指针。如果函数想要修改指针变量实参的值,需要传入该指针地址(二级指针),在函数修改的是指针。
③引用传递:所谓引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
注意:
声明一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象。
一旦一个引用被初始化后,就不能改为指向其他对象
#include <iostream>
using namespace std;
//交换两值
//1.值传递
void swap(int a, int b)
{
int c = a;
a = b;
b = c;
printf("%d %d\n", a, b);
}
//2.引用传递 C++才有引用
void swap1(int& a, int& b)
{
int c = a;
a = b;
b = c;
printf("%d %d\n", a, b);
}
int main()
{
int a = 9;
int b = 13;
printf("%d %d \n", a, b);
printf("值传递\n");
swap(a, b);
printf("%d %d \n", a, b);
printf("引用传递\n");
swap1(a, b);
printf("%d %d \n", a, b);
return 0;
}