C语言-第三章:变量进阶与函数

传送门:C语言-第二章-加餐:猜数字游戏与循环嵌套

目录

第一节:变量进阶

        1-1.局部变量与全局变量

                1-1-1.局部变量

                1-1-2.全局变量

        1-2.变量生命周期

                1-2-1.局部变量的生命周期

                1-2-2.全局变量的生命周期

第二节:函数

        2-1.函数调用

        2-2.库函数

        2-3.自定义函数

        2-4.加餐-函数解耦

                2-4-1.游戏菜单

                2-4-2.选择

                2-4-3.开始游戏

下期预告:


第一节:变量进阶

        在第二章中,我们已经学习了变量的定义与使用,接下来我们将学习变量的更多特性。

        1-1.局部变量与全局变量

                1-1-1.局部变量

        我们之前在代码中定义的变量全部都是 局部变量,它的特征是被{}包括在内,可以说,被{}包括在内的变量都是局部变量:

int main()
{ // 大括号

    int a = 0;    // 我是一个局部变量
    char b = 'A';  // 我也是一个局部变量
    return 0;
} // 反大括号

        经过第二章的学习,我们可以注意到无论分支语句还是循环语句,它们都各自带有自己的{}。对于{}嵌套的情况,即使在嵌套中的{}定义的变量,也是局部变量,无论{}嵌套了多少层:

int main()
{ // 大括号

    int a = 0;    // 我是一个局部变量
    char b = 'A';  // 我也是一个局部变量
    
    if(1)
    {
        float f = 1.000001; // 我也是一个局部变量
    }
    while(1)
    {
        long c = 10; // 我还是一个局部变量
    }
    return 0;
} // 反大括号

                1-1-2.全局变量

        与局部变量相反,只要不被{}包括的变量就是 全局变量,可以说,一个变量不是局部变量就是全局变量:

int e = 100; // 我就是全局变量

int main()
{ // 大括号

    int a = 0;    // 我是一个局部变量
    char b = 'A';  // 我也是一个局部变量
    
    if(1)
    {
        float f = 1.000001; // 我也是一个局部变量
    }
    while(1)
    {
        long c = 10; // 我还是一个局部变量
    }
    return 0;
} // 反大括号

        全局变量和局部变量在使用范围上有区别,这种区别就是变量的另一种特性:生命周期

        1-2.变量生命周期

        变量的生命周期就是它的“寿命”,一个变量的生命周期从它被定义开始,到它所在的这个{}结束(或者程序结束时结束)。在这个变量的生命周期之外,我们不能使用它。

                1-2-1.局部变量的生命周期

        请阅读以下代码:

int main()
{ // 大括号

    int a = 0;    // 我是一个局部变量a,我的生命周期从这一行开始
    
    if(1)
    {
        float f = 1.000001;
    }
    while(1)
    {
        long c = 10; 
    }
    return 0;   // 程序结束,所有“存活”变量的生命周期都在这里结束
}               // 反大括号,局部变量a的生命周期在这里结束

        局部变量a的生命周期如上图所示,在它的生命周期中,可以对它进行使用。

        下图帮助理解生命周期的长度:

5e4dbb02444d4d8fb9ed4eee5f187518.png

       ps:上面图片的 main 函数中并没有 return(忘记写了,正常应该补上),所以a的生命周期才在反大括号处结束

        如何证明生命周期确实是这样呢?我们先看看局部变量a:

#include <stdio.h>
int main()
{ // 大括号

    int a = 0;    // 我是一个局部变量a,我的生命周期从这一行开始

    printf("我是一个标记,标记号:1,现在我使用变量a:%d",a);

    return 0;     // 程序结束,局部变量a的生命周期在这里结束
}                

       0696f6927bf84a9b990cba49c08a0411.png

        我们在a的生命周期中使用a,程序可以正常执行。

        看看生命周期之外使用a的情况:

