首页 > 其他分享 >嵌入式基础 C语言篇 数组.初阶

嵌入式基础 C语言篇 数组.初阶

时间:2025-01-18 20:28:44浏览次数:3  
标签:初阶 int 嵌入式 地址 内存 数组 printf C语言 buf

一、基本概念

  • 逻辑:一次性定义多个相同类型的变量,并存储到一片连续的内存中
  • 语法释义:
    int buf[5];
  • buf是数组名,即这片连续内存的名称
  • [5] 代表这片连续内存总共分成5个相等的格子,每个格子称为数组的元素
  • int 代表每个元素的类型,可以是任意基本类型,也可以是组合类型,甚至可以是数组
  • 初始化:在定义的时候赋值,称为初始化
int buf[5] = {100,200,300,400,500};        // ok,正常初始化

 

  • 图解:

通过buf+1得出的的地址,可以知晓buf的作用范围是多少

数组里面的元素的内存都是相邻的(也就是数组是一片连续的内存构成的)

#include <stdio.h>
int main(int argc, char const *argv[])
{
    // (1)、一次性定义多个相同类型的变量 --- 语法释义(数组演化史 --- 带入创作者的角度去看看)
    // 1、为什么要像下面的这种写法呢??(a、名字要有意义; b、名字会冲突; c、需要的名字越来越多)
    // a、以往的写法:
    int num1 = 100;
    int num2 = 200;
    int num3 = 300;


    // b、现有的写法:
    int num[100];       // 想象中的:100 int num;
    num[0];             // 如何表示数组的元素(从0开始到100-1)
    // ...
    num[99];

    // (2)、 存储到一片连续的内存中
    // 1、num1、num2、num3其实他们三个变量的内存也是连续存储的(如何证明:打印其地址即可)
    printf("num1的地址 == %p\n", &num1);            // &符号是取变量的地址的意思
    printf("num2的地址 == %p\n", &num2); 
    printf("num3的地址 == %p\n", &num3); 
    /*
        地址分析:
            num1的地址 == 0x7ffc85bc4294            
            num2的地址 == 0x7ffc85bc4298
            num3的地址 == 0x7ffc85bc429c

        说明:1个地址 == 1个字节,所以以上三个变量是相邻的
    */

    // 2、数组在内存中的说明
    int buf[5]  = {100, 200, 300, 400, 500};
    // A、数组的元素在一片连续的内存中
    printf("buf[0]内存的值 == %d, buf[0]的地址 == %p\n", buf[0], &buf[0]);
    // printf("buf[0]+1的地址 == %p\n", &buf[0]+1);
    printf("buf[1]内存的值 == %d, buf[1]的地址 == %p\n", buf[1], &buf[1]);
    printf("buf[2]内存的值 == %d, buf[2]的地址 == %p\n", buf[2], &buf[2]);
    printf("buf[3]内存的值 == %d, buf[3]的地址 == %p\n", buf[3], &buf[3]);
    printf("buf[4]内存的值 == %d, buf[4]的地址 == %p\n", buf[4], &buf[4]);
    /*
        内存值、地址解析:
            buf[0]内存的值 == 100, buf[0]的地址 == 0x7fff52e71d80
            buf[1]内存的值 == 200, buf[1]的地址 == 0x7fff52e71d84
            buf[2]内存的值 == 300, buf[2]的地址 == 0x7fff52e71d88
            buf[3]内存的值 == 400, buf[3]的地址 == 0x7fff52e71d8c
            buf[4]内存的值 == 500, buf[4]的地址 == 0x7fff52e71d90

        每个数组元素(int型),相隔4个地址,也就是4个字节,所以可以证明
        数组里面的元素的内存都是相邻的(也就是数组是一片连续的内存构成的)
    */
    
    // B、buf是数组名,即这片连续内存的名称(也表示数组首元素的地址)
    // a、buf代表的地址
    printf("buf代表的地址   == %p\n", buf);
    // b、buf的作用范围(如何求一个地址的作用范围???让其+1,并将其和原先的地址进行比较即可)
    printf("buf+1代表的地址 == %p\n", buf+1);
    /*
        解析:
            buf代表的地址:   0x7fff52e71d80 
            buf+1代表的地址:  0x7fff52e71d84
            所以可以得出buf的作用范围是4个字节,它和&buf[0]是相等的
    */

    // c、&buf的作用范围
    printf("&buf代表的地址     == %p\n", &buf);
    printf("&buf+1代表的地址   == %p\n", &buf+1);
    /*
        解析:
            buf代表的地址:   0x7fff52e71d80 
            buf+1代表的地址:  0x7fff52e71d94   
            
            所以可以得出&buf代表的作用范围是20个字节(刚好就是整个数组的大小)
    */

    // (3)、数组的初始化:
    int buf1[5] = {100, 200, 300, 400, 500};            // ok,正常初始化
    // int buf2[5] = {100, 200, 300, 400, 500, 600};    // 不ok,越界了(会报一个警告: warning: excess elements in array initializer)
    int buf3[5] = {100,200,300};                        // ok,只初始化数组元素的一部分
    int buf4[]  = {100,200,300};                        // ok,自动根据初始化列表分配数组元素个数

    return 0;
}

 

