嵌入式学习 c语言_函数

1.函数的作用

  • 避免重复性代码
  • 让程序更加模块化

2.函数的三种形式

函数的定义、函数的调用、函数的声明

1.函数的定义

定义一个函数的实现

1.定义形式

函数类型 函数名(数据类型1 形式参数1, 数据类型2 形式参数2, 数据类型3 形式参数3,
...)

{
    函数体;

    return 返回值;
}

int fun(int x, int y)
{
    函数体;

    return 0;
}

函数类型:函数运行结果的类型 int void char double float
函数名:与变量名要求保持一致
形式参数:对数据操作的方式(函数定义时形参必须有类型)
返回值:函数的运行结果

2.函数的调用

使用形式

函数名(实参1, 实参2);

该表达式最终结果为函数return后面的值

该表达式最终类型为函数类

示例

int add(int a, int b) {
    return a + b;
}

int main() {
    int result = add(3, 5);  // 传递两个整数参数
    printf("Result: %d\n", result);
    return 0;
}
 
  • 主调函数:主动调用别的函数的函数称为主调函数

  • 被调函数:被主调函数调用的函数称为被调函数

3.函数的声明

在C语言中,函数声明(也称为函数原型)用于告诉编译器函数的存在及其参数和返回类型,通常出现在函数定义之前。

声明方式:
如果被调函数在主调函数的下方定义需要再主调函数上方声明
如果被调函数在主调函数的上方定义,定义时已经完成函数的声明

return_type function_name(parameter_list);
 
  • return_type:函数返回值的数据类型(如intfloatvoid等)。

  • parameter_list:参数类型和名称(可选),多个参数用逗号分隔。

示例

// 头文件 math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H

int add(int x, int y);       // 声明加法函数
double sqrt(double value);   // 声明平方根函数

#endif

// 源文件 main.c
#include "math_utils.h"
#include <stdio.h>

int main() {
    printf("Sum: %d\n", add(3, 5));
    return 0;
}
 

3.变量的作用域和生存周期

在C语言中,变量的作用域和生存周期由存储类别(autostaticregisterextern)和声明位置(全局或局部)决定。以下是分类总结:


1. 局部变量(自动变量)
  • 声明方式: 在函数或块内声明,默认为auto(可省略)。
  • 作用域: 仅限于声明它的函数或块内。
  • 生存周期: 从进入函数或块时创建,到退出时销毁。
  • 示例:
    void func() {
        int x = 10; // 局部变量
    }
    


2. 静态局部变量
  • 声明方式: 在函数或块内用static修饰。
  • 作用域: 仅限于声明它的函数或块内。
  • 生存周期: 程序运行时创建,程序结束时销毁(仅初始化一次)。
  • 示例:
    void func() {
        static int count = 0; // 静态局部变量
    }
    


3. 全局变量
  • 声明方式: 在函数外声明,默认为extern(可省略)。
  • 作用域: 从声明处到文件末尾,其他文件通过extern引用。
  • 生存周期: 程序运行时创建,程序结束时销毁。
  • 示例:
    int global = 100; // 全局变量
    void func() {
        extern int global; // 引用其他文件的全局变量
    }
    


4. 静态全局变量
  • 声明方式: 在函数外用static修饰。
  • 作用域: 仅限于当前文件(不可被其他文件extern引用)。
  • 生存周期: 程序运行时创建,程序结束时销毁。
  • 示例:
    static int file_scope = 200; // 静态全局变量
    


5. 寄存器变量
  • 声明方式: 用register修饰(建议编译器将变量存储在寄存器中)。
  • 作用域: 与局部变量相同(仅限于声明它的块内)。
  • 生存周期: 与局部变量相同(块结束时销毁)。
  • 示例:
    void func() {
        register int i; // 寄存器变量
    }
    


总结表格
变量类型作用域生存周期存储类别
局部变量函数/块内函数/块执行期间auto
静态局部变量函数/块内整个程序运行期间static
全局变量文件或跨文件整个程序运行期间extern
静态全局变量当前文件内整个程序运行期间static
寄存器变量函数/块内函数/块执行期间register

关键区别
  • 静态变量static)的生存周期为整个程序运行期间,但作用域取决于声明位置。
  • 全局变量默认跨文件可见,而静态全局变量仅限当前文件。
  • 寄存器变量是局部变量的优化建议,实际是否存入寄存器由编译器决定。
6.代码运行时,内部空间分配
C语言程序运行时内存空间分配

C语言程序在运行时,内存通常分为以下几个主要区域,其分配方式和管理特点如下:

内存区域存储内容生命周期分配/释放方式典型大小限制
代码区编译后的机器指令(二进制代码)整个程序运行期间编译器/操作系统静态分配由系统剩余内存决定
全局/静态区全局变量、静态变量(static修饰)整个程序运行期间编译时固定地址系统限制(通常较大)
常量区字符串常量、const全局变量整个程序运行期间编译器分配系统限制
栈区局部变量、函数参数、返回地址函数调用开始到结束编译器自动管理较小(Linux默认8MB,Windows1MB)
堆区动态分配内存(malloc/calloc等)程序员控制(free释放前持续存在)手动分配/释放受系统虚拟内存空间限制


4.递归函数

递归函数是指在函数体内调用自身的函数。递归通常用于解决可以分解为相似子问题的情况,例如阶乘、斐波那契数列、汉诺塔等问题。递归函数需要满足两个条件:

  • 基线条件(Base Case):递归终止的条件,防止无限递归。
  • 递归条件(Recursive Case):函数调用自身,逐步向基线条件靠近

递归函数的实现示例

示例1:计算阶乘
#include <stdio.h>
  
  int fun (int num)
  {
      if (1 == num)
      {
          return 1;
      }
      else
      {
          return num * fun (num - 1);                                                                                                                                              
      }
  }
  
 
  int main(void)
  {
      int ret = 0;
      int a = 0;
  
      scanf("%d",&a);
  
      ret = fun(a);
 
      printf("ret = %d\n",ret);
      return 0;
  }
示例二:汉诺塔

1 #include <stdio.h>
  2 
  3 int hannuota(int n,char A,char B,char C)
  4 {
  5     if(1 == n)
  6     {
  7         printf("%c -> %c\n",A,C);
  8     }
  9     else
 10     {
 11         hannuota(n-1,A,C,B);
 12         printf("%c -> %c\n",A,C);
 13         hannuota(n-1,B,A,C);
 14     }
 15 
 16     return 0;                                                                                                                                                                    
 17 }
 18 
 19 int main(void)
 20 {
 21     int n = 0;
 22 
 23     printf("请输入有多少个盘子:");
 24 
 25     scanf("%d",&n);
 26 
 27     hannuota(n,'A','B','c');
 28 
 29     return 0;
 30 }

5.函数传参

1.值传递


函数调用时,将实参的值复制一份传给形参。形参是实参的副本,修改形参不会影响实参。

void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}
int main() {
    int x = 1, y = 2;
    swap(x, y);  // x和y的值不会被交换
}
 

2.整型数组传递

1.两种形式

int fun(int array[5]);
int fun(int array[], int len);

注意:数组传递到函数体内部与外部操作的是同一数组

示例

#include <stdio.h>
 

 
 int sortfun(int a[],int len)
  {
     int j = 0;
     int i = 0;
 27     int tmp = 0;
 28     for(j = 0;j < len - 1;j++)
 29     {
 30         for(i = 0;i < len - 1- j;i++)
 31         {
 32             if(a[i] > a[i+1])
 33             {
 34                 tmp = a[i];
 35                 a[i] = a[i + 1];
 36                 a[i + 1] = tmp;
 37             }
 38         }
 39     }
 40     return 0;
 41 }
 42 
 43 int putfun(int a[],int len)
 44 {
 45     int i = 0;
 46     for(i = 0;i < len;i++)
 47     {
 48         scanf("%d",&a[i]);
 49     }
 50 }
 51 
 52 int dayin(int a[],int len)
 53 {
 54     int i = 0;
 55     for(i = 0;i < len;i++)
 56     {
 57         printf("a[%d] = %d ",i,a[i]);
 58     }
 59     printf("\n");
 60     return 0;
 61 }
 62 int main(void)
 63 {
 64     int num[5] = {0};
 65     putfun(num,sizeof(num)/sizeof(num[0]));
 66     sortfun(num,sizeof(num)/sizeof(num[0]));
 67     dayin(num,sizeof(num)/sizeof(num[0]));
 68    
 73 
 74     return 0;
 75 }
         

3.字符型数组传递

int fun(char str[]);

示例

封装strlen功能

1 #include <stdio.h>
  2 
  3 int getstrlen(char fstr[])                                                                                                                                                       
  4 {
  5     int i = 0;
  6     while(fstr[i] != '\0')
  7     {
  8         i++;
  9     }
 10     return i;
 11 }
 12 
 13 int main(void)
 14 {
 15     int len = 0;
 16     char str[32] = {0};
 17 
 18     gets(str);
 19 
 20     len = getstrlen(str);
 21 
 22     printf("len = %d\n",len);
 23 
 24     return 0;
 25 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值