#include <stdio.h>
int main()
{                 // 大括号
    printf("我是一个标记,标记号:0,现在我使用变量a:%d", a);

    int a = 0;    // 我是一个局部变量a,我的生命周期从这一行开始
    return 0;
}                 // 程序结束,局部变量a的生命周期在这里结束

        5258fe74993b4239af4077f2a28bec53.png 

        结果报错了,a是没有声明的标识符,意思是a没有定义,它还没有“出生”。

        再来看看嵌套{}中的局部变量f:

#include <stdio.h>
int main()
{ 
    if (1)
    {
        float f = 1.000001;   // 局部变量f的生命周期在这里开始
        printf("我是一个标记,标记号:1,现在我使用变量f:%f", f);
    }                         // 反大括号,局部变量f的生命周期在这里结束
    return 0;
}  

        4083e2c4c0bc45a9b25c5aa045a8403d.png

        我们在f的生命周期中使用f,程序可以正常执行。

        看看生命周期之外使用f的情况:

#include <stdio.h>
int main()
{ 
    if (1)
    {
        float f = 1.000001;   // 局部变量f的生命周期在这里开始;
    }                         // 反大括号,局部变量f的生命周期在这里结束
    printf("我是一个标记,标记号:0,现在我使用变量f:%f", f);
    return 0;
}    

          f8cbdc09e3904f3fb727cad4ade2f307.png

        虽然我们在f定义之后的再使用f,但是这时候它已经“死了”,在生命周期之外所以也属于未定义的符号。

                1-2-2.全局变量的生命周期

        全局变量并没有被{}括起来,它的生命周期从定义开始,直到程序结束:

59def642e0db401b9538c18975f69146.png

         我们可以验证一下,请阅读以下代码和执行结果:

#include <stdio.h>
int e = 100; // 我是一个全局变量e,我的生命周期从这一行开始
int main()
{
    printf("我是一个标记,标记号:0,现在我使用变量e:%d", e);
    if(1)
    {
        printf("我是一个标记,标记号:1,现在我使用变量e:%d", e);
    }
    printf("我是一个标记,标记号:2,现在我使用变量e:%d", e);
    return 0; // 程序结束,所有“存活”变量的生命周期都在这里结束,包括全局变量
}

618ef0bbb4b34f6093427f26c80c1afd.png

        结果表明,无论是在{}还是嵌套{}中,全局变量都可以使用,即它的生命周期覆盖整个程序。

第二节:函数

        2-1.函数调用

        我们之前已经使用过 printf 函数,函数的使用就叫调用,它的调用格式如下:

[函数名] ([参数]);

        例如使用 printf 函数

printf("我是参数");

        2-2.库函数

        库函数是C语言库中自带的函数比如之前的 printf 函数和 scanf 函数,我们要使用这些函数需要引头文件:

#include <stdio.h> // stdio.h 就是头文件名,#include <头文件名>引进这个库,就可以使用里面的库函数

int main()
{
    int a;
    printf("使用我需要引用头文件stdio.h");
    scanf("%d",&a); // 使用我也需要引用头文件stdio.h
}

         ps:一个头文件可以包含多个库函数,一些库函数在不同头文件中

        这类函数不需要我们自己写就可以用,因为它们是其他人写好了保存在头文件中,可以被我们之间使用。    

        除了可以直接使用的库函数,我们也可以自己写函数。

        2-3.自定义函数

        我们自己写的函数叫 自定义函数,它们写在 main 函数之前,所有函数(包括库函数)都具有以下格式:

[返回类型] [函数名]([参数])
{
    使用函数时执行的代码
}

        返回类型:包括之前讲的基本类型:int、short、char等,它是函数调用 return 时返回的一个数据类型,然后可以被外部接收到,不需要返回数据就填 void。

        函数名:函数的名称,自定义函数可以自己取名字,像变量一样。

        参数:使用函数时需要的参数,可以没有参数,也可以有多个参数。

        我们可以编写函数来实现一些固定功能,例如一个简单的加法函数:

int Add(int x,int y) // 函数的声明
{
    int sum = x + y; // {}是函数的定义,里面可以不写任何东西
    return sum;
}

        ps:不论 return 之后有没有代码,只要执行了 return 后面的代码都不执行了。

        以上叫做函数的 声明 与 定义。

        先声明,后调用 是函数的六字真言。

        现在我们使用它来完成一些简单的加法:

