【C语言】函数知识总结(1)

引言

模块化的程序设计方法通常是将比较复杂的问题分解为若干个相对简单的子问题,然后分别求解,以降低解决问题的复杂度。如果已有解决某个子问题的代码,就可以直接使用这些代码,也就是函数。一个C语言程序由一个或多个程序模块组成,每一个程序模块由一个或多个函数组成,所以函数是实现模块化程序设计不可缺少的重要机制。

一、函数概述


  • 函数本质:一段可以被重复调用的、功能相对独立的程序段
  • 函数的引入目的:
    1.便于结构化、模块化编程
    2.解决代码的重复

函数调用
当一个C语言程序的规模较大时,可以由多个源文件组成,但其中只有一个源文件含有主函数main(),而其他源文件不能含有主函数。主函数可以调用其他函数,但是相反则不行。其它函数之间可以互相调用,同一个函数可以被一个或多个函数调用任意多次。一个函数调用另一个函数,前者称为调用函数,后者称为被调函数。
  • 函数分类:
    函数分类

二、函数定义

1. 无参函数的定义

类型名 函数名()
{
函数体
}

类型名 函数名(void)
{
函数体
}


  • 类型名指定函数返回值的类型,省略时,默认函数返回值的类型为int,void 表示函数没有参数
  • 函数体包含声明部分和语句部分(可以只有其中一部分,也可以都没有)
  • 声明部分主要是变量的声明或所调用的函数的声明
  • 执行部分有执行语句组成,函数的功能由这些语句实现

2.有参函数的定义

类型名 函数名(形式参数表列)
{
函数体
}
形式参数表列格式:类型1 形参1,类型2 形参2,…,类型n 形参n


#include<stdio.h>
#include<math.h>
double fact(int n);//函数声明
int main()
{
    
    
	int i = 1;
	double x, item, s = 0;
	printf("输入x的值:");
	scanf("%lf", &x);//由键盘读入浮点数x的值
	item = x;
	while (fabs(item) >= 0.00001)
	{
    
    
		s = s + item;//累加一项
		i++;//累计次数
		item = pow(x, i) / fact(i);//调用函数,fact()函数中i为实参
	}
	printf("和是:%lf\n", s);
	return 0;
}
double fact(int n)//函数首部 n为形参
{
    
    
	int i;
	double jc = 1;//阶乘变量赋初值
	for (i = 1; i < n; i++)//计算阶乘
		jc = jc * i;
	return jc;//返回阶乘
}

3.空函数的定义

类型名 函数名()
{ }


  • 用来声明函数,该函数可以是需日后完善的函数
  • 目的是程序的结构清晰,可读性好,以后扩充功能方便

三、函数调用


定义函数的目的就是为了重复使用,因此只有在程序中调用函数才能实现函数的功能


1.函数调用的形式和过程

(1)函数调用的一般形式

函数名(实际参数表列)

  • 实际参数表列,即实际参数,简称实参。可以是常数、变量、表达式
#include <stdio.h>

// 定义一个函数,它有三个形式参数
void print_values(int a, float b, char c) {
    
    
    printf("The values are: %d, %f, %c\n", a, b, c);
}

int main() {
    
    
    int x = 3;
    float y = 3.14;
    char z = 'A';

    // 调用函数print_values(),传递常数、变量和表达式作为实参
    print_values(1, y, 'B');
    print_values(x, 2.5, z);
    print_values(x + 1, y * 2, z + 1);

    return 0;
}

  • 各实参之间用逗号隔开
  • 实参的个数、类型应与函数形参的个数、类型一致
  • 若为无参函数,则无实际参数表列,但括号不能省略

(2)函数调用的方式

Ⅰ.函数语句
把函数调用作为一条语句
一般形式:函数名(实参表列);
这种方式常用于调用一个没有返回值的函数,只要求函数完成一定的操作
Ⅱ.函数表达式
函数调用作为表达式中的一部分出现在表达式中,
以函数返回值参与表达式的运算
Ⅲ.函数嵌套使用

C语言程序从main函数开始执行,而自定义函数的执行是通过对自定义函数的调用来实现的。当自定义函数结束时,从自定义函数结束的位置返回到主函数中的调用处继续执行,直到主函数结束。