二、数组元素的赋值和引用

  • 存储模式:一片连续的内存,按数据类型分割成若干相同大小的格子
  • 元素下标:数组开头位置的偏移量,a[0]引用第1个格子,a[1]引用第2个格子,以此类推
  • 元素下标偏移量

  • 示例代码:
    #include <stdio.h>
    // 计算数组元素的个数
    #define CAL_ARR_NUM(A) (sizeof(A)/sizeof(A[0]))
                            // 整个数组的大小 / 数组的首元素的大小 == 数组元素个数
    
    // 主函数
    int main(int argc, char const *argv[])
    {
        // 初始化
        int  buf1[5] = {1,2,3,4,5};             // int型数组的12345,和char型数组(字符串)的"12345"是不一样的    
        char buf2[5] = {'1','2','3','4','\0'};  // 等价于 char buf2[5] = "1234";
        
        // (1)、单个赋值
        buf1[0] = 100;
        buf1[1] = 200;
        buf1[2] = 300;
        buf1[3] = 400;
        buf1[4] = 500;
        // buf1[5] = 600;      // 到此为止,后面的内存是非法区域(也就是你没有权限对其进行操作)
    
        printf("buf[5] == %d\n", buf1[5]);
    
        // (2)、循环赋值
        unsigned long int ret = CAL_ARR_NUM(buf2);
        printf("数组buf2的元素个数 == %lu\n", ret);
    
        for (int i = 0; i < ret; i++)
        {
            buf2[i] = 'A'+i;
            printf("buf2[%d] == %c\n", i, buf2[i]);
        }
        
    
    
        return 0;
    }

    三、其它类型的数组

    (1)、多维数组

  • 概念:若数组元素类型也是数组,则该数组称为多维数组
  • 语法:
    int buf[2][3];    // 相当于int [3] buf[2];
  • 图解:
  • 示例代码:
    #include <stdio.h>
    int main(int argc, char const *argv[])
    {
        // 一、二维数组
        int buf[2][3] = {{1,2,3},{4,5,6}};
    
        // (1)、二维数组各个地址的表示说明(推导)
        // 1、&buf的作用范围
        printf("\n");
        printf("&buf代表的地址   == %p\n", &buf);
        printf("&buf+1代表的地址 == %p\n", &buf+1);
        /*
            解析(本地址和后面的地址不相干,是之前编译分配的地址):
                &buf代表的地址   == 0x7fff037540c0
                &buf+1代表的地址 == 0x7fff037540d8
            说明:c到d == 16, 0到8 == 8, 总:24字节
        */
    
        // 2、buf的作用范围
        printf("\n");
        printf("buf代表的地址   == %p\n", buf);
        printf("buf+1代表的地址 == %p\n", buf+1);
    
        printf("\n");
        printf("&buf[0]代表的地址   == %p\n", &buf[0]);
        printf("&buf[0]+1代表的地址 == %p\n", &buf[0]+1);
        /*
            解析(本地址和后面的地址不相干,是之前编译分配的地址):
    
            buf代表的地址       == 0x7fff24d28480
            buf+1代表的地址     == 0x7fff24d2848c
    
            &buf[0]代表的地址   == 0x7fff24d28480
            &buf[0]+1代表的地址 == 0x7fff24d2848c
    
            说明:0到c == 12, 总:12字节
        
        */
    
        // 3、buf[0]的作用范围
        printf("\n");
        printf("buf[0]代表的地址   == %p\n", buf[0]);
        printf("buf[0]+1代表的地址 == %p\n", buf[0]+1);
    
        printf("\n");
        printf("&buf[0][0]代表的地址   == %p\n", &buf[0][0]);
        printf("&buf[0][0]+1代表的地址 == %p\n", &buf[0][0]+1);
        /*
            解析(本地址和后面的地址不相干,是之前编译分配的地址):
    
            buf[0]代表的地址   == 0x7ffc5d50d2f0
            buf[0]+1代表的地址 == 0x7ffc5d50d2f4
    
            &buf[0][0]代表的地址   == 0x7ffc5d50d2f0
            &buf[0][0]+1代表的地址 == 0x7ffc5d50d2f4
    
            说明:0到4 == 4, 总:4字节
        
        */
    
        // 4、buf[1]的作用范围
        printf("\n");
        printf("buf[1]代表的地址   == %p\n", buf[1]);
        printf("buf[1]+1代表的地址 == %p\n", buf[1]+1);
        /*
            解析(本地址和后面的地址不相干,是之前编译分配的地址):
    
            buf[1]代表的地址   == 0x7ffc8c006c2c
            buf[1]+1代表的地址 == 0x7ffc8c006c30
    
            说明:2c到30 == 4, 总:4字节
        
        */
    
        return 0;
    
    }

    (2)、字符数组

  • 概念:专门存放字符的数组,称为字符数组
  • 示例代码:
    #include <stdio.h>
    int main(int argc, char const *argv[])
    {
        // 二、字符数组
        // (1)、字符串数组的初始化
        char s1[5] = {'a', 'b', 'c', 'd', 'e'};             // 字符数组,不是字符串(末尾没有'\0')(字符串是一个特殊的字符数组)
        char s2[5] = {'a', 'b', 'c', 'd', '\0'};            // 它既是字符数组,又是字符串
    
        char s3[5] = {"nihao"};                             // 字符数组(末尾没有'\0')
        // printf("%s\n", s3);                              // 此处因为没有'\0',有可能打印不出数据来
        char s4[5] = {"niha"};                              // 字符串(末尾有'\0')
        char s5[5] = "niha";                                // 字符串的简写
    
        // (2)、字符串数组的赋值和引用
        // a、字符数组的赋值和引用和前面的普通数组的赋值一样(为什么?因为char型本质上就是单字节的int整型)
        // b、字符串的赋值,可以使用字符串处理函数(str开头的函数)
         //  栈区(可读可写)   常量区(可读不可写)
        char s6[256] =  "吾爱有三,日月与卿,日为朝,月为暮,卿为朝朝暮暮"; // 初始化
        printf("s6 == %s\n", s6);
    
        // 使用strcpy函数对字符串数组进行赋值
        bzero(s6, sizeof(s6));                  // 将s6数组清零(清sizeof(s6)这么大的空间)
        
        //  将常量区的数据,复制到栈区中(s6),后面修改s6的值,修改是栈区s6的值
        strcpy(s6, "世界那么大,我想带你去看看");
        printf("s6 == %s\n", s6);
    
        // 题:
        // 栈区(可读可写)  常量区(可读不可写)   
        char *s7    = "nihao,shijie";
        // 将常量区("世界...")的数据,通过s7指针复制到另一个常量区""nihao.."
        // strcpy(s7, "世界那么大,我想带你去看看");   // Segmentation fault (core dumped)
        
        return 0;
    }

    四、数组语法解析

  • 任意的数组,不管有多复杂,其定义都由两部分组成。
    • 第1部分:说明元素的类型(type),可以是任意的类型(除了函数)
    • 第2部分:说明数组名(x)和元素个数(N)
  • 示例代码:
  • int a[4];               // 第一部分:int(元素的类型), 第二部分:a[4](数组名+元素个数)
    int b[3][4]:            // 第一部分:int [4](元素的类型), 第二部分:b[3](数组名+元素个数)
    int c[2][3][4];         // 第一部分:int [3][4](元素的类型), 第二部分:c[2](数组名+元素个数)
    int *d[6];              // 第一部分:int *(元素的类型), 第二部分:d[6](数组名+元素个数)
    int (*e[7])(int,char);  // 第一部分:int (*)(int,char)(元素的类型), 第二部分:e[7](数组名+元素个数)

  • 图解:

 @FeZit