#include <stdio.h>

int Add(int x, int y)
{
    int sum = x + y;
    return sum;
}

int main()
{
    int result_1 = Add(4, 5); // 可以传具体数字
    printf("结果为: % d\n",result_1);

        int a = 4;
    int b = 3;
    int result_2 = Add(a, b); //也可以传变量
    printf("结果为: % d\n",result_2);

        return 0;
}

        cf1864c71ab2406d9dbb425286a70f68.png

        上述代码的执行顺序是:

04bd92f78dc54178a99c0b5d786c631d.png

       还有一些细节需要注意:

        1、函数调用:调用时,传入的参数4和5会被函数里的参数x和y按顺序接收到,等价于int x = 4,int y = 5;下面传入a、b时也一样会被接收,即int x = a、int y = b

        2、函数返回:根据之前讲的生命周期,在函数外部sum已经被销毁了,所以函数返回时是把sum变量的值返回了,例如第一次调用 Add 函数时,返回的是sum的值 9,然后被result_1接收到,即int result_1 = 9

        2-4.加餐-函数解耦

        现在我们可以自己写函数了,我们可以用函数把我们之前写的猜数字小游戏这种比较长的代码,按照功能用不同的函数执行。 

 传送门:C语言-第二章-加餐:猜数字游戏与循环嵌套

        先来看看源代码:

#define _CRT_SECURE_NO_WARNINGS
 
#include <stdio.h>
#include <stdlib.h>  // 包含函数 srand 和 rand 的文件
#include <time.h>    // 包含函数 time 的文件
int main()
{
	while(1)    
	{
		//游戏菜单
		printf("************************************\n");
		printf("*************1.开始游戏*************\n");
		printf("*************0.退    出*************\n");
		printf("************************************\n");
		int select;
		printf("请选择:");
		scanf("%d", &select);
		switch (select)
		{
		case 1: // 开始游戏
			srand(time(NULL));     // 用时间戳设置随机数种子
			int random = rand();   // 获取一个随机数
			random = random % 101; // 让随机数的值在0--100之间
			int count = 0;         // 记录猜测次数
			while (1)         
			{
				int guess;
				printf("请输入你猜测的数字:");
				scanf("%d", &guess);
				if (guess > random)      // 大于
				{
					printf("猜大了\n");
					count++;
				}
				else if (guess < random) // 小于
				{
					printf("猜小了\n");
					count++;
				}
				else                     // 等于
				{
					count++;
					printf("恭喜你,猜中了\n");
					printf("共猜了 %d 次\n", count);
					break;
				}
			}
			break;
		case 0: // 退出
			return 0;
		default:// select既不是1也不是0,即一个非法的输入
			printf("非法的输入,请重新选择\n");
		}
	}           
	return 0;
}

        把他分成不同的功能分区:

#define _CRT_SECURE_NO_WARNINGS
 
#include <stdio.h>
#include <stdlib.h>  // 包含函数 srand 和 rand 的文件
#include <time.h>    // 包含函数 time 的文件
int main()
{
	while(1)    
	{
		//游戏菜单---------------------------------------------
		printf("************************************\n");
		printf("*************1.开始游戏*************\n");
		printf("*************0.退    出*************\n");
		printf("************************************\n");
        //游戏菜单---------------------------------------------
        
        //选择------------------------------------------------
		int select;
		printf("请选择:");
		scanf("%d", &select);
		switch (select)
		{
		case 1: //开始游戏-----------------------------------
			srand(time(NULL));     // 用时间戳设置随机数种子
			int random = rand();   // 获取一个随机数
			random = random % 101; // 让随机数的值在0--100之间
			int count = 0;         // 记录猜测次数
			while (1)         
			{
				int guess;
				printf("请输入你猜测的数字:");
				scanf("%d", &guess);
				if (guess > random)      // 大于
				{
					printf("猜大了\n");
					count++;
				}
				else if (guess < random) // 小于
				{
					printf("猜小了\n");
					count++;
				}
				else                     // 等于
				{
					count++;
					printf("恭喜你,猜中了\n");
					printf("共猜了 %d 次\n", count);
					break;
				}
                //开始游戏-----------------------------------
			}
			break;
		case 0: // 退出
			return 0;
		default:// select既不是1也不是0,即一个非法的输入
			printf("非法的输入,请重新选择\n");
		}
        //选择------------------------------------------------
	}           
	return 0;
}

                2-4-1.游戏菜单

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>  // 包含函数 srand 和 rand 的文件
#include <time.h>    // 包含函数 time 的文件

