C语言入门基础day5

1 概念

在程序设计过程中,为了实现某个功能需要编写多行代码,
例如求一个一维数组中的最大值,如果该功能需要被多次使
用,我们可以在每次使用时将原来的代码重复编写,但是这
样编程效率不高。为了避免重复劳动,我们可以将这部分代
码封装到一个“函数”中,在需要使用该功能时调用封装好的函数即可

1.1 练习

//自定义一个函数完成返回一个一维数组的最大值的功能
int array_max(int a[], int len)
{
  int i, max = a[0];
  for(i = 1; i < len; i++)
 {
    if(a[i] > max)
      max = a[i];
 }
  return max;
}
int main()
{
  int a[4][4] = { {10, 5, 90, 7},
         {3, 6, 2, 8},
         {23,34,56,8},
         {13,6,34,567}};
  int i, max;
  for(i = 0; i < 4; i++)
 {
    max = array_max(a[i], 4);
    printf("max = %d\n", max);
 }
  return 0;
}

1.2 小结

函数就是具有特殊功能的指令的集合C程序是由函数组成的,
函数是 C 程序的基本模块,C程序从主函数main()开始执行

从函数定义的角度出发,函数可以分为库函数和用户自定义
函数两种:

1.库函数:由标准C库提供,用户不需要自己实现,在使用
时直接调用即可,例如printf、scanf函数等

2.用户自定义函数:需要用户自己根据实际需求自己实现,
例如比较两个整数的大小,并且求出最大值

2 语法及分类

2.1函数定义的语法规则

类型标识符 函数名(形参列表)
{
  函数体
}

说明:

类型标识符:函数返回数据的类型,支持C语言所有的数据
类型

函数名:由用户定义的标识符

形参列表:函数用来接收用户所传递数据的参数,参数可
以是0个也可以是多个

函数体:实现函数功能的代码块

2.2 无参函数的定义

概念:函数不需要接收用户传递的数据,即形参列表为空

类型标识符 函数名()//形参,形式参数
{
  函数体
}

注意1:如果函数不需要返回值,”类型标识符“可以设计为void

void func()
{
  printf("hello world\n");
}

注意2:如果函数需要返回值,返回值是什么类型”类型标识符“就是什么类型
练习:

//设计一个函数返回1~100的和
int func()
{
  int i, sum = 0;
  for (i = 1; i <= 100; i++)
  sum += i;
  return sum;
}

2.3有参函数的定义

概念:可以根据实际需求设计函数的形参,形参的作用就是接收用户传递的数据

类型标识符 函数名(类型标识符 形参1, 类型标识符 形参2
... )
{
  函数体
}
//注意:形参的数据类型及个数由实际需求而定

练习:

//设计一个函数计算两个整数的和
void sum(int a, int b)
{
  int c = a+b;
  printf("sum: %d\n", c);
}

3 参数和返回值

3.1 函数的形参和实参

概念:形参出现在函数的定义中,在整个函数体中都可以访问到,
离开了该函数就不能被访问了,实参出现在函数调用时函数
调用时,将实参的值的赋值给形参
特点:
1. 形参只有在函数被调用时才会被分配内存空间
2. 实参可以是常量、变量、表达式、函数名

在这里插入图片描述

3.2 函数的返回值

概念:函数的返回值是函数将函数体中的执行结果返回(传递)给函数的调用者,通过return语句返回

return 表达式;
或者
return (表达式);有没有( )都是正确的,为了简明,一般也不
写( )。例如:
return max;
return a+b;
return (100+200);

注意1:函数执行完return语句后,函数执行完毕(函数退出),函数的返回类型就是函数的类型。
对于:

int func(){}

该函数的返回类型是int,那我们就说函数func是个整型函数。
注意2:如果函数不需要返回值,函数的返回类型为void,在函数体中:可以使用 “return ;” 语句退出函数,也可以不使用“return ;”

void func()
{
  printf("hello\n");
  return ; //这句话也可以不写
}

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

double max() // 函数的返回类型为double
{
  int a = 1;
  return a;// 返回值a为int类型,会转为double类型
再返回,最终返回 1.0
}

4 调用

在自定义函数时我们要注意:

函数在定义完以后,如果不被调用函数是不会被执行到的。

main函数是C程序的主函数,是会被自动执行到的,C程序中
有且只有一个main函数。

