首页 > 其他分享 >嵌入式初学-C语言-十七

嵌入式初学-C语言-十七

时间:2024-08-07 22:27:22浏览次数:9  
标签:全局变量 函数 形参 int 嵌入式 初学 数组 printf C语言

#接嵌入式初学-C语言-十六#

函数的递归调用

含义:

在一个函数中直接或者间接调用了函数本身,称之为函数的递归调用

// 直接调用
    a()->a();
// 间接调用
    a()->b()->a();
    a()->b()->..->a();

递归调用的本质:

本是是一种循环结构,它不同于之前所学的while,do-while,for这样的循环结构,这些循环结构是借助循环变量,而递归是利用了函数自身实现循环结构,如果不加以控制,很容易产生死循环

递归调用的注意事项:

  1. 递归调用必须要有出口,一定要终止递归,否则会产生死循环
  2. 对终止条件的判断一定要放在函数递归之前。
  3. 进行函数的递归调用
  4. 函数递归调用的同时一定要将函数调用向出口逼近

案例1: 

/**
* 需求:递归案例-有5个人坐在一起,问第5个人多少岁?他说比第4个人大2岁。
       问第4个人岁数,他说比第3个人大2岁。
       问第3个人,又说比第2个人大2岁。
       问第2个人,说比第1个人大2岁。
       最后问第1个人,他说是10岁。请问第5个人多大。
*/
#include <stdio.h>
/* 求年龄的递归函数 */

int age(int n)
{
    // 存放函数的返回值,也就是年龄
    int c;
    if(n == 1)
    {
        c = 10;// 第一个人的年龄是10岁
    }
    else if(n > 1)
    {
        c = age(n-1)+2; // 当前这个人的年龄 = 上一个人的年龄+2
    }
    return c;
}

int main()
{
    printf("%d\n",age(5));

    return 0;
}

 案例2:

/**
* 需求:递归案例-求阶乘(n!)
*/
#include <stdio.h>

/* 编写一个函数,用来求阶乘 */
long fac(int n)
{
    // 因为int型表示的数据范围小,所以乘法操作我们使用long来接收计算结果
    long f;
    if(n < 0)
    {
        printf("n的范围不能是0以下的数!\n");
    }
    else if(n == 0 || n==1) // 此时不满足阶乘条件
    {
        f = 1;
    }
    else
    {
        f = fac(n-1)*n;
    }

    return f;
}

int main()
{
    int n;
    printf("请输入一个整数:\n");
    scanf("%d",&n);

    printf("%d!=%ld\n",n,fac(n));

    return 0;
}

 

数组作为函数参数

注意:

  1. 当用数组做函数的实际参数时,则形参应该也要用数组/指针变量来接收,但请注意,此次并不代表传递了数组中所有元素数据,而是传递了第一个元素的内存地址(数组首地址),形参接收这个地址后,形参和实参就代表了同一块内存空间,则形参的数据修改会改变实参的,这种数据传递方式我们可以称之为引用传递
  2. 如果用数组做函数的形式参数,那么我们提供另一个形参表是数组的元素个数,原因是数组形参代表的仅仅是实际数组的首地址,也就是说形参只获取到了实际数组元素的开始,并未获取到元素的结束,所以提供另一个形参,表示数组的元素个数,可以防止在被调函数对实际数组元素访问的越界
  3. 但有一个例外如果是以字符数组做形参,且实际数组中存放的是字符串数据(形参是字符数组,实参是字符串)则不用表示数组元素个数的形参,原因是字符串本身会自带结束符\0

 案例-数组元素做函数实参:

/**
* 需求:数组为参数案例-有两个数组a和b,各有10个元素,将它们对应元素逐个地相比(即a[0]与b[0]比,a[1]
与b[1]比……)。如果a数组中的元素大于b数组中的相应元素的数目多于b数组中元素大于a数组中相应元素的数目(例
如,a[i]>b]i]6次,b[i]>a[i] 3次,其中i每次为不同的值),则认为a数组大于b数组,并分别统计出两个数组相应元
素大于、等于、小于的个数。
*
*/
#include <stdio.h>

/* 定义一个函数,实现两个数的比较 */
int large(int x,int y)
{
    int flag;// 用来存放比较结果

    if(x > y) flag = 1;
    else if(x < y) flag = -1;
    else flag = 0;

    return flag;
}