void PrintMune() // 游戏菜单
{
	printf("************************************\n");
	printf("*************1.开始游戏*************\n");
	printf("*************0.退    出*************\n");
	printf("************************************\n");
}

int main()
{
	while (1)
	{
		//游戏菜单---------------------------------------------
		PrintMune();
		//游戏菜单---------------------------------------------

		//选择------------------------------------------------
		int select;
		printf("请选择:");
		scanf("%d", &select);
		switch (select)
		{
		case 1: //开始游戏-----------------------------------
			srand(time(NULL));     // 用时间戳设置随机数种子
			int random = rand();   // 获取一个随机数
			random = random % 101; // 让随机数的值在0--100之间
			int count = 0;         // 记录猜测次数
			while (1)
			{
				int guess;
				printf("请输入你猜测的数字:");
				scanf("%d", &guess);
				if (guess > random)      // 大于
				{
					printf("猜大了\n");
					count++;
				}
				else if (guess < random) // 小于
				{
					printf("猜小了\n");
					count++;
				}
				else                     // 等于
				{
					count++;
					printf("恭喜你,猜中了\n");
					printf("共猜了 %d 次\n", count);
					break;
				}
				//开始游戏-----------------------------------
			}
			break;
		case 0: // 退出
			return 0;
		default:// select既不是1也不是0,即一个非法的输入
			printf("非法的输入,请重新选择\n");
		}
		//选择------------------------------------------------
	}
	return 0;
}

                2-4-2.选择

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>  // 包含函数 srand 和 rand 的文件
#include <time.h>    // 包含函数 time 的文件

void PrintMune()
{
	printf("************************************\n");
	printf("*************1.开始游戏*************\n");
	printf("*************0.退    出*************\n");
	printf("************************************\n");
}

void Select()  // 选择
{
	int select;
	printf("请选择:");
	scanf("%d", &select);
	switch (select)
	{
	case 1: //开始游戏-----------------------------------
		srand(time(NULL));     // 用时间戳设置随机数种子
		int random = rand();   // 获取一个随机数
		random = random % 101; // 让随机数的值在0--100之间
		int count = 0;         // 记录猜测次数
		while (1)
		{
			int guess;
			printf("请输入你猜测的数字:");
			scanf("%d", &guess);
			if (guess > random)      // 大于
			{
				printf("猜大了\n");
				count++;
			}
			else if (guess < random) // 小于
			{
				printf("猜小了\n");
				count++;
			}
			else                     // 等于
			{
				count++;
				printf("恭喜你,猜中了\n");
				printf("共猜了 %d 次\n", count);
				break;
			}
			//开始游戏-----------------------------------
		}
		break;
	case 0: // 退出
		return 0;
	default:// select既不是1也不是0,即一个非法的输入
		printf("非法的输入,请重新选择\n");
	}
}

int main()
{
	while (1)
	{
		//游戏菜单---------------------------------------------
		PrintMune();
		//游戏菜单---------------------------------------------

		//选择------------------------------------------------
		Select();
		//选择------------------------------------------------
	}
	return 0;
}

                2-4-3.开始游戏

        前排提示:函数里面也可以调用函数,所以 开始游戏 的函数在 选择 函数里面调用。

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>  // 包含函数 srand 和 rand 的文件
#include <time.h>    // 包含函数 time 的文件

void PrintMune()
{
	printf("************************************\n");
	printf("*************1.开始游戏*************\n");
	printf("*************0.退    出*************\n");
	printf("************************************\n");
}