标签:初阶,int,嵌入式,地址,内存,数组,printf,C语言,buf
From: https://blog.csdn.net/weixin_63053154/article/details/145207783

相关文章

  • 嵌入式基础 C语言篇 指针初阶
    一、指针的入门(1)、预备知识0、图解:1、内存地址字节:字节是内存的容量单位,英文称为byte,一个字节有8位,即1byte(00000000---11111111)=8bits(0---1)地址:系统为了便于区分每一个字节而对它们逐一进行的编号,称为内存地址,简称地址。在32位系统:说明:地址+1就是......
  • 嵌入式基础 C语言篇 错题
    (1) 若已定义x和y为double类型,则表达式x=1,y=x+3/2的值是________。A.1     B.2    C.2.0    D.2.53/2=1;y=2.0(2)简述i++和++i    i++是先使用i的值,再i+1;++i是先i+1,再使用i的值底层原理:1、i++和++i都是带有返回值的函数2......
  • 第1讲:C语言常见概念
    目录1.C语言是什么?2.C语言的历史和辉煌3.编译器的选择VS20224.VS项目和源文件、头文件介绍5.第一个C语言程序6.main函数7.printf和库函数8.关键字介绍9.字符和ASCII编码10.字符串和\011.转义字符12.语句和语句分类13.注释是什么?为什么写注释?正文开始1.C语言......
  • 第2讲:C语言数据类型和变量
    目录1.数据类型介绍2.signed和unsigned3.数据类型的取值范围4.变量5.算术操作符:+、-、*、/、%6.赋值操作符:=和复合赋值7.单目操作符:++、--、+、-8.强制类型转换9.scanf和printf介绍正文开始1.数据类型介绍C语言提供了丰富的数据类型来描述生活中的各种数......
  • C语言中的流程控制(for循环 while循环 do-while循环)
    什么是循环?循环---重复在执行循环语句for while do-while 1. for循环for(表达式1;表达式2;表达式3) {  语句} ①求解表达式1  ②判断表达式2  真 ③执行语句④求解表达式3  重复②-④直到表达式2为假    ①只会执行一次  ......
  • 嵌入式知识点总结(一)-C/C++关键字
     针对于嵌入式软件杂乱的知识点总结起来,提供给读者学习复习对下述内容的强化。目录1.C语言宏中"#“和"##"的用法1.1.(#)字符串化操作符1.2.(##)符号连接操作符2.关键字volatile有什么含意?并举出三个不同的例子?2.1.并行设备的硬件寄存器2.2.中断服务程序中修改的变......
  • GCC支持Objective C的故事?Objective-C?GCC只能编译C语言吗?Objective-C 1.0和2.0有什
    GCC支持ObjectiveC的故事Objective-C主要由 Stepstone 公司的BradCox和 TomLove在1980年左右发明。乔布斯离开苹果公司后成立了NeXTSTEP公司, 买下了Objective-C语言的授权。GCC对Objective-C语言的支持是在1992年加入的,具体是在GCC1.3版本中首次引入的。G......
  • 嵌入式杂谈——什么是DMA?有什么用?
    什么是DMA?——直接内存访问技术详解在嵌入式系统和计算机体系结构中,DMA(DirectMemoryAccess,直接内存访问) 是一种重要的数据传输技术。它允许外设(如UART、SPI、ADC等)直接与内存进行数据交换,而无需CPU的干预。DMA技术可以显著提高系统的效率和性能,尤其是在需要高速数据传输的......
  • 华为2024嵌入式研发面试题
    01你认为最好的排序算法是什么?在实际的编程中,最好的排序算法要根据实际需求和数据规模来选择,因为每种排序算法都有其优势和劣势。以下是一些常见排序算法及其优缺点:冒泡排序冒泡排序是一种简单直观的排序算法,它的时间复杂度是O(n^2)。虽然它的时间复杂度比较高,但它的实现方......
  • C语言中char *str[] 和char *str有什么区别
    charstr[]和charstr的区别:C语言中charstr和charstr[]的区别-CSDN博客char*str[]和char*str在C语言中有不同的含义和用途,以下是它们的区别:1.char*str类型:这是一个指向字符的指针。用途:通常用于指向一个字符串。字符串在C语言中是一个以空字符'\0'结尾的字......