int main()
{
    // 比较用的两个数组,循环变量,最大,最小,相等
    int a[10],b[10],i,max=0,min=0,k=0;

    printf("请给数组a添加十个整型数据:\n");
    for(i = 0;i < sizeof(a)/sizeof(int);i++)
    {
        scanf("%d",&a[i]);
    }
    printf("\n");
    printf("请给数组b添加十个整型数据:\n");
    for(i = 0;i < sizeof(b)/sizeof(int);i++)
        scanf("%d",&b[i]);
    printf("\n");

    // 遍历
    for(i = 0;i < sizeof(a)/sizeof(int);i++)
    {
        if(large(a[i],b[i])==1)
        {
            max++;
        }
        else if(large(a[i],b[i])==0)
        {
            k++;
        }
        else
        {
            min++;
        }
    }

    printf("max=%d,min=%d,k=%d\n",max,min,k);

    return 0;
}

案例2:

/**
* 需求:数组函数的参数案例-编写一个函数,用来分别求数组score_1(有5个元素)和数组score_2(有10个元素)
各元素的平均值 。
*/
#include <stdio.h>
/* 定义一个函数,用来求平均分 */
float avg(float scores[],int len)
{
    int i;// 循环变量
    float aver,sum = scores[0];// 保存平均分和总成绩
    // 遍历集合
    for(i = 1;i < len;i++)
    {
        sum += scores[i];
    }
    aver = sum / len;

    return aver;
}

int main()
{
    //准备俩测试数组
    float score_1[5] = {66,34,46,37,97};
    float score_2[10] = {77,88,66,55,65,76,87,98,75,34};

    printf("这个班的平均分是:%6.2f\n",avg(score_1,sizeof(score_1)/sizeof(float)));

    printf("这个班的平均分是:%6.2f\n",avg(score_2,sizeof(score_2)/sizeof(float)));

    return 0;
}

变量的作用域

引入问题

我们在函数设计过程中,经常要考虑对参数的设计,换句话说,我们需要考虑函数需要几个参数,需 要什么类型的参数,但我并没有考虑函数是否需要提供参数,如果说函数可以访问到已定义的数据, 则就不需要提供函数形参,那么我么到底要不要提供函数参数,取决于什么?答案就是变量的作用域 (如果函数在变量的作用域范围内,则函数可以直接访问数据)

变量的作用域

概念:变量的作用范围,也就是说变量在什么范围是有效的

变量的分类

根据变量的作用域不同,变量可分为全局变量和局部变量

局部变量

序号

局部变量

作用域

1

形式参数(形参)

函数作用域

2

函数内定义的变量

函数作用域

3

复合语句中定义的变量

块作用域

4

for循环表达式1定义的变量

块作用域

 全局变量

序号

全局变量

作用域

1

定义在函数之外的变量,也称为外部变量或全程变量

全局变量定义处到本源文件结束

 

建议在全局变量定义时初始化,如果不初始化,系统会将全局变量初始化为0

  1. 使用全局变量的优缺点

优点:

  1. 利用全局变量可以实现函数对外输出的多个结果数据
  2. 利用全局变量可以减少函数形参个数,从而降低内存消耗,以及因形参传递带来的时间消耗

        缺点

  1. 全局变量在整个程序运行期间,始终占据内存空间,会引起资源消耗
  2. 过多的全局变量会引起程序的混乱,造成程序结果错误
  3. 降低程序通用性,特别是当我们进行函数移植时,不仅仅要移植函数,还要考虑全局变量
  4. 违反了”高内聚,低耦合”的程序设计原则

总结:我们发现弊大于利,建议尽量减少对全局变量的使用,函数之间要产生联系,仅通过实参,形参的方式产生联系

作用域举例:

案例:

int p=1,q=5; /*外部变量p,q*/
float f1(int a) /*定义函数f1*/
{ int b,c;
…
}
char c1,c2; /*外部变量c1,c2*/
char f2 (int x, int y) /*定义函数f2*/
{ int i,j;
…
}
void main ( ) /*主函数*/
{ int m,n;
…
}

注意:

如果全局变量和局部变量同名,程序执行的时候就近原则 

int a = 10;
int main()
{
int i = 20;
printf("%d\n",a); // 20 就近原则
for(int i = 0;i < 5; i++)
{
printf("i=%d ",i); // 0 1 2 3 4 就近原则
}
}