void StartGame()  // 开始游戏
{
	srand(time(NULL));     // 用时间戳设置随机数种子
	int random = rand();   // 获取一个随机数
	random = random % 101; // 让随机数的值在0--100之间
	int count = 0;         // 记录猜测次数
	while (1)
	{
		int guess;
		printf("请输入你猜测的数字:");
		scanf("%d", &guess);
		if (guess > random)      // 大于
		{
			printf("猜大了\n");
			count++;
		}
		else if (guess < random) // 小于
		{
			printf("猜小了\n");
			count++;
		}
		else                     // 等于
		{
			count++;
			printf("恭喜你,猜中了\n");
			printf("共猜了 %d 次\n", count);
			break;
		}
	}
}

void Select()
{
	int select;
	printf("请选择:");
	scanf("%d", &select);
	switch (select)
	{
	case 1: //开始游戏-----------------------------------
		StartGame();
			//开始游戏-----------------------------------
		break;
	case 0: // 退出
		return 0;
	default:// select既不是1也不是0,即一个非法的输入
		printf("非法的输入,请重新选择\n");
	}
}

int main()
{
	while (1)
	{
		//游戏菜单---------------------------------------------
		PrintMune();
		//游戏菜单---------------------------------------------

		//选择------------------------------------------------
		Select();
		//选择------------------------------------------------
	}
	return 0;
}

        这样就完成了,但是还有一点BUG,那就是选择0退出时,由于 return 在 Select 函数中,就变成了 Select 函数退出,而不是程序结束,所以可以让 Select 函数把选择的值返回回来,如果是0就在 main 函数中退出:

        1、修改 Select 函数的返回值为 int

        2、在 main 函数中用变量 select 接收返回值

        3、判断 selset 的值,是0就结束程序,否则什么都不做

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>  // 包含函数 srand 和 rand 的文件
#include <time.h>    // 包含函数 time 的文件

void PrintMune()
{
	printf("************************************\n");
	printf("*************1.开始游戏*************\n");
	printf("*************0.退    出*************\n");
	printf("************************************\n");
}

void StartGame()  // 开始游戏
{
	srand(time(NULL));     // 用时间戳设置随机数种子
	int random = rand();   // 获取一个随机数
	random = random % 101; // 让随机数的值在0--100之间
	int count = 0;         // 记录猜测次数
	while (1)
	{
		int guess;
		printf("请输入你猜测的数字:");
		scanf("%d", &guess);
		if (guess > random)      // 大于
		{
			printf("猜大了\n");
			count++;
		}
		else if (guess < random) // 小于
		{
			printf("猜小了\n");
			count++;
		}
		else                     // 等于
		{
			count++;
			printf("恭喜你,猜中了\n");
			printf("共猜了 %d 次\n", count);
			break;
		}
	}
}

int Select()
{
	int select;
	printf("请选择:");
	scanf("%d", &select);
	switch (select)
	{
	case 1: //开始游戏-----------------------------------
		StartGame();
			//开始游戏-----------------------------------
		break;
	case 0: // 退出
		return 0;
	default:// select既不是1也不是0,即一个非法的输入
		printf("非法的输入,请重新选择\n");
	}
}

int main()
{
	while (1)
	{
		//游戏菜单---------------------------------------------
		PrintMune();
		//游戏菜单---------------------------------------------

		//选择------------------------------------------------
		int select = Select();
        if(select == 0)
        {
            return 0;
        }
		//选择------------------------------------------------
	}
	return 0;
}

        这样代码就改好了。

        像这样使用多个函数将代码分区的方式叫 解耦,解耦有几个好处:

        1、每个函数各自执行其功能,互不影响

        2、main 函数中可以清晰的知道代码执行的大体逻辑

        3、如果代码出了问题,可以将问题定位到某个函数中,更容易发现和修改

下期预告:

        下一次是加餐,主要内容如下:

        1、作用域与 static 关键字

        2、函数的链式访问 和 递归

传送门:C语言-第三章-加餐:static关键字与函数递归、链式访问

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值