C语言第四章函数
前言
结合千峰教育和菜鸟教程自用
- 千峰教育
转载千峰教育C语言第四章函数 - 菜鸟教程
转载菜鸟教程C语言-c函数
第 4 章 函数
4.1 函数的概念
0. 菜鸟教程中的解释
- 菜鸟总结
语句;至少有一个主函数 main();划分;任务;声明;定义;内置函数;很多叫法!
- 函数是 c 语言的功能单位,实现一个功能可以封装一个函数来实现。
定义函数的时候一切以功能为目的,根据功能去定函数的参数和返回值。 - 总结:功能单位;封装;参数和返回值。
4.2 函数的分类
- 从定义角度分类(即函数是谁实现的)
- a.库函数 (c 库实现的)
- b.自定义函数 (程序员自己实现的函数)
- c.系统调用 (操作系统实现的函数)
- 从参数角度分类
- a.有参函数
- 函数有形参,可以是一个,或者多个,参数的类型随便
完全取决于函数的功能
int fun(int a,float b,double c)
{
}
int max(int x,int y)
{
}
- 函数有形参,可以是一个,或者多个,参数的类型随便
- b.无参函数
- 函数没有参数,在形参列表的位置写个 void 或什么都不写
int fun(void)
{
}
int fun()
{
}
- 函数没有参数,在形参列表的位置写个 void 或什么都不写
- 从返回值角度分类
- a.带返回值的函数
- 在定义函数的时候,必须带着返回值类型,在函数体里,必须有 return
如果没有返回值类型,默认返回整型
- 在定义函数的时候,必须带着返回值类型,在函数体里,必须有 return
例 1:
char fun()//定义了一个返回字符数据的函数
{
char b='a';
return b;
}
例 2:
fun()
{
return 1;
}
如果把函数的返回值类型省略了,默认返回整型
注:在定义函数的时候,函数的返回值类型,到底是什么类型的,取决于函数的功能。
- b.没返回值的函数
- 在定义函数的时候,函数名字前面加 void
void fun(形参表)
{
;
;
return ;
;
}
在函数里不需要 return
如果想结束函数,返回到被调用的地方, return ;什么都不返回就可以了
- 在定义函数的时候,函数名字前面加 void
例 3:
#include <stdio.h>
int max(int x,int y)
{
int z;
if(x>y)
z=x;
else
z=y;
return z;
}
void help(void)
{
printf("*********************\n");
printf("********帮助信息*****\n");
printf("*********************\n");
}
int main(int argc, char *argv[])
{
int num;
help();
num = max(10,10+5);
printf("num=%d\n",num);
return 0;
}
运行结果如下:
4. 总结
函数的分类有三种:从定义角度分类;从参数角度分类;从返回值角度分类。
4.3 函数的定义
0.菜鸟教程中的解释
- 菜鸟总结
在 C 语言中,函数由一个函数头和一个函数主体组成。
什么叫做函数的定义呢?即函数的实现
- 函数的定义方法
- 返回值类型 函数名字(形参列表)
{//函数体,函数的功能在函数体里实现
}
- 返回值类型 函数名字(形参列表)
例 4:
int max(int x, int y)
{
int z;
if(x>y)
z=x;
else
z=y;
return z;
}
注:形参必须带类型,而且以逗号分隔
函数的定义不能嵌套,即不能在一个函数体内定义另外一个函数,所有的函数的定义是平行的。
例 5:
void fun(void)
{
;
;
;
void fun2(void)
{
;
}
}
这个程序是错误的,不能再 fun 的函数体中,定义 fun2 函数。
例 6:
void fun(void)
{
;
;
;
}
void fun2(void)
{
;
}
这个程序是正确的,fun 和 fun2 是平行结构
注:在一个程序中,函数只能定义一次
给函数起名字的时候,尽量的见名知意,符合 c 语言的命名 规则
2. 总结
要注意函数的定义方法,函数的定义不能嵌套,函数的定义是平行的,给函数起名字时候要做到见名之意!
4.4 函数的声明
0.菜鸟教程中的解释
- 菜鸟总结
函数声明会告诉编译器函数名称及如何调用函数。函数的实际主体可以单独定义。
- 概念
- 对已经定义的函数,进行说明
函数的声明可以声明多次。
- 对已经定义的函数,进行说明
- 为什么要声明
- 有些情况下,如果不对函数进行声明,编译器在编译的时候,可能不认识这个函数,
因为编译器在编译 c 程序的时候,从上往下编译的。
- 有些情况下,如果不对函数进行声明,编译器在编译的时候,可能不认识这个函数,
- 声明的方法
- 什么时候需要声明
- (1) 主调函数和被调函数在同一个.c 文件中的时候
a.被调函数在上,主调函数在下
- (1) 主调函数和被调函数在同一个.c 文件中的时候
- 什么时候需要声明
例 7:
void fun(void)
{
printf("hello world\n");
}
int main()
{
fun();
}
这种情况下不需要声明
b. 被调函数在下,主调函数在上
例 8:
int main()
{
fun();
}
void fun(void)
{
printf("hello world\n");
}
编译器从上往下编译,在 main 函数(主调函数),不认识 fun,需要声明
- 怎么声明呢?
- a. 直接声明法
将被调用的函数的第一行拷贝过去,后面加分号
- a. 直接声明法
例 9:
void fun(void);
int main()
{
fun();
}
void fun(void)
{
printf("hello world\n");
}
b. 间接声明法
将函数的声明放在头文件中,.c 程序包含头文件即可
例 10:
a.c
#include”a.h”
int main()
{
fun();
}
void fun(void)
{
printf("hello world\n");
}
a.h
extern void fun(void);
- (2) 主调函数和被调函数不在同一个.c 文件中的时候
- 一定要声明
声明的方法:- a.直接声明法
将被调用的函数的第一行拷贝过去,后面加分号,前面加 extern - b.间接声明法
将函数的声明放在头文件中,.c 程序包含头文件即可
- a.直接声明法
- 一定要声明
- 总结
声明可以多次!
情况一:被调函数在上,主调函数在下不用声明;
情况二:被调函数在下,主调函数在上需要声明;
(1).主调函数和被调函数在同一个.c 文件中的时候
直接声明法:将被调用的函数的第一行拷贝过去,后面加分号;
间接声明法:将函数的声明放在头文件中,.c 程序包含头文件即可!
(1).主调函数和被调函数不在同一个.c 文件中的时候
直接声明法:将被调用的函数的第一行拷贝过去,后面加分号,前面加 extern;
间接声明法:将函数的声明放在头文件中,.c 程序包含头文件即可!
4.5 函数的调用
0.菜鸟教程中的解释
-
菜鸟总结
创建 C 函数时,会定义函数做什么,然后通过调用函数来完成已定义的任务。
C 传值方式调用函数
菜鸟教程中的C 传值方式调用函数
C 引用方式调用函数
[菜鸟教程中的C 引用方式调用函数 -
函数的调用方法
- 变量= 函数名(实参列表);//带返回值的
函数名(实参列表);//不带返回值的
- 变量= 函数名(实参列表);//带返回值的
- 有无返回值
- 1).有返回值的,根据返回值的类型,需要在主调函数中定义一个对应类型的变量,接返回值
例 11:
int max(int x,int y)// x、y 形参,是个变量
{
}
int main()
{
int num;//需要定义一个 num 接收 max 函数的返回值
num=max(4,8);//4 和 8 就是实参
}
2).没有返回值的函数,不需要接收返回值。
例 12:
void fun(void)
{
printf("hello world\n");
}
int main()
{
fun();
}
-
有无形参
- 函数名(实参列表);//带形参的
函数名();//没有形参的
注意:实参,可以常量,可以是变量,或者是表达式
形参是变量,是被调函数的局部变量。 - 函数名(实参列表);//带形参的
-
总结
变量= 函数名(实参列表);//带返回值的
函数名(实参列表);//不带返回值的
注意:实参,可以常量,可以是变量,或者是表达式
形参是变量,是被调函数的局部变量。
4.6 函数总结
在定义函数的时候,关于函数的参数和返回值是什么情况,完全取决于函数的功能。
使用函数的好处?
1、定义一次,可以多次调用,减少代码的冗余度。
2、使咱们代码,模块化更好,方便调试程序,而且阅读方便
4.7 变量的存储类别
4.7.1 内存的分区:
- 内存:物理内存、虚拟内存
- 物理内存:实实在在存在的存储设备
- 虚拟内存:操作系统虚拟出来的内存。
- 操作系统会在物理内存和虚拟内存之间做映射。
- 在 32 位系统下,每个进程的寻址范围是 4G,0x00 00 00 00 ~0xff ff ff ff
- 在写应用程序的,咱们看到的都是虚拟地址。
- 在运行程序的时候,操作系统会将虚拟内存进行分区。
- 1).堆
在动态申请内存的时候,在堆里开辟内存。 - 2).栈
主要存放局部变量。 - 3).静态全局区
a.未初始化的静态全局区
静态变量(定义变量的时候,前面加 static 修饰),或全局变量 ,没有初始化的,存在此区
b.初始化的静态全局区
全局变量、静态变量,赋过初值的,存放在此区 - 4).代码区
存放咱们的程序代码 - 5).文字常量区
存放常量的。
- 1).堆
4.7.2 普通的全局变量
- 概念:
- 在函数外部定义的变量
int num=100;//num 就是一个全局变量
int main()
{
return 0;
}
- 作用范围:
- 普通全局变量的作用范围,是程序的所有地方。
只不过用之前需要声明。声明方法 extern int num;
注意声明的时候,不要赋值。
- 普通全局变量的作用范围,是程序的所有地方。
- 生命周期:
- 程序运行的整个过程,一直存在,直到程序结束。
注意:定义普通的全局变量的时候,如果不赋初值,它的值默认为 0
4.7.3 静态全局变量 static
- 概念:
- 定义全局变量的时候,前面用 static 修饰。
static int num=100;//num 就是一个静态全局变量
int main()
{
return 0;
}
- 作用范围:
- static 限定了静态全局变量的,作用范围
只能在它定义的.c(源文件)中有效
- static 限定了静态全局变量的,作用范围
- 生命周期:
- 在程序的整个运行过程中,一直存在。
注意:定义静态全局变量的时候,如果不赋初值,它的值默认为 0
4.7.4 普通的局部变量
- 概念:
- 在函数内部定义的,或者复合语句中定义的变量
int main()
{
int num;//普通局部变量
{
int a;//普通局部变量
}
}
- 作用范围:
- 在函数中定义的变量,在它的函数中有效
在复合语句中定义的,在它的复合语句中有效。
- 在函数中定义的变量,在它的函数中有效
- 生命周期:
- 在函数调用之前,局部变量不占用空间,调用函数的时候,
才为局部变量开辟空间,函数结束了,局部变量就释放了。
在复合语句中定义的亦如此。
- 在函数调用之前,局部变量不占用空间,调用函数的时候,
#include<stdio.h>
void fun()
{
int num=3;
num++;
printf("num=%d\n",num);
}
int main()
{
fun();
fun();
fun();
return 0;
}
4.7.5 静态的局部变量
- 概念:
- 定义局部变量的时候,前面加 static 修饰
- 作用范围:
- 在它定义的函数或复合语句中有效。
- 生命周期:
- 第一次调用函数的时候,开辟空间赋值,函数结束后,不释放,
以后再调用函数的时候,就不再为其开辟空间,也不赋初值,
用的是以前的那个变量。
- 第一次调用函数的时候,开辟空间赋值,函数结束后,不释放,
void fun()
{
static int num=3;
num++;
printf("num=%d\n",num);
}
int main()
{
fun();
fun();
fun();
}
运行结果如下图所示:
注意:
- 1:定义普通局部变量,如果不赋初值,它的值是随机的。
定义静态局部变量,如果不赋初值,它的值是 0 - 2:普通全局变量,和静态全局变量如果不赋初值,它的值为 0
变量存储类别扩展:
- 在同一作用范围内,不允许变量重名。
- 作用范围不同的可以重名。
- 局部范围内,重名的全局变量不起作用。(就近原则)
4.7.6 外部函数
咱们定义的普通函数,都是外部函数。
即函数可以在程序的任何一个文件中调用。
4.7.7 内部函数
在定义函数的时候,返回值类型前面加 static 修饰。这样的函数
被称为内部函数。
static 限定了函数的作用范围,在定义的.c 中有效。
内部函数,和外部函数的区别:
外部函数,在所有地方都可以调用
内部函数,只能在所定义的.c 中的函数调用。
4.7.8 总结
4.7.1 内存的分区:1.内存的分区;2.虚拟内存的分区;
4.7.2 普通的全局变量;
4.7.3 静态全局变量 static;
4.7.4 普通的局部变量;
4.7.5 静态的局部变量:
- 注意:
- 1:定义普通局部变量,如果不赋初值,它的值是随机的。
定义静态局部变量,如果不赋初值,它的值是 0 - 2:普通全局变量,和静态全局变量如果不赋初值,它的值为 0
- 1:定义普通局部变量,如果不赋初值,它的值是随机的。
- 变量存储类别扩展:
- 在同一作用范围内,不允许变量重名。
- 作用范围不同的可以重名。
- 局部范围内,重名的全局变量不起作用。(就近原则)
4.7.6 外部函数
4.7.7 内部函数
4.8 菜鸟笔记
1.笔记一:
根据函数能否被其他源文件调用,将函数区分为内部函数和外部函数。
内部函数
如果一个函数只能被本文件中其他函数所调用,它称为内部函数。在定义内部函数时,在函数名和函数类型的前面加 static,即
static 类型名 函数名 (形参表)
例如,函数的首行:
static int max(int a,int b)
内部函数又称静态函数。使用内部函数,可以使函数的作用域只局限于所在文件。即使在不同的文件中有同名的内部函数,也互不干扰。提高了程序的可靠性。
外部函数
如果在定义函数时,在函数的首部的最左端加关键字 extern,则此函数是外部函数,可供其它文件调用。
如函数首部可以为
extern int max (int a,int b)
C 语言规定,如果在定义函数时省略 extern,则默认为外部函数。
在需要调用此函数的其他文件中,需要对此函数作声明(不要忘记,即使在本文件中调用一个函数,也要用函数原型来声明)。在对此函数作声明时,要加关键字 extern,表示该函数是在其他文件中定义的外部函数。
实例
以下实例通过多个文件的函数实现输入一串字符串,然后删除指定的字符:
file1.c(文件1)
#include <stdio.h>
static void delete_string(char str[],char ch);
int main()
{
extern void enter(char str[]); // 对函数的声明
extern void print(char str[]); // 对函数的声明
char c,str[100];
enter(str);
scanf("%c",&c);
delete_string(str,c);
print(str);
return 0;
}
static void delete_string(char str[],char ch)//内部函数
{
int i,j;
for(i=j=0;str[i]!='\0';i++)
if(str[i]!=ch)
str[j++]=str[i];
str[j]='\0';
}
file2.c(文件2)
#include <stdio.h>
void enter(char str[100]) // 定义外部函数 enter
{
fgets(str, 100, stdin); // 向字符数组输入字符串
}
file3.c(文件3)
#include <stdio.h>
void print(char str[]) // 定义外部函数 print
{
printf("%s\n",str);
}
输入字符串"abcdef",给字符数组 str,在输入要删去的字符'd'。 运行结果:
$ gcc file1.c file2.c file3.c
$ ./a.out
abcdef # 输入的字符串
d # 要删除的字符
abcef # 删除后的字符串
2.笔记二
内联函数
内联函数是指用inline关键字修饰的函数。在类内定义的函数被默认成内联函数。内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。
内联扩展是用来消除函数调用时的时间开销。它通常用于频繁执行的函数,对于小内存空间的函数非常受益。
使用内联函数的时候要注意:
- 递归函数不能定义为内联函数
- 内联函数一般适合于不存在while和switch等复杂的结构且只有1~5条语句的小函数上,否则编译系统将该函数视为普通函数。
- 内联函数只能先定义后使用,否则编译系统也会把它认为是普通函数。
- 对内联函数不能进行异常的接口声明。
示例:一个简单的交换函数
inline void swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
- 笔记三
关于 main 函数的参数
在有些很专业的书会看到如下代码
int main( int argc, char *argv[] )
上面的代码中 main 函数带了参数。
但是有时又会看见main函数没有参数,如下:
int main()
那么 main 函数到底有没有参数,有没有参数会不会有什么影响?
main 函数其实与我们写的函数没有什么区别,它也会有自己的参数。
argc 和 argv 是 main 函数的形式参数。
这两个形式参数的类型是系统规定的。如果 main 函数要带参数,就是这两个类型的参数;否则main函数就没有参数。
变量名称argc和argv是常规的名称,当然也可以换成其他名称。在传入参数后main函数收到参数后就会做自己的事。那么,实际参数是如何传递给main函数的argc和argv的呢?我们知道,C程序在编译和链接后,都生成一个exe文件,执行该exe文件时,可以直接执行;也可以在命令行下带参数执行,命令行执行的形式为:可执行文件名称 参数1 参数2 … … 参数n。可执行文件名称和参数、参数之间均使用空格隔开。
如果按照这种方法执行,命令行字符串将作为实际参数传递给main函数。具体为:
- (1) 可执行文件名称和所有参数的个数之和传递给 argc;
- (2) 可执行文件名称(包括路径名称)作为一个字符串,首地址被赋给 argv[0],参数1也作为一个字符串,首地址被赋给 argv[1],… …依次类推。
- 笔记四
上面的是求两个数的最大值,我的是求三个数的最大值:
#include <stdio.h>
int DoMax(int a, int b, int c){
int max=a;
if(b>max){
max=b;
if(c>max){
max=c;
}
} else {
if(c>max){
max=c;
}
}
return max;
}
int main(){
int x, y, z, maxOne;
printf("请输入三个数字(空格分隔):");
scanf("%d%d%d",&x,&y,&z);
maxOne=DoMax(x, y, z);
printf("\n");
printf("最大数为:%d; \n",maxOne);
return 0;
}
- 笔记五
函数参数传递常用的三种方式
示例程序均以交换两个整数为例。
- 1. 值传递
#include <stdio.h>
void swap(int x, int y);
void swap(int x, int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
int main( int argc, char *argv[] )
{
int a = 5;
int b = 10;
swap(a, b); //调用交换函数
printf("交换结果为 a = %d, b = %d\n",a,b);
return 0;
}
由于值传递是单向传递,传递过程中只是改变了形参的数值,并未改变实参的数值,因此并不会改变a和b原有的值。
- 2. 指针传递
#include <stdio.h>
void swap(int *x, int *y);
void swap(int *x, int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
int main( int argc, char *argv[] )
{
int a = 5;
int b = 10;
swap(&a, &b); //调用交换函数
printf("交换结果为 a = %d, b = %d\n",a,b);
return 0;
}
指针传递过程中,将a和b的地址分别传递给了x和y,在函数体内部改变了a、b所在地址的值,即交换了a、b的数值。
- 3. 引用传递
#include <stdio.h>
void swap(int &x, int &y);
void swap(int &x, int &y)
{
int temp;
temp = x;
x = y;
y = temp;
}
int main( int argc, char *argv[] )
{
int a = 5;
int b = 10;
swap(a, b); //调用交换函数
printf("交换结果为 a = %d, b = %d\n",a,b);
return 0;
}
引用传递中,在调用swap(a, b);时函数会用a、b分别代替x、y,即x、y分别引用了a、b变量,这样函数体中实际参与运算的其实就是实参a、b本身,因此也能达到交换数值的目的。
注:严格来说,C语言中是没有引用传递,这是C++中语言特性,因此在.c文件中使用引用传递会导致程序编译出错。
- 笔记六
函数声明和函数原型的参数名可以不一样,编译器他想知道的是函数参数的类型,与函数参数的名字没有关系,eg:
include<stdio.h>
int sum(int c,int d); // 函数声明
int main(int argc ,char*argv[])
{
int a=2,b=3;
printf("输出结果为: %d \n",sum(a,b));
return 0;
}
int sum(int a,int b)
{
return a+b ;
}
甚至函数声明可以写成:
int sum(int ,int );
编译器只要检查到函数返回类型,名称和参数类型正确即可。
- 笔记七
函数实现了代码的重用,大大简化缩短了程序员的工作量,更使得程序的可读性大大提高,函数的递归调用更是一种简化程序代码的方法;递归调用其实就是函数自己调用自己。
下面的实例是一个求1+2+3.....+n的递归实例:
#include <stdio.h> //导如输入输出头文件
int sum(int n);//声明函数
int main(){
//主函数
int a=sum(4);
printf("%d",a);
return 0;
}
int sum(int n){
//求和函数实现
//如果n为1,无需求和,直接返回1
if(n==1){
return 1;
}
//如果n大于1,就返回n加上1+2+3.....+n-1的和
return n+sum(n-1);
}
可以发现,递归的代码很少,但是,递归也有缺点,递归占用的内存要比递推大,而且时间也要比递推长。
- 笔记八
占位符就是先占住一个固定的位置,等着你再往里面添加内容的符号,广泛用于计算机中各类文档的编辑。
格式占位符(%)是在C/C++语言中格式输入函数,如 scanf、printf 等函数中使用。其意义就是起到格式占位的意思,表示在该位置有输入或者输出。
%d, %i 代表整数
%f 浮点
%s 字符串
%c char
%p 指针
%fL 长log
%e 科学计数
%g 小数或科学计数。
%a,%A 读入一个浮点值(仅C99有效)。
%c 读入一个字符。
%d 读入十进制整数。
%i 读入十进制,八进制,十六进制整数。
%o 读入八进制整数。
%x,%X 读入十六进制整数。
%s 读入一个字符串,遇空格、制表符或换行符结束。
%f,%F,%e,%E,%g,%G 用来输入实数,可以用小数形式或指数形式输入。
%p 读入一个指针。
%u 读入一个无符号十进制整数。
%n 至此已读入值的等价字符数。
%[] 扫描字符集合。
%% 读 % 符号
实例:
scanf("%d,%d,%d",&a,&b,&c); // 从键盘输入三个整数,用逗号分隔
scanf("%c", &s); // 从键盘输入一个字符
scanf("%f", &f); // 从键盘输入一个浮点型数据
printf("%d\n",a); // 输出一个整数
printf("%f\n",b); // 输出一个浮点数
printf("%s\n",c); // 输出一个字符, 其中\n表示换行
- 笔记九
- 1、函数的调用:由于程序是从上向下执行,所以函数要先声明,后调用。这种先后是文档中所处位置的先后,不是时间的先后。以下写法为正确的:
#include<stdio.h>
void f(void) /*定义函数*/
{
printf("我是一个函数,我将在主函数中输出\n");
}
int main(void)
{
f(); /*调用函数*/
}
在上面这个实例中,在主函数中调用了函数 f(), 而函数的声明是在调用以前。
- 2、这种写法是错误的
#include<stdio.h>
int main(void)
{
f();/*调用函数*/
}
void f(void) /*定义函数*/
{
printf("我是一个函数,我将在主函数中输出\n");
}
在上面这个实例中,在主函数中调用了函数 f(), 而函数的声明却在调用之后。由于函数执行时是从上往下执行的所以,这写法是错误的。
//如果函数非要写在主函数之后可以在主函数之前加入一个函数的前置声明。
//前置声明如下:
#include<stdio.h>
void f(void); /*前置声明*/
int main(void)
{
f(); /*调用函数*/
}
void f(void) /*定义函数*/
{
printf("我是一个函数,我一定要先声明后调用\n");
}
- 笔记十
本质上说,C 里面所有的函数参数传递,都是值传递。
指针传递之所以能改变传递参数变量的值,是因为 swap 函数交换的不是传递进来的指针本身,而是指针指向的值。
void swap(int *x, int *y);
void swap(int *x, int *y){
int temp;
//这里操作的是指针指向的值 而不是指针
temp = *x;
*x = *y;
*y = temp;
// 倘若直接交换指针 a、b的值不会交换
// temp = x;
// x = y;
// y = temp;
}
int main( int argc, char *argv[] )
{
int a = 5;
int b = 10;
swap(&a, &b); //调用交换函数
printf("交换结果为 a = %d, b = %d\n",a,b);
return 0;
}
引用传递也类似。
- 笔记十一
上面那个3个数最大值的太复杂,我这个好理解些:
#include <stdio.h>
int main()
{
int a,b,c,max;
printf("请输入三个数字(空格分隔):");
scanf("%d%d%d",&a,&b,&c);
if(a==b==c)
max=a;
else if((a>b)&&(a>c))
max=a;
else if((b>a)&&(b>c))
max=b;
else if((c>a)&&(c>a))
max=c;
printf("max=%d",max);
return 0;
}
- 笔记十二
上面求3个数最大值的太复杂,这个更简洁:
#include <stdio.h>
float myMax(float a, float b, float c){
return a>=b ? (a>=c ? a : c) : (b>=c ? b : c);
}
int main() {
float x, y, z, maxValue;
printf("请输入任意三个数:\n");
scanf("%f%f%f", &x,&y,&z);
maxValue = myMax(x, y, z);
printf("最大值为:%f\n", maxValue);
return 0;
}
- 笔记十三
“本质上说,C 里面所有的函数参数传递,都是值传递”,这一条,完全正确的代码如下:
#include<stdio.h>
void swap(int *x, int *y);
void swap(int *x, int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
int main()
{
int a = 5;
int b = 10;
swap(&a, &b);
printf("result of swap: a=%d, b=%d", a, b);
return 0;
}
- 笔记十四
函数名和参数列表一起构成了函数签名。意味着可以出现参数列表不同但是函数名相同的函数。比如说定义两个函数:
void print()
{
printf("hello world!");
}
void print(int nums)
{
printf("%d\n",a);
}
这是合法的。
- 笔记十五
可以用预处理命令 define 来定义简单函数:
#define MAX_3(a, b, c) ( ((a > b ? a : b) > c) ? (a > b ? a : b) : c )
#define MIN_3(a, b, c) ( ((a < b ? a : b) < c) ? (a < b ? a : b) : c )
#define MAX_2(x, y) ( x> y ? x : y )
#define MIN_2(x, y) ( x< y ? x : y )
#define ARR_SIZE(a) ( sizeof( (a) ) / sizeof( (a[0]) ) )
#define MULTIPLE(m, n) ( (m%n == 0)?0:1 )
#define AVE_3(a, b, c) (a+b+c)/3
#define SUM_3(a, b, c) a+b+c
#define SWAP(a, b){int t= a;a=b;b=t;}