函数嵌套调用

C语言的函数定义是互相平行、独立的,也就是说,在定义函数时,
一个函数内不能再定义另一个函数,也就是不能嵌套定义,
但可以嵌套调用函数

(3)函数调用的过程

  • 1.为被调函数的所有形参分配内存,再计算实参的值,并一一对应地赋予相应的形参(对于无参函数,不做该项工作)
  • 2.为函数说明部分中定义的变量分配存储空间,再依次执行函数的可执行语句。当执行到“return(表达式);”语句时,计算返回值(如果是无返回值的函数,不做该项工作)。
  • 3.释放在本函数中定义的变量所占用的存储空间(对于static类型的变量,其空间不会释放),返回主调函数继续执行

2.参数传递


  • 在调用有参函数时,调用函数与被调用函数之间存在数据传递的关系
  • 调用函数向被调用函数传递数据主要是通过函数的参数进行的
  • 被调用函数向调用函数传递数据一般是通过return语句实现的
  • 形参是函数定义时函数名后括号中的变量
  • 实参是指调用函数时函数名后括号中的常量、变量、表达式
  • 在调用函数时,将实参的值传递给形参,使形参在数值上和实参相同
  • 两种参数传递数据方式:按值传递和按地址传递

(1)按值传递


  • 函数调用时,调用函数把实参的值传递给被调用函数的形参,形参值的变化不会影响实参的值,这是一种单向的数据传送方式
  • 当实参是变量、常量、表达式、数组元素或函数时,函数传递数据采用的式按值传递

#include <stdio.h>
void swap(int x, int y)
{
    
    
    int t;
    t = x; x = y; y = t;
    printf("x=%d,y=%d\n", x, y);
}
int main() 
{
    
    
    int a, b;
    scanf("%d,%d", &a, &b);
    swap(a, b);
    printf("a=%d,b=%d\n", a, b);
    return 0;
}

结果:
在这里插入图片描述


  • 实参的个数、数据类型应与形参一致,否则将会出现编译错误
  • 定义函数时,系统并不给形参分配存储单元,只有函数被调用时系统才给形参分配存储单元。在调用结束后,形参所占用的存储单元被释放
  • 实参与形参即使同名,也会分配不同的存储单元
  • 参数传递是“值传递”时,属于单向传递,即实参把值传给形参,但形参的值不能传实参,也就是说对形参的修改不会影响对应的实参。这是由于在内存中,实参与形参是的存储单元,函数执行结束后,形参的存储单元被释放

(2)按地址传递


当函数的形参为数组或指针类型时,函数调用的参数传递称为按地址传递。由于传递的是地址,使形参与实参共享相同的存储单元,这样通过形参可以直接引用或处理该地址中的数据,达到改变实参值的目的


3.函数的返回值

1.函数的值只能通过return语句返回给调用函数

return 表达式;
return (表达式);//如 a>b?:a:b

在函数中允许有多个return语句,但每次调用逻辑上只能有一个return语句被执行。
2.如果不需要从被调用函数返回函数值,可以省略return语句。这时,执行函数体中的最后一条语句后,自动跳出被调用函数,而且返回不确定的值
3.return语句中表达式的值的类型应与函数定义中函数的类型保持一致

4.函数声明

1.先声明后使用
(1)调用库函数时,一般需要在程序的开头用“#include”命令
(2)调用用户自己定义的函数时,函数声明格式:

类型名 函数名(参数类型1,参数类型2...);
类型名 函数名(参数类型1 形参1,参数类型2 形参2,...);

2.当满足下面两种情况之一时,在主调函数中可以不对被调函数进行声明

  • 被调函数定义在主调函数之前时
  • 被调函数的返回值类型是整型或字符型时

5.函数的嵌套调用

C语言的函数定义都是互相平行、独立的。也就是说,在定义函数时,一个函数内不能包含另一个函数的定义。如果在一个函数中再调用其他函数,则称为函数的嵌套调用。也就是说,在被调用函数的过程中,又可以调用另一个函数。

猜你喜欢

转载自blog.csdn.net/m0_74102736/article/details/130446639