函数

函数最初主要用于计算数学中的公式,现在用于编写功能模块;

对功能模块划分,遇到功能复杂的,可以进行分解,把一个复杂任务分解成一些子任务,分别实现,这使得程序的编写和维护更加方便;

函数基础

函数定义是函数体的实现,函数体是一个代码块,它在函数被调用是执行。

与函数定义相反,函数声明出现在函数被调用的地方

函数声明想编译器提供该函数的相关信息,用于确保函数被正确调用;

函数定义语法

返回类型 函数名(变元说明表){

            说明序列和语句序列

}
最简单函数结构

dummy(){}

该结构用作开发程序期间占位符;函数定义中省略了返回类型,则缺省为int

程序是变量和函数定义的集合

函数之前通信是通过变元、函数返回值以及外部变量进行

返回值

  • return 语句用于被调用函数想调用者返回值,return之后可以跟任何表达式
  • return 表达式;
  • 在必要是要把表达式转换成函数的返回类型(结果类型)

函数分类

C 程序是由函数组成的,我们写的代码都是由主函数 main()开始执行的。函数是 C 程序的基本模块,是用于完成特定任务的程序代码单元。

从函数定义的角度看,函数可分为系统函数和用户定义函数两种:

  1. 系统函数,即库函数:这是由编译系统提供的,用户不必自己定义这些函数,可以直接使用它们,如我们常用的打印函数printf()。
  2. 用户定义函数:用以解决用户的专门需要。

函数的作用

  1. 函数的使用可以省去重复代码的编写,降低代码重复率
  2. 函数可以让程序更加模块化,从而有利于程序的阅读,修改和完善
#include <stdio.h>

int main()
{
	float list[50];

	// 这里只是举例,函数还没有实现
	max(list, 50);
	average(list, 50);
	sort(list, 50);

	return 0;
}

函数的定义

函数定义的一般形式:

	返回类型 函数名(形式参数列表)
	{
		数据定义部分;
		执行语句部分;
    }

 

函数名字、形参、函数体、返回值

函数名

    约定俗成函数为见名知意,且后面跟圆换号()

形参

   在定义函数时指定的形参,在未出现函数调用时,它们并不占内存中的存储单元,因此称它们是形式参数或虚拟参数,简称形参,表示它们并不是实际存在的数据,所以,形参里的变量不能赋值。

void compare(int a=1, int b =2)  //erro:形参不能赋值
{
}

在定义函数时指定的形参,必须是,类型+变量的形式:

// 正确:类型+变量
void compare(int a, int b)  
{
}
//错误:缺少变量
void compare(int , int b)  
{
}
//错误:缺少类型
void compare(a , int b)  
{
}

  在定义函数时指定的形参,可有可无,根据函数的需要来设计,如果没有形参,圆括号内容为空,或写一个void关键字

// 没形参, 圆括号内容为空
void compare()
{
}

// 没形参, 圆括号内容为void关键字
void compare(void)
{
}

函数体

花括号{ }里的内容即为函数体的内容,这里为函数功能实现的过程,这和以前的写代码没太大区别,以前我们把代码写在main()函数里,现在只是把这些写到别的函数里。

返回值

   函数的返回值是通过函数中的return语句获得的,return后面的值也可以是一个表达式。

return 表达式;

在必要是要把表达式转换成函数的返回类型(结果类型),尽量保证return语句中表达式的值和函数返回类型是

int example(){   // 函数的返回值为int类型
    int a = 1;
    return a;   返回值a为int类型,函数返回类型也是int,匹配
}

   如果函数返回的类型和return语句中表达式的值不一致,则以函数返回类型为准,即函数返回类型决定返回值的类型。对数值型数据,可以自动进行类型转换。

double example(){   // 函数的返回值为double 类型
    int a = 1;
    return a;   返回值a为int类型,它会转为double 类型在返回 
}

注意:如果函数返回的类型和return语句中表达式的值不一致,而它又无法自动进行类型转换,程序则会报错。

   return语句的另一个作用为中断return所在的执行函数,类似于break中断循环、switch语句一样。

int compare()
{
	return 1;// 执行到,函数已经被中断,所以下面的return 2无法被执行到
	return 2;// 没有执行
}

   如果函数带返回值,return后面必须跟着一个值,如果函数没有返回值,函数名字的前面必须写一个void关键字,这时候,我们写代码时也可以通过return中断函数(也可以不用),只是这时,return后面不带内容( 分号“;”除外)

void compare()// 最好要有void关键字
{
	return; // 中断函数,这个可有可无
}

函数的调用

    定义函数后,我们需要调用此函数才能执行到这个函数里的代码段。这和main()函数不一样,main()为编译器设定好自动调用的主函数,无需人为调用,我们都是在main()函数里调用别的函数,一个 C 程序里有且只有一个main()函数

函数执行流程

#include <stdio.h>

void print_test()
{
	printf("this is for test\n");
}

int main()
{
	print_test();	// print_test函数的调用

	return 0;
}

1)进入main()函数

2)调用print_test()函数:

它(指的谁?编译器?)会在main()函数前寻找print_test()函数定义;

若找到,接着检查函数的参数,这里调用函数时没有传参,函数定义也没形参,参数类型匹配?;