4.1 无参函数的调用

调用方法:

函数名();
或者:
变量 = 函数名();
注意:当函数有返回值时,我们可以定义一个变量来接收函数的返回值,
但是定义变量的数据类型必须和函数的返回类型一致,
当然我们也可以不接收函数的返回值
案例:
int func()
{
  return 10;
}
int main()
{
  func();
  int x = func();
  return 0;
}

4.2 有参函数的调用

调用方法:

函数名(实参列表)
或者
变量 = 函数名(实参列表)

在这里插入图片描述
注意:变量名可以相同也可以不同,并且实参的个数和形参的个数必须一致。

5 函数的嵌套调用

概念:函数的嵌套调用:某个函数的函数体中调用了另外一个函数

void b()
{
  printf("b\n");
}
void a()
{
  printf("a\n");
  b();
}
int main()
{
  a();
  return 0;
}

执行逻辑:
在这里插入图片描述

6 函数的声明

错误示例:

void a()
{
  printf("a\n");
  b();
}
void b()
{
  printf("b\n");
}
int main()
{
  a();
  return 0;
}
结果:[Error] 'b' was not declared in this scope

解决办法:

//1. 将函数b的定义放在函数a之前
void b()
{
  printf("b\n");
}
void a()
{
  printf("a\n");
  b();
}

int main()
{
  a();
  return 0;
}
//2. 在代码的前面部分对函数b进行声明
void b();

void a()
{
  printf("a\n");
  b();
}
void b()
{
  printf("b\n");
}
int main()
{
  a();
  return 0;
}

6.1 小结

函数类型 函数名(形参列表);
注意:

1、后面有分号 ;

2、函数声明时,函数类型(返回值类型)必须于函数实现时一致,函数名必须和函数实现时一致

3、形参列表中,可以不填写形参变量的名字,只需要填写形参的类型即可,例如:
int fun(int, float);

7 局部变量和全局变量

7.1 局部变量

概念:定义在{}内的变量,称之为局部变量

void func()
{
 int func_x = 100; 	//局部变量
}
int main()
{
  int i = 10;		//局部变量
  {
    int i = 100; 	//局部变量
    int j = 100; 	//局部变量
  }
  return 0;
}

7.1.1局部变量的作用域

局部变量的作用域:所在的 {} 内

void func() 
{
  int func_x = 100; //局部变量
}
int main()
{
  int i = 10;//局部变量
  {
    int i = 100; //局部变量
    printf("%d\n", i); // 100
    int j = 100; //局部变量
  }
  printf("%d\n", i); // 10
  return 0;
}

7.1.1局部变量的生命周期

局部变量的生命周期:随 {} 的结束而结束

void func()
{
  int func_x = 100; //局部变量
}
int main()
{
  int i = 10;//局部变量
  {
    int i = 100; //局部变量
    printf("%d\n", i); // 100
    int j = 100; //局部变量
  }
  printf("%d\n", i); // 10
  printf("%d\n", j); //编译报错:error: 'j'
undeclared
  printf("%d\n", func_x);//编译报错:error:
'func_x' undeclared
  return 0;
}

7.2 全局变量

概念:定义在函数外部的变量称之为:全局变量

int cnt = 10; //全局变量
void func()
{
  int func_x = 100; //局部变量
  cnt++;
}
int main()
{
  func();
  printf("cnt: %d\n", cnt);
  return 0;
}
1. 全局变量的初始化全局变量在定义时如果不初始化,编译
器会将值设置为默认值0

2. 全局变量的作用域:整个程序

3. 全局变量的生命周期:随程序的结束而结束
注意:
全局变量默认的作用域实际上是在单个文件中,由于
我们现在只使用了单文件编程,所以作用域是整个程序。等
后续我们学习到多文件编程之后。全局变量的作用域就只在
定义的那个文件里。那么全局变量的作用域可以扩展到整个
程序,方法是在全局变量的声明前面加上extern修饰。
extern int a;

8 递归函数

概念:一个函数在它的函数体内调用自身称为递归调用。这种函数称为递归函数。

void func()
{
  func();
}

4.1 使用和练习

注意:函数递归调用一定要有退出条件!!!
练习:

求n的阶乘,比如5的阶乘 = 5x4x3x2x1
long long fun(int n)
{
  if (n== 1)
  return 1;
  return n*fun(n-1);
}
使用递归实现求斐波那契数列的第n项的值,斐波
那契数列:从第三项开始,每一项等于前两项的和:1123581321、。。。
int fun(int n)
{
  if ((n == 1) || (n == 0))
  return n;
  return fun(n-2) + fun(n-1);
}
求斐波那契数列的前n项的和
#include<stdio.h> 
//求斐波那契数列的第n项
int fac(int n)
{
  if ((n == 1) || (n == 0))
    return n;
  return fac(n-2) + fac(n-1);
}
//求斐波那契数列的前n项的和
/*
* 解题思路:前n项的和 = 第n项 + 前n-1项的和
* */
unsigned long long facSum(int n)
{
  if (n == 1 || n == 0)
    return n;
  return fac(n) + facSum(n-1);
}
int main()
{
  unsigned long long sum;
  int n;
  scanf("%d", &n);
  printf("%lld\n", facSum(n));
  return 0;
}
5个人坐在一起,问第5个人多少岁?他说比第4个人大2岁。
问第4个人岁数,他说比第3个人大2岁。问第3个人,又说比
第2个人大2岁。问第2个人,说比第1个人大2岁。最后问第1
个人,他说是10岁。请问第5个人多大
int func(int n)
{
	if (n==1)
		return 10;
	return func(n-1)+2;
}
int main()
{
	int n;
	scanf("%d",&n);
	int ret = func(n); 
	printf("%d",ret);
 } 

9 预处理概述

概念:以 #号开头的命令称为预处理命令

C语言提供了多种预处理功能,如宏定义、文件包含、条件编
译等。合理地使用预处理功能编写的程序便于阅读、修改、
移植和调试,也有利于模块化程序设计

10 宏定义

在C语言源程序中允许用一个标识符来表示一个字符串,
称为“宏”。被定义为“宏”的标识符称为“宏名”。
在编译预处理时对程序中所有出现的“宏名”,
都用宏定义中的字符串去进行文本替换,
这称为“宏代换”或“宏展开”

10.1 无参宏定义

语法:

#define 标识符 字符串

注意:“字符串”可以是常量、表达式

示例:

#include <stdio.h>
#define PI 3.14

int main()
{
  int r;
 double s;
  scanf("%d",&r);
 s=r*r*PI; 
 printf("%lf\n",s);
  return 0;
  结果: 输入r = 3,输出s=28.260000
}

注意:宏定义是简单的文本替换,不会做语法检查!!!

10.2 有参宏定义

C语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数

语法:

#define 宏名(形参表) 字符串

使用方法:

#define F(x) x*x*x
int main()
{
  int r = F(3);
  return 0;
}

10.3宏定义注意事项

宏定义的“字符串”如果是表达式,表达式中的变量需要用 ()包含起来,因为在预处理阶段展开宏时,可能会用表达式来替换宏定义中的变量

#define F(x) (x)*(x)*(x)
int main()
{
  F(1+2);
  return 0;
}

11 文件包含

#include <文件名>
#include "文件名"

使用尖括号表示在开发环境的头文件目录下查找,而不在
源文件目录去查找
使用双引号则表示首先在当前的源文件目录中查找,如果
没有找到才到包含目录中去查找
“文件名”可以是相对路径,也可以是绝对路径,建议不要
使用绝对路径

12 条件编译

在这里插入图片描述

#ifdef 标识符
  程序段 1
#else
  程序段 2
#endif
代码说明:如果标识符已被 #define 命令定义过则对程序段
1 进行编译;
否则对程序段 2 进行编译

13 总结

1. 函数就是具有特殊功能的指令的集合

2. 库函数:由标准C库提供,例如printf、scanf函数等。

3. 用户自定义函数:需要用户自己根据实际需求自己实现,
例如比较两个整数的大小,并且求出最大值。

4. 函数分类:
1. 无参无返回值函数:void func(void);
2. 无参有返回值函数:int func(void);
3. 有参无返回值函数:void func(int a, int b);
4. 有参有返回值函数:int func(int a, int b);

5. 形参只有在函数被调用时才会被分配内存空间

6. 实参可以是常量、变量、表达式、函数名

7. 如果函数不需要返回值,在函数体中可以使用 "return "
语句退出函数,也可以不使用“return
  • 27
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值