【C Primer Plus第六版 学习笔记】 第十六章 C预处理器和C库

news2024/11/27 3:48:25

有基础,进阶用,个人查漏补缺

第十五章的内容之前学过,跳过

  1. 预处理之前,编译器必须对该程序进行一些翻译处理

    1. 首先把源代码中出现的字符映射到原字符集

    2. 其次编译器定位每个反斜杠后面跟着换行符的实例,并删除它们(把由于写代码时,一行太长,会用反斜杠\把一行逻辑行变成两个物理行)

    3. 然后编译器把文本划分为预处理记号序列、空白序列和注释序列。此处需要注意的是,编译器将用一个空格字符替换每一条注释,如

      int/* 注释*/fox;
      //将变成
      int fox;//中间的注释变成了一个空格
      
  2. C预处理器在程序执行之前查看程序,故称之为预处理器。根据程序中的预处理器指令,预处理器把符号缩写替换成其表达的内容。

  3. 明示常量:#define

    1. 指令从#开始运行,到第1个换行符结束,针对的是一个逻辑行(可以用\进行物理换行)

    2. 类对象宏定义的组成:宏的名称中不允许有空格,需要遵循C变量的命名规则

      #define PX printf("x is %d\n", x)
      //预处理指令 宏 替换体
      
    3. 预处理器不做计算,不对表达式求值,只进行替换

    4. 记号:可以把宏的替换体看作是记号(token)型字符串

      #define FOUR 2*2    //有一个记号2*2,但对于C编译器来说是3个记号
      #define six 2 * 3   //有三个记号2、*、3,额外的空格也是替换体的一部分
      
    5. 重定义常量:假设先把LIMIT定义为20,稍后在该文件中又把它定义为25。

      //ANSI标准在新定义和旧定义完全相同时才允许重定义
      #define six 2 * 3
      #define six 2 * 3
      
    6. 在#define中使用参数,即类函数宏:

      1. 为保证运算顺序,要多使用圆括号

        #define SQUARE(X) X*X
        #define SQUARE1(X) (X*X)
        #define SQUARE2(X) (X)*(X)
        int x = 5;
        z = SQUARE(x);//z=25
        z = SQUARE(x+2);//z= x+2*x+2 = 5+2*5+2 = 17
        z = 100 / SQUARE(2);//z = 100/2*2 = 100/2*2 = 100
        
        z = SQUARE1(2);//z = 100 / (2*2) = 25
        
        z = SQUARE2(x+2);//z = (x+2)*(x+2)
        
        
      2. 避免使用++x等这种递增或者递减

      3. 用宏参数创建字符串:#运算符

        #define PSQR(X) printf("The square of X is %d.\n", ((X)*(X)))
        PSQR(8);//输出The square of X is 64.**注意双引号中的X被视为普通文本,不是记号**
        
        #define PSQR(x) printf("The square of " #x " is %d.\n", ((x)*(x)))
        int y = 5;
        PSQR(y);//输出The square of y is 25
        PSQR(2 + 4);//输出The square of  2 + 4 is 36
        
      4. 预处理黏合剂:##运算符

        #define XNAME(n) x ## n
        int XNAME(1) = 14;//变成int x1 = 14
        
      5. 变宏参:…和__VA_ARGS__

        #define PR(...) prinf(__VA_ARGS__)
        pr("Hoedy");//等于 prinf("Hoedy")
        
        #define PR(X, ...) prinf("Message " #X ": " __VA_ARGS__)
        int x = 2;
        PR(1, "x = %d\n", x);//即prinf("Message " "1" ": " "x = %d\n", x)
        //输出Message 1: x = 2
        
  4. 宏和函数的选择

    1. 宏生成内联代码,即在程序中生成语句,调用20次宏就生成20行代码。而调用函数20次,在程序中只有一份函数语句的副本,节省空间

    2. 调用函数时,程序控制必须跳转到函数内,再返回主调程序,比内联代码更费时间

    3. 宏不用担心变量类型

    4. 在嵌套循环中使用宏更有助于提高效率

    5. 对于简单的函数,通常使用宏

      #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
      #define ABS(X,Y) ((X) < 0 ? -(X) : (X))
      #DEFINE ISSIGN(X) ((X)  == '+' || (X) == '-' ? 1 : 0)
      
  5. 文件包含:#include

    1. 当预处理器发现#include指令时会查看后面的文件名并把文件的内容包含到当前文件中,即替换源文件中的#include指令。这相当于把被包含文件的全部内容输入到源文件#include指令所在的位置。

    2. #include指令有两种形式:文件名在尖括号或者双引号中

      //在unix系统中
      #include <stdio.h>              //查找系统目录
      #include "mystuff.h"            //查找当前工作目录
      #include "/usr/biff/mystuff.h"  //查找/usr/biff/目录
      
    3. 头文件实例

      1. names_st.h————names_st结构的头文件

        // 常量
        #include <string.h>
        #define SLEN 32
        
        // 结构声明
        struct names_st
        {
            char first[SLEN];
            char last[SLEN];
        };
        
        // 类型定义
        typedef struct names_st names;
        
        // 函数原型
        void get_names(names *);
        void show_names(const names *);
        char * s_gets(char * st, int n);
        
      2. names_st.c————定义names_st.h中的函数

        #include <stdio.h>
        #include "names_st.h"     //包含头文件
        
        //函数定义
        void get_names(names * pn)
        {
            printf("Please enter your first name: ");
            s_gets(pn->first, SLEN);
            
            printf("Please enter your last name: ");
            s_gets(pn->last, SLEN);
         }
        
        void show_names(const names * pn)
        {
            printf("%s %s", pn->first, pn->last);
        }
        
        char * s_gets(char * st, int n)
        {
            char * ret_val;
            char * find;
            
            ret_val = fgets(st, n, stdin);
            if (ret_val)
            {
                find = strchr(st, '\n');   //查找换行符
                if (find)                  //如果地址不是NULL,
                    *find = '\0';          //在此处放一个空字符
                else
                    while (getchar() != '\n')
                        continue;          //处理输入行中的剩余字符
            }
            return ret_val;
        }
        
        
      3. useheader.c————使用names_st结构

        #include <stdio.h>
        #include "names_st.h"
        //记得链接names_st.c
        
        int main(void)
        {
            names candidate;
            
            get_names(&candidate);
            printf("Let's welcome ");
            show_names(&candidate);
            printf(" to this program!\n");
            return 0;
        }
        
      4. 注意:

        1. 两个源文件.c都使用names_st类型结构,所以它们都必须包含names_st.h头文件
        2. 必须编译和链接names_st.c和useheader.c源代码文件
        3. 声明和指令放在names_st.h头文件中,函数定义放在names_st.c源代码文件中
    4. 使用头文件

      头文件中最常用的形式如下:

      1. 明示常量
      2. 宏函数
      3. 函数声明
      4. 类型定义
      5. 使用头文件声明外部变量供其他文件共享
  6. #undef 指令

    用于取消已定义的 #define 指令

    #define LIMIT 40
    #undef LIMIT      //可以移除上面的定义
    

    现在可以将LIMIT重新定义为一个新值,即使原来没有定义LIMIT,该取消也依旧有效;

    如果想使用一个名称,又不确定是否之前已经用过,为安全起见,可以使用 #undef 取消该名称的定义

  7. 条件编译——#ifdef、#else、#endif

    预处理器不识别用于标记块的花括号{}

    缩进与否看个人风格

    #ifdef MAVIS          //如果已经用#define定义了MAVIS,则执行下面的指令
    	#include "horse.h"
    	#define STABLE 5
    #else                 //如果没有用#define定义了MAVIS,则执行下面的指令
    	#include "cow.h"
    	#define STABLE 5
    #endif                //必须存在
    

    也可以用这些指令标记C语句块

    #include <stdio.h>
    #define JUST_CHECKING
    #define LIMIT 4
    
    int main(void)
    {
        int i;
        int total = 0;
    
        for (i = 1; i <= LIMIT; i++)
        {
            total += 2*i*i + 1;
    #ifdef JUST_CHECKING
            printf("i=%d, running total = %d\n", i, total);
    #endif
        }
        printf("Grand total = %d\n", total);
        
        return 0;
    }
    

    输出:

    i=1, running total = 3
    i=2, running total = 12
    i=3, running total = 31
    i=4, running total = 64
    Grand total = 64
    

    如果省略JUST_CHECKING定义(把#define JUST_CHECKING放在注释中,或者使用#undef指令取消它的定义),并重新编译该程序,只会输出最后一行。该方法可用来调试程序。

  8. 条件编译——#ifndef 指令

    #ifndef 和#ifdef 用法类似,也是和#else、#endif一起使用,只是它们的逻辑相反

    有arrays.h

    #ifndef SIZE
    	#define SIZE 100
    #endif
    

    有代码

    #define SIZE 10
    #include "arrays.h" //当执行到该行时,跳过了#define SIZE 100,故SIZE为10
    

    故可以使用#ifndef 技巧避免重复包含

    #ifndef NAMES_H_
    #define NAMES_H_
    
    // constants
    #define SLEN 32
    
    // structure declarations
    struct names_st
    {
        char first[SLEN];
        char last[SLEN];
    };
    
    // typedefs
    typedef struct names_st names;
    
    // function prototypes
    void get_names(names *);
    void show_names(const names *);
    char * s_gets(char * st, int n);
    
    #endif
    

    用以下代码进行测试,是没有问题的。但是如果把上面的.h中的#ifndef 删除,程序会无法通过编译

    #include <stdio.h>
    #include "names.h"
    #include "names.h"   //不小心第2次包含头文件
    
    int main()
    {
        names winner = {"Less", "Ismoor"};
        printf("The winner is %s %s.\n", winner.first, winner.last);
        return 0;
    }
    
  9. 条件编译——#if 和 #elif

    类似于if语句。#if 后面跟着整型常量表达式

    #if SYS == 1
    	#include "a.h"
    #elif SYS == 2
    	#include "b.h"
    #elif SYS == 3
    	#include "c.h"
    #else
    	#include "d.h"
    #endif
    

    另一个新的用法测试名称是否已经定义

    #if defined (ABC)
    	#include "a.h"
    #elif defined (DE)
    	#include "b.h"
    #elif defined (FG)
    	#include "c.h"
    #else
    	#include "d.h"
    #endif
    
  10. 预定义宏

    在这里插入图片描述

  11. #line 和 #error

    #1ine 指令重置__LINE__和__FILE__宏报告的行号和文件名。可以这样使用Iine:

    #line 1000 11      //把当前行号重置为1000
    #line 10 "cool.c"  //把行号重置为10,把文件名重置为 cool.c
    

    #error 指令让预处理器发出一条错误消息,该消息包含指令中的文本。如果可能的话,编译过程应该中断。可以这样使用#error 指令:

    #if __STDC_VERSION__!= 201112L
    #error Not C11
    #endif
    
    //编译以上代码生成后,输出如下:
    $ gcc newish.c
    newish.c:14:2: error: #error Not C11
    $ gcc -std=c11 zewish.c
    $
    

    如果编译器只支持旧标准,则会编译失败,如果支持 CI1 标准,就能成功编译。

  12. #pragma

    在现在的编译器中,可以通过命令行参数或 IDE 菜单修改编译器的一些设置。#pragma 把编译器指令放入源代码中。例如,在开发 C99 时,标准被称为 C9X,可以使用下面的编译指示 (pragma)让编译器支持 C9X:

    #pragma c9x On
    
  13. 泛型选择(C11)

    在程序设计中,泛型编程(generic programming)指那些没有特定类型,但是一旦指定一种类型,就可以转换成指定类型的代码。

    例如,C++在模板中可以创建泛型算法,然后编译器根据指定的类型自动使用实例化代码。C没有这种功能。然而,C11 新增了一种表达式,叫作泛型选择表达式(generic selection expression),可根据表达式的类型(即表达式的类型是int、double 还是其他类型)选择一个值。泛型选择表达式不是预处理器指令,但是在一些泛型编程中它常用作#define 宏定义的一部分。

    下面是一个泛型选择表达式的示例:

    _Generic (x, int: 0, float: 1, double: 2, default: 3)
    

    _Generic 是C11 的关键宇。_Generic 后面的國括号中包含多个用逗号分隔的项。

    1. 第1个项是一个表达式,后面的每个项都由一个类型、一个冒号和一个值组成,如float:1
    2. 第1个项的类型匹配哪个标签,整个表达式的值是该标签后面的值。例如,假设上面表达式中× 是int 类型的变量,× 的类型匹配int :标签,那么整个表达式的值就是0。
    3. 如果没有与类型匹配的标签,表达式的值就是 default:标签后面的值。
    4. 泛型选择语句与 switch 语句类似,只是前者用表达式的类型匹配标签,而后者用表达式的值匹配标签。
    #include <stdio.h>
    #define MYTYPE(X) _Generic((X),\
    int: "int",\
    float : "float",\
    double: "double",\
    default: "other"\
    )
    
    int main(void)
    {
        int d = 5;
        printf("%s\n", MYTYPE(d));     //d是int类型,输出int
        printf("%s\n", MYTYPE(2.0*d)); //2.0*d是double类型,输出double
        printf("%s\n", MYTYPE(3L));    //3L是long类型,输出other
        printf("%s\n", MYTYPE(&d));    //&d是int * 类型输出other
        return 0;
    }
    
  14. 内联函数(C99)

    通常,函数调用都有一定的开销,因为函数的调用过程包括建立调用、传递参数、跳转到函数代码并返回。使用宏使代码内联,可以避免这样的开销。

    C99还提供另一种方法:内联函数(inline function)。把函数变成内联函数,编译器可能会用内联代码替换函数调用,并(或)执行一些其他的优化,但是也可能不起作用。

    标准规定具有内部链接的函数可以成为内联函数,还规定了内联函数的定义与调用该函数的代码必须在同一个文件中。

    因此,最简单的方法是使用函数说明符inline和存储类别说明符static。通常,内联函数应定义在首次使用它的文件中,所以内联函数也相当于函数原型。如下所示:

    #include <stdio.h>
    inline static void eatline ()   // 内联函数定义/原型
    {
    	while (getchar() != '\n')
    		continue;
    }
    int main()
    {
    	...
    	eatline();              //函数调用
    	...
    }
    

    编译器查看内联函数的定义(也是原型),可能会用函数体中的代码替换 eatline)函数调用。也就是说,效果相当于在西数调用的位置输入函数体中的代码:

    #include <stdio.h>
    inline static void eatline ()   // 内联函数定义/原型
    {
    	while (getchar() != 'In')
    		continue;
    }
    int main()
    {
    	...
    //函数调用之处相当于插入代码块
    	while (getchar() != "\n')
    		continue;              
    	...
    }
    

    由于并未给内联函数预留单独的代码块,所以无法获得内联函数的地址(实际上可以获得地址,不过这样做之后,编译器会生成一个非内联函数)。另外,内联函数无法在调试器中显示。

    内联函数应该比较短小。把较长的函数变成内联并未节约多少时间,因为执行函数体的时间比调用函数的时间长得多。

    编译器优化内联函数必须知道该函数定义的内容。这意味着内联函数定义与函数调用必须在同一个文件中。鉴于此,一般情况下内联函数都具有内部链接。

    因此,如果程序有多个文件都要使用某个内联函数,那么这些文件中都必须包含该内联函数的定义。最简单的做法是,把内联函数定义放入头文件,并在使用该内联函数的文件中包含该头文件即可。

    一般都不在头文件中放置可执行代码,内联函数是个特例。因为内联两数具有内部链接,所以在多个文件中定义同一个内联函数不会产生什么问题。

    与C++不同的是,C还允许混合使用内联函数定义和外部函数定义(具有外部链接的两数定义)。例如,一个程序中使用下面了个文件:

    //  file1.c
    #include <stdio.h>
    inline static double square(double x) { return x*x; }
    void spam(double);
    void masp(double);
    int main()
    {
        double q = square(1.3);
        
        printf("%.2f\n", q);
        spam(12.6);
        masp(1.6);
        
        return 0;
    }
    
    //  file2.c
    #include <stdio.h>
    double square(double x) { return (int) (x*x); }
    void spam(double v)
    {
        double kv = square(v);
        printf("%.2f\n", kv);
        return;
    }
    
    //  file3.c
    #include <stdio.h>
    inline double square(double x) { return (int) (x * x + 0.5); }
    void masp(double w)
    {
        double kw = square(w);
        printf("%.2f\n", kw);
        return;
    }
    

    如上述代码所示,3 个文件中都定义了square() 函数。

    1. file1.c文件中是 inline static定义
    2. file2.c 文件中是普通的函数定义(因此具有外部链接)
    3. file3.c 文件中是 inline 定义,省路了static
    • 3个文件中的函数都调用了 sguare() 函数,这会发生什么情况?
      1. file1.c文件中的main()使用square()的局部static 定义。由于该定义也是inline 定义,所以编译器有可能优化代码,也许会内联该函数。
      2. file2.c文件中spam函数使用该文件中square()函数的定义,该定义具有外部链接,其他文件也可见。
      3. file3.c 文件中,编译器既可以使用该文件中square()函数的内联定义,也可以使用file2.c文件中的外部链接定义。如果像 file3.c 那样,省路file1.c 文件 inline 定中的 static,那么该 inline 定义被视为可替换的外部定义。
  15. 关于库以及一些函数的使用跳过

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1349439.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件测试/测试开发丨Python 常用第三方库 pymysql

pymysql 概述 Python 的数据库接口标准是 Python DB-APIPyMySQL 是从 Python 连接到 MySQL 数据库服务器的接口PyMySQL 的目标是成为 MySQLdb 的替代品官方文档&#xff1a;pymysql.readthedocs.io/ pymysql 安装 使用 pip 安装使用 Pycharm 界面安装 pip install pymysqlp…

玩转贝启科技BQ3588C开源鸿蒙系统开发板 —— 代码下载(1)

本文主要参考&#xff1a; BQ3588C_代码下载 1. 安装依赖工具 安装命令如下&#xff1a; sudo apt-get update && sudo apt-get install binutils git git-lfs gnupg flexbison gperf build-essential zip curl zlib1g-dev gcc-multilib g-multiliblibc6-dev-i386 l…

Note: An Interesting Festival

An Interesting Festival 一个有趣的节日。 festival The Agricultural Feast takes place after the independence Day. 农业盛会在独立日后举行 takes place independence feast agricultural It is not a worldwide celebration. 它不是一个全球的庆典。 worldwide ce…

利用计算机名称共享打印机步骤,如何连接共享打印机汇总教程

转载&#xff1a;利用计算机名称共享打印机步骤,如何连接共享打印机汇总教程-CSDN博客 新到办公室第一件事肯定是连接办公区的共享打印机&#xff0c;那么对于已经设置好的共享打印机&#xff0c;我们自己的电脑要怎么连上它呢&#xff0c;下面就以win7和win10系统给大家具体讲…

【揭秘】如何使用LinkedHashMap来实现一个LUR缓存?

LRU&#xff08;Least Recently Used&#xff09;缓存是一种常用的缓存淘汰策略&#xff0c;用于在有限的缓存空间中存储数据。其基本思想是&#xff1a;如果数据最近被访问过&#xff0c;那么在未来它被访问的概率也更高。因此&#xff0c;LRU缓存会保留最近访问过的数据&…

Android 反编译处理Dex

前言 当我们将Android项目打包上架的时候&#xff0c;为了提高被人反编译代码的可能性可以提取 dex 文件对代码进一步做混淆处理。 本文不对相关工具做过多的解释&#xff0c;不了解的可以先熟悉相关工具的使用。 相关工具&#xff08;点击直接下载&#xff09; jadx-gui&a…

PyTorch 节省显存技巧:Activation Checkpointing

参考资料 官方文档&#xff1a; https://pytorch.org/docs/2.0/checkpoint.html官方博客&#xff1a;https://medium.com/pytorch/how-activation-checkpointing-enables-scaling-up-training-deep-learning-models-7a93ae01ff2d Activation Checkpointing 介绍 激活检查点 …

miniqmt配置

1 下载安装qmt 2 将安装目录下的 xtquant 目录复制到 python安装目录 的相同路径下 3 测试 from xtquant import xtdata def on_data (datas):#回调函数 print(datas) seq xtdata.subscribe_whole_quote(code_list[‘002306.SZ’], callbackon_data) time.sleep(10) xtda…

2023-12-15 LeetCode每日一题(反转二叉树的奇数层)

2023-12-15每日一题 一、题目编号 2415. 反转二叉树的奇数层二、题目链接 点击跳转到题目位置 三、题目描述 给你一棵 完美 二叉树的根节点 root &#xff0c;请你反转这棵树中每个 奇数 层的节点值。 例如&#xff0c;假设第 3 层的节点值是 [2,1,3,4,7,11,29,18] &…

钉钉-蓝牙打卡和平台打卡的区别

钉钉的群是部门概念。 你的账号归属到哪个群&#xff0c;就是哪个群的员工。 -------------------------------------------------------------------- 蓝牙打卡是对账号归属进行打卡的。 平台打卡是只对属于自己平台内的账号打卡的。 ----------------------------------…

cnPuTTY CAC 0.80—PuTTY CAC 0.80中文版本简单说明~~

随着PuTTY 0.80在2023-12-18发布&#xff0c;PuTTY CAC也同步进行了更新。 PuTTY CAC 0.80同步更新了针对Terrapin攻击(CVE-2023-48795)的修改&#xff0c;除了这些还进行了额外的添加和修改。另外来自cnPuTTY CAC自身也进行了小的修改。更多详细的内容请参考以下内容。 首先&…

产品经理学习-从0-1搭建策略产品

从0-1搭建策略产品 目录&#xff1a; 回顾策略产品 如何从0-1搭建策略产品 回顾策略产品 之前也了解过从产品实施的角度来看&#xff0c;策略就是针对问题的解决方案&#xff0c;在互联网时代更集中体现在2个维度&#xff1a;业务场景和数据应用 如何从0-1搭建策略产品 我们…

Python玫瑰花完整代码

文章目录 环境需求完整代码普通玫瑰花三维玫瑰花多彩玫瑰花环境需求 python3.11.4PyCharm Community Edition 2023.2.5pyinstaller6.2.0(可选,这个库用于打包,使程序没有python环境也可以运行,如果想发给好朋友的话需要这个库哦~)【注】 python环境搭建请见:https://want…

数据结构(二)栈和队列

本文是在原本数据结构与算法闯关的基础上总结得来&#xff0c;加入了自己的理解和部分习题讲解 原活动链接 邀请码: JL57F5 目录 栈和队列1.什么是栈 ?栈的入栈、出栈操作 2.什么是队列 ?队列的入队和出队 3.案例讲解 : 使用Python实现栈来管理定时任务Task 类TaskStack 类…

Spring Cloud Function SpEL注入漏洞(CVE-2022-22963)分析

一、概述 2022年3月24日&#xff0c;Pivotal修补了Spring Cloud Function中一个关键的服务器端代码注入漏洞&#xff08;Spring表达式语言注入&#xff09;&#xff0c;该漏洞有可能导致系统被攻击。Spring是一种流行的开源Java框架&#xff0c;该漏洞与另一个相关的远程代码执…

rime中州韵 help lua Translator

lua 是 Rime中州韵/小狼毫输入法强大的武器&#xff0c;掌握如何在Rime中州韵/小狼毫中使用lua&#xff0c;你将体验到什么叫 随心所欲。 先看效果 在 rime中州韵 输入效果一览 中的 &#x1f447; help效果 一节中&#xff0c; 我们看到了在Rime中州韵/小狼毫输入法中输入 h…

07-2-接口文档管理工具-swagger注解使用__ev

swagger参考demo package com.example.swagger2.controller;import com.example.swagger2.exception.SwaggerException; import com.example.swagger2.model.User; import io.swagger.annotations.*; import org.springframework.web.bind.annotation.*;import java.util.Has…

MySQL数据库索引优化

一、引言 1. 索引的重要性 MySQL数据库索引的重要性主要体现在&#xff0c;一是查询速度优化&#xff0c;索引可以极大地提高查询速度。对于没有索引的表&#xff0c;MySQL必须进行全部扫描来找到所需的行&#xff0c;如果表中数据量很大&#xff0c;那么通常很慢。通过适当的…

Python pycharm编辑器修改代码字体

在pycharm编辑器下修改代码字体&#xff0c;可以按照以下步骤&#xff1a; 点开上图所示的菜单&#xff0c; 再点击File->Settings&#xff0c;进入设置页面。 我们找到Editor下的Font并点选&#xff0c;然后我们就可以在右侧修改字体相关配置了。 这里建议使用等宽字体&…

数据结构第1章 线性表

名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼《定风波莫听穿林打叶声》 本篇笔记整理&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 0、思维导图线性表1、顺序存储1&#xff09;顺序表2&…