开始执行print_test()函数,main()函数里面的执行会阻塞(停)在print_test()这一行代码,等待print_test()函数的执行

3)print_test()函数执行完,main()才会继续往下执行,执行到return 0, 程序执行完毕。

函数的形参和实参

1)形参在函数中定义,整个函数内都能使用,离开该函数则不能使用

2)实参出现在主调函数中,进入被调函数后,实参不能使用

3)实参变量对形参变量的数据传递是“值传递”,即单向传递只由实参传给形参,而不能由形参传回来给实参

4)在调用函数时,编译系统临时给形参分配存储单元。调用结束后,形参被释放

5)实参单元与形参单元是不同的单元。调用结束后,形参单元被释放,函数调用结束后返回主函数偶则不能在使用该形参变量。实参单元仍保留并维持原值。因此,在执行一个被调用函数时,形参的值如果发生改变,并不会改变主调函数中实参的值

#include <stdio.h>

void f(int q) //形参q
{
	 q=10;
	 //return 0;
}

int main(void)
{
	int i=1;  //实参 i
	f(i);  //调用函数
   printf("i=%d\n",i);// i=1 值没有改变
	return 0;
	
}
i=1

注:实参可以为常量、变量或表达式,在进行函数调用时,它们必须是确定的值,以便把该传送给形参。

函数返回值

1)如果函数定义没有返回值,函数调用时不能写void关键字,调用函数时也不能接收函数的返回值。

// 函数的定义
void test()
{
}

int main()
{
	// 函数的调用
	test(); // right
	void test(); // error, void关键字只能出现在定义,不可能出现在调用的地方
	int a = test();	// error, 函数定义根本就没有返回值

	return 0;
}

2)如果函数定义有返回值,这个返回值我们根据用户需要可用可不用,但是,假如我们需要使用这个函数返回值,我们需要定义一个匹配类型的变量来接收。

// 函数的定义, 返回值为int类型
int test()
{
}

int main()
{
	// 函数的调用
	int a = test(); // right, a为int类型
	int b;
	b = test();	// right, 和上面等级

	char *p = test(); // 虽然调用成功没有意义, p为char *, 函数返回值为int, 类型不匹配

	// error, 必须定义一个匹配类型的变量来接收返回值
	// int只是类型,没有定义变量
	int = test();	
	
	// error, 必须定义一个匹配类型的变量来接收返回值
	// int只是类型,没有定义变量
	int test();
	
	return 0;
}

函数声明

用户自定义函数与调用它的函数(主函数)不在同一文件中,或者用户定义函数位置在主调函数之后,则必须在此函数之前对被调用的函数作声明

函数声明:在函数尚未定义的情况下,事先将该函数的有关信息通知编译系统,相当于告诉编译器,函数在后面定义,以便编译能正常进行。

注意:一个函数只能被定义一次,但可以声明多次

#include<stdio.h>

int compare(int x, int y); //函数声明,分号不能省略

int main(){
	int a=1,b=2,c;
	c = compare(a,b); //函数调用 
	printf("max: %d\n", c); 
	return 0;
} 

int compare(int x, int y){
	return x>y?x:y;
}

函数定义与声明区别

1)定义指对函数功能的确立,是一个独立完整的函数单元

2)声明作用通知编译系统,在对函数调用语句进行编译时,对被调用函数进行对照检查(如,函数名,实参与形参的类型和个数是否一致)

带默认参数值的函数

函数在定义时可预先声明默认的形参值,调用时,若给出实参,则用实参初始化形参,若无实参,则采用声明的默认值;

有默认值的形参必须在形参列表的最后,即在有默认值的形参右面,不能出现无默认值的形参,因为函数调用时,实参与形参是按从左向右的顺序建立对应关系的。

int func(int x=10,int y=20);
int func2(int x,int y =10);
int func3(int x =10,int y);//错误

在相同作用域内,不允许在同一个函数的多个声明中对同一个参数的默认值重复定义,即使前后定义的值相同也不行;

main函数与exit函数

  在main函数中调用return和exit结果是一样的,但在子函数中调用return只是代表了函数终止;在子函数中调用exit,程序终止

多文件(份文件)编程

1)分文件编

  把函数声明放在头文件xxx.h中,在主函数中包含相应头文件

  在头文件对应的xxx.c中实现xxx.h声明函数

2)防止头文件重复包含

当一个项目比较大时,往往都是份文件,值得注意不能把同一个头文件include多次,或者头文件嵌套包含

a.h中包含b.h

#include<b.h>

b.h中包含a.h

#include<a.h>

main.c中使用其头文件:

#include<a.h>
#include<b.h>  # 头文件多次包含

int main(){
    

    retrun 0;

}

编译报错

为了避免同一文件被include多次,C/C++中有两种方式,一种是#ifndef,另一种是pragma once

#ifndef __SOMEFILE_H__
#define __SOMEFILE_H__

//声明语句

#endif
#pragma once

//声明语句

练习

编写一个函数strrindex(s,t),用于返回字符串t在s中最右出现的位置,如果s中不含t,那么返回-1。

注:内容参考传智播客讲义,侵 联系删

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值