标签:全局变量,函数,形参,int,嵌入式,初学,数组,printf,C语言
From: https://blog.csdn.net/MaBaB/article/details/141002560

相关文章

  • 【C语言常见函数】格式化输入与字符串处理函数汇总
    格式化输出sprintf()、printf()和fprintf()功能上有本质区别,分别用于向字符串缓冲区、终端和文件输出格式化的数据!简介printf():printf()是C标准库中的函数,用于向标准输出流(通常是终端)输出格式化数据。格式:intprintf(constchar*format,...)通过printf()函数......
  • C语言入门基础题:最大公约数(三个数间取最大公约数)
    1.题目描述输入三个正整数x,y,z,求它们的最大公约数(GreatestcommonDivisor)g:最大的正整数g>=1满足x,y,z都是g的倍数,即(x modg)=(ymodg)=(zmodg)=0。2.输入格式输入一行三个正整数x,y,z。3.输出格式输出一行一个整数g,表示x,y,z的最大公约数,4.输入......
  • 用C语言实现输入一个奇数n,输出一个由*构成的n阶实心菱形
    样图示例:一.基本思路该问题的主要难点时是如何使用循环通过人为输入的指定长度来确定空格和星号的输出,我的想法是将图形以中间最长的一条线分为上下部分,然后分别用不同的变量来表示空格和星号的输出,最后通过c语言来实现对图形颜色和闪烁的控制。二.具体实现1.上半部分......
  • 字符串左旋(c语言)
    1.字符串左旋//实现一个函数,可以左旋字符串的k个字符例如:ABCD左旋字符串的1个字符BCDA     ABCD左旋字符串的2个字符CDAB2.第一步我们先输入k(scanf),将第一位进行储存,然后其他位先前走一位,然后将第一位放在最后,然后进行打印。方法一#include<stdio.h>voidtest......
  • C语言实现猜数字小游戏
    游戏要求:1.电脑自动生成1-100的随机数2.玩家猜数字,猜数字的过程中,根据猜测数据的大小给出大了还是小了的反馈,直到猜对游戏结束1.随机数的生产C语言提供了一个函数叫rand,这个函数可以生产随机数,函数的原型如下所示:rand函数会返回一个伪随机数,这个随机数的大小是在0-32767(......
  • 音频应用编程-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板
    音频应用编程Linux下ALSA框架概述ALSA简介:ALSA是AdvancedLinuxSoundArchitecture(高级的Linux声音体系)的缩写地位与功能:现已成为Linux下的主流音频体系架构,提供音频和MIDI支持,替代了旧版本中的OSS(开放声音系统)框架设计:ALSA是Linux系统下标准且先进的......
  • C语言随机数的生成
    目录前言一、 随机数⽣成1.rand2.srand 3.time4.设置随机数的范围 总结前言我们在前面已经学到了分支和循环结果,掌握了前面的知识,我们已经可以写一点有趣的代码了一、 随机数⽣成要想完成猜数字游戏,⾸先得产⽣随机数,那怎么产⽣随机数呢?1.randC语⾔提供了⼀......
  • C语言 操作符详解
    目录一、操作符的分类二、二进制和进制转换 2.1二进制转十进制 2.2二进制转八进制 2.3二进制转十六进制 三、原码、反码、补码四、移位操作符4.1左移操作符​编辑 4.2右移操作符五、位操作符按位与:&按位或:|按位异或:^按位取反:~六、逗号表达式七、操作......
  • 《重生到现代之从零开始的C语言生活》—— 调试
    前言:调试是几乎每一个计算机行业的人员必备的技能,那么让我们来学习一下吧bugbug这个词好像出现在生活的很多地方,一般指在电脑系统中或程序中,隐藏着一些未被发现的缺陷和问题,简称程序漏洞调试(debug)我们发现bug后,下一步就是找到问题并修复问题,找问题的过程就是调试调试一......
  • 《重生到现代之从零开始的C语言生活》——函数递归
    递归啥是递归啊递归是解决问的一种方式,简单来说,就是函数自己调用自己递归解决问题把复杂的大问题转化为一个一个与原文题相似的小问题。递归的思想就是把大事化小在递归中,递就是递推,归就是回归递归中的限制条件递归必须存在限制条件,当满足这个条件时,递归不在继续每次......