《嵌入式C语言笔记(十二):二维数组传参、作用域与生存期全解析》

今日学习内容

1. 二维数组作为函数参数
(1) 参数传递规则
  • 整型二维数组:必须显式传递行数和列数
// 函数声明
void process_matrix(int mat[][4], int rows);  // 列数必须显式指定
// 调用示例
int arr[3][4] = {0};
process_matrix(arr, 3);

  • 字符型二维数组
void print_strings(char str[][20], int count);  // 每行最多19字符+'\0'

(2) 内存视角
  • 数组名传递:实际传递的是首行地址(等价于&arr[0][0]
  • 行数计算:必须在主调函数中计算后传递
int rows = sizeof(arr)/sizeof(arr[0]);
int cols = sizeof(arr[0])/sizeof(arr[0][0]);

2. 标识符作用域与可见性
(1) 作用域分类
类型范围示例
局部作用域函数内部或代码块{}函数形参、局部变量
全局作用域从定义处到文件结束全局变量、函数名
(2) 核心规则

        先定义后使用

printf("%d", num);  // 错误!
int num = 10;

        同作用域禁止重名

int x = 5;
float x = 3.14;  // 编译错误

        无包含关系作用域

void func1() { int a=1; }
void func2() { int a=2; }  // 合法,互不影响

        包含关系作用域

int a = 10;
void func() {
    int a = 20;
    printf("%d", a);  // 输出20(外层a被屏蔽)
}

3. 变量生存期
(1) 静态生存期
  • 包含对象:全局变量、static修饰的变量
  • 特性
    • 程序启动时创建,结束时销毁
    • 未初始化时自动赋0值
    • static的两种用途:
static int count = 0;     // 限制作用域到本文件
void func() {
    static int calls = 0; // 保留值且仅在函数内可见
}

(2) 动态生存期
  • 包含对象auto局部变量(默认)
  • 特性
    • 进入作用域时创建,离开时销毁
    • 未初始化时值为随机垃圾数据
(3) 存储类别关键字
关键字作用示例
auto默认局部变量(可省略)auto int x;
register建议编译器将变量存入寄存器register int i;
static延长生命周期或限制作用域static int counter;
extern声明外部定义的变量extern int global_var;
4.练习
        1.二维整型数组相关练习
int sum0Array2DEdge(int a[][4],int rows)//边缘求和
{
    int cols = sizeof(a[0]) / sizeof(a[0][0]);
    int i,j;
    int sum =0;

    for(i = 0;i < rows;++i)
    {
        for(j = 0;j < cols;++j)
        {
            if(i == 0 || j == 0 || i == rows - 1 || j == cols -1)
            {
                sum += a[i][j];            
            }
        }
    }
    return sum;
}

void printArray2D(int a[][4],int rows) //遍历输出
{
    int cols = sizeof(a[0]) / sizeof(a[0][0]);
    int i,j;
    int sum =0;

    for(i = 0;i < rows;++i)
    {
        for(j = 0;j < cols;++j)
        {
            printf("%2d ",a[i][j]);            
        }
        puts("\n");
    }
}

void reverse(int a[],int len)//一维数组翻转
{
    int i;
    for(i = 0;i < len / 2;++i)
    {
        int t = a[i];
        a[i] = a[len - i - 1];
        a[len - i - 1] = t;
    }
}

void reverse2D(int a[][4],int rows)//水平翻转
{
    int i,j;
    int cols = sizeof(a[0]) / sizeof(a[0][0]);

    for(i = 0;i < rows;++i)
    {
        reverse(a[i],cols);
    }
}

void advArray2D(int a[][4],int b[],int rows)//每一行平均值
{
    int i = 0,j = 0;
    for(i = 0;i < rows;++i)
    {
        int sum = 0;
        for(j = 0;j < 4;++j)
        {    
            sum += a[i][j];
        }
        sum = sum / 4;
        b[i] = sum;
    }
}

int main(void)
{
    int a[][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
    int sum = 0;
    int rows = sizeof(a) / sizeof(a[0]);
    
    //printArray2D(a,rows);
    //sum = sum0Array2DEdge(a,rows);
    //printf("%d\n",sum);

    //reverse2D(a,rows);
    //printArray2D(a,rows);
    
    
    int b[3];
    advArray2D(a,b,rows);
    int i;
    for(i = 0;i < 3;++i)
    {
        printf("%d\n",b[i]);
    }

    return 0;
}
        2.二维字符型数组相关练习
#include <string.h>

void printStrings(char s[][100],int rows)//遍历输出
{
    int i;
    for(i = 0;i < rows;++i)
    {
        puts(s[i]);
    }
}

void reverseStrings(char s[][100],int rows)//逆序
{
    int i;
    for(i = 0;i < rows / 2;++i)
    {
        char t[100];
        strcpy(t,s[i]);
        strcpy(s[i],s[rows - i - 1]);
        strcpy(s[rows - i - 1],t);
    }
}

void sortStrings(char s[][100],int rows)//插入排序
{
    int i,j;
    for(i = 0;i < rows - 1;++i)
    {
        for(j = i + 1;j < rows;++j)
        {
            if(strcmp(s[i],s[j]) > 0)
            {
                char t[100];
                strcpy(t,s[i]);
                strcpy(s[i],s[rows - i - 1]);
                strcpy(s[rows - i - 1],t);
            }
        }
    }
}

void maxOfStrings(char s[][100],int rows,char max[])//极值
{
    strcpy(max,s[0]);
    int i;
    for(i = 1;i < rows;++i)
    {
        if(strcmp(max,s[i]) < 0)
        {
            strcpy(max,s[i]);
        }
    }
}

int binaryFindStrings(char s[][100],int rows,char n[])
{
    int begin = 0;
    int end = rows - 1;
    int mid;
    while(begin <= end)
    {
        mid = (begin + end) / 2;
        if(strcmp(s[mid],n) > 0)
        {
            end = mid - 1;
        }
        else if(strcmp(s[mid],n) < 0)
        {
            begin = mid + 1;
        }
        else
        {
            break;
        }
    }
    if(begin <= end)
    {
        return 1;
    }
    else
    {
        return -1;
    }
}

int main(void)
{
    char s[][100] = {"Hello","World","China"};
    char max[100];
    char n[100] = "China";
    int rows = sizeof(s) / sizeof(s[0]);
   
    //maxOfStrings(s,rows,max);
    //puts(max);

    //reverseStrings(s,rows);
    //printStrings(s,rows);

    //sortStrings(s,rows);
    //printStrings(s,rows);

    sortStrings(s,rows);
    int i = binaryFindStrings(s,rows,n);
    if(i > 0)
    {
        printf("Found\n");
    }
    else
    {
        printf("Eroor\n");
    }
    return 0;
}

5. 开发技巧
(1) Vim操作
  • 解除鼠标限制:set mouse=a
  • 分屏编辑
:vsp fun.c    " 垂直分屏
:sp test.h    " 水平分屏

(2) 多文件编译
  • 头文件声明
// mylib.h
#ifndef MYLIB_H
#define MYLIB_H
extern void my_func();  // 声明函数
#endif

  • 编译命令
gcc main.c lib.c -o app  # 联合编译多个.c文件
6.日历

详情在下面代码

https://gitcode.com/weixin_72612809/rili

总结

  1. 二维数组传参:必须显式传递维度信息(列数/行数)
  2. 作用域规则:严格遵循"就近原则",合理使用static控制可见性
  3. 生存期管理
    • 全局/静态变量:长期存在但增加内存占用
    • 局部变量:高效但需注意生命周期
  4. 嵌入式优化
    • 慎用register(现代编译器自动优化)
    • 多文件开发优先使用头文件

关联知识:结合指针理解二维数组的内存布局

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值