标准I/O库-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

news2024/12/24 10:08:21

标准I/O库

在这里插入图片描述

1、标准I/O库简介

什么是标准I/O库

  • 标准C库当中用于文件I/O操作相关的一套库函数,使用标准I/O需要包含头文件

标准I/O和文件I/O之间的区别

  • 标准I/O是库函数,而文件I/O是系统调用

  • 标准I/O是对文件I/O的封装

  • 可移植性:标准I/O相对于文件I/O具有更好的额移植性

  • 效率:标准I/O在效率上要优于文件I/O

2、FILE 指针和fopen函数

FILE指针

  • 标准I/O使用FLIE指针作为文件句柄,与文件I/O中的文件描述符相似

打开文件–fopen()函数

  • 标准I/O中使用fopen()函数打开文件,是对open函数的封装

  • #include <stdio.h>
    FILE *fopen(const char *path, const char *mode);

    • path:参数 path 指向文件路径,可以是绝对路径、也可以是相对路径

    • mode:参数 mode 指定了对该文件的读写权限

    • 返回值:调用成功返回一个指向 FILE 类型对象的指针(FILE *),该指针与打开或创建的文件相关联,后续的标准 I/O 操作将围绕 FILE 指针进行。如果失败则返回 NULL,并设置 errno

    • 新建文件的权限

      • 无法手动指定文件的权限,但却有一个默认值:
        S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH (0666)(110 110 110)

        • 所有用户都只有可读可写权限,没有可执行权限

关闭文件–fclose()函数

  • 关闭一个由 fopen()打开的文件

  • #include <stdio.h>
    int fclose(FILE *stream);

    • stream 为 FILE 类型指针

    • 调用成功返回 0;失败将返回 EOF(也就是-1),并且会设置 errno

3、读文件和写文件

读文件–fread()函数

  • #include <stdio.h>
    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);1

    • ptr:fread()将读取到的数据存放在参数 ptr 指向的缓冲区中

    • size:fread()从文件读取 nmemb 个数据项,每一个数据项的大小为 size 个字节,所以总共读取的数据大小为 nmemb * size 个字节

    • nmemb:参数 nmemb 指定了读取数据项的个数

    • stream:FILE 指针

    • 返回值:调用成功时返回读取到的数据项的数目nmemb,如果发生错误或到达文件末尾,则 fread()返回的值将小于参数 nmemb,可以使用 ferror()或 feof()函数来判断

写文件–fwrite()函数

  • #include <stdio.h>
    size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

    • ptr:将参数 ptr 指向的缓冲区中的数据写入到文件中

    • size:参数 size 指定了每个数据项的字节大小

    • nmemb:参数 nmemb 指定了写入的数据项个数

    • stream:FILE 指针

    • 返回值:调用成功时返回读取到的数据项的数目nmemb,如果发生错误,则 fwrite()返回的值将小于参数 nmemb(或者等于 0)

设置读写位置–fseek()函数

  • 用于设置文件读写位置偏移量

  • #include <stdio.h>
    int fseek(FILE *stream, long offset, int whence);

    • stream:FILE 指针

    • offset:偏移量,以字节为单位

    • 用于定义参数 offset 偏移量对应的参考值,该参数为下列其中一种(宏定义):

      • SEEK_SET

        • 读写偏移量将指向 offset 字节位置处(从文件头部开始算)
      • SEEK_CUR

        • 读写偏移量将指向当前位置偏移量 + offset 字节位置处,offset 可以为正、也可以为负
      • SEEK_END

        • 读写偏移量将指向文件末尾 + offset 字节位置处,同样 offset 可以为正、也可以为负
    • 返回值:成功返回 0;发生错误将返回-1,并且会设置 errno

      • 与 lseek()函数的返回值意义不同

        • lseek()函数返回值

          • 成功将返回从文件头部开始算起的位置偏移量(字节为单位)

          • 错误将返回-1

4、feof和ferror函数

判断是否到达文件末尾–feof()函数

  • 当文件的读写位置移动到了文件末尾时,end-of-file 标志将会被设置

  • #include <stdio.h>
    int feof(FILE *stream);

    • 如果 end-of-file 标志被设置了,则调用
      feof()函数将返回一个非零值,如果 end-of-file 标志没有被设置,则返回 0

判断是否发生错误–ferror()函数

  • 当对文件的 I/O 操作发生错误时,错误标志将会被设置

  • #include <stdio.h>
    int ferror(FILE *stream);

    • 如果错误标志被设置了,则 调用 ferror()函数
      将返回一个非零值,如果错误标志没有被设置,则返回 0

清除标志–clearerr()函数

  • 用于清除 end-of-file 标志和错误标志

    • 当调用 feof()或 ferror()校验这些标志后,通常需 要清除这些标志,避免下次校验时使用到的是上一次设置的值,此时可以手动调用 clearerr()函数清除标志

    • 对于 end-of-file 标志,当调用 fseek()成功时也会清除文件的 end-of-
      file 标志

  • #include <stdio.h>
    void clearerr(FILE *stream);

    • 此函数没有返回值,调用将总是会成功!

5、格式化I/O

格式化输出

  • printf()

    • 用于将格式化数据写入到标准输出

    • int printf(const char *format, …);

      • 函数调用成功返回打印输出的字符数;失败将返回一个负值!
  • fprintf()

    • int fprintf(FILE *stream, const char *format, …);

    • 函数调用成功返回写入到文件中的字符数;失败将返回一个负值!

  • dprintf()

    • int dprintf(int fd, const char *format, …);

    • 函数调用成功返回写入到文件中的字符数;失败将返回一个负值!

  • sprintf()

    • int sprintf(char *buf, const char *format, …);

    • 一般会使用这个函数进行格式化转换

    • 会在字符串尾端自动加上一个字符串终止字符’\0’

    • 可能会造成由参数 buf 指定的缓冲区溢出,调用者有责任确保该缓冲区足够大,因为缓冲区溢出会造成程序不稳定甚至安全隐患!

    • 函数调用成功返回写入到 buf 中的字节数;失败将返回一个负值!

  • snprintf()

    • int snprintf(char *buf, size_t size, const char *format, …);

    • 使用参数 size 显式的指定缓冲区的大小,如果写入到缓冲区的字节数大于参数 size 指定的大小,超出的部分将会被丢弃!如果缓冲区空间足够大,snprintf()函数就会返回写入到缓冲区的字符数,与 sprintf()函数相同,也会在字符串末尾自动添加终止字符’\0’

    • 若发生错误,snprintf()将返回一个负值!

格式化输入

  • scanf()

    • 将用户输入(标准输入)的数据进行格式化转换

    • int scanf(const char *format, …);

    • 函数调用成功后,将返回成功匹配和分配的输入项的数量;如果较早匹配失败,则该数目可能小于所提供的数目,甚至为零。发生错误则返回负值。

  • fscanf()

    • 从 FILE 指针指定文件中读取数据,并将数据进行格式化转换

    • int fscanf(FILE *stream, const char *format, …);

    • 函数调用成功后,将返回成功匹配和分配的输入项的数量;如果较早匹配失败,则该数目可能小于所提供的数目,甚至为零。发生错误则返回负值

  • sscanf()

    • 从参数 str 所指向的字符串中读取数据,并将数据进行格式化转换

    • int sscanf(const char *str, const char *format, …);

    • 函数调用成功后,将返回成功匹配和分配的输入项的数量;如果较早匹配失败,则该数目可能小于所提供的数目,甚至为零。发生错误则返回负值。

6、文件I/O的内核缓冲

文件I/O的内核缓冲

- 系统调用 write() 与磁盘操作并不是同步的

- 提高文件 I/O 的速度和效率

- Linux内核对于文件I/O的内核缓冲区大小没有固定上限,因此内核会尽可能分配更多的内存作为文件I/O的内核缓冲区。系统可用的物理内存越多,内核缓冲区也会相应变大,这样操作更大的文件时就能依赖更大空间的内核缓冲区。

刷新文件I/O的内核缓冲

  • 系统调用(fsync、fdatasync、sync)

    • fsync()函数

      • 将参数 fd 所指文件的内容数据和元数据写入磁盘,只有在对磁盘设备的写入操作完成之后,fsync()函数才会返回

      • #include <unistd.h>
        int fsync(int fd);

        • fd 表示文件描述符,函数调用成功将返回 0,失败返回-1 并设置 errno
      • 元数据

        • 元数据并不是文件内容本身的数据,而是一些用于记录文件属性相关的数
          据信息,譬如文件大小、时间戳、权限等等信息,这些信息存储在磁盘设备中
    • fdatasync()函数

      • fdatasync()与 fsync()类似,不同之处在于 fdatasync()仅将参数 fd 所指文件的内容数据写入磁盘,并不包括文件的元数据;同样,只有在对磁盘设备的写入操作完成之后,fdatasync()函数才会返回

      • #include <unistd.h>
        int fdatasync(int fd);

    • sync()函数

      • 将所有文件 I/O 内核缓冲区中的文件内容数据和元数据全部更新到磁盘设备中

      • #include <unistd.h>
        void sync(void);

      • 在 Linux 实现中,调用 sync()函数仅在所有数据已经写入到磁盘设备之后才会返回;然后在其它系统中,sync()实现只是简单调度一下 I/O 传递,在动作未完成之后即可返回

  • O_DSYNC和O_SYNC标志 控制文件 I/O 内核缓冲标志

    • O_DSYNC 标志

      • 当在调用open()函数时指定O_DSYNC标志,这个标志的作用类似于在每次调用write()函数后立即调用fdatasync()函数来进行数据同步。这意味着在使用O_DSYNC标志的情况下,系统会确保每次写入操作后都会将数据同步到磁盘,实现数据同步
    • O_SYNC 标志

      • 在调用 open()函数时,指定 O_SYNC 标志,使得每个 write()调用都会自动将文件内容数据和元数据刷新到磁盘设备中,其效果类似于在每个 write()调用之后调用 fsync()函数进行数据同步

7、直接I/O-绕过内核缓冲

O_DIRECT标志

  • 在调用 open()函数打开文件时,指定
    O_DIRECT 标志就可以实现直接I/O

  • 如:fd = open(filepath, O_WRONLY | O_DIRECT);

  • 需要在程序中自己指定 O_DIRECT 标志

    • 直接在源文件中定义:#define _GNU_SOURCE

    • gcc 编译时使用-D 选项定义_GNU_SOURCE 宏

      • gcc -D_GNU_SOURCE -o testApp testApp.c

      • 该宏定义在整个源码工程中都是生效的,是一个全局宏定义

直接I/O的对齐限制

  • 1、应用程序的缓冲区起始地址必须以块大小的整数倍进行对齐

    • 定义了一个静态字符数组

      • 其大小为块的整数倍字节

      • 指定数组在内存中的对齐方式为块大小个字节

        • 通过__attribute((aligned (块大小)))这个属性
      • 如:static char buf[8192] __attribute((aligned (4096)));

  • 2、写文件时,文件的位置偏移量必须是块大小的整数倍

    • 调用lseek()函数来移动读写指针
  • 3、写入到文件的数据大小必须是块大小的整数倍

    • 先判断写入字节
  • 不满足3 个对齐条件种的任何一个,然后编译程序进行测试,会发生 write()函数会报错,均是“Invalid argument”错误。

对比测试

  • 直接I/O方式的效率和性能较低,大多数应用程序不会使用直接I/O方式来进行文件I/O操作,通常只在一些特殊的应用场景下才会考虑使用。然而,我们可以利用直接I/O方式来测试磁盘设备的读写速率,因为这种测试方式相比普通I/O方式更加准确。

8、stdio缓冲

标准I/O的stdio缓冲

  • 标志I/O在应用层维护了自己的缓冲区,把这个缓冲区称为stdio缓冲

    • 标准 I/O(fopen、fread、fwrite、fclose、fseek 等)是 C 语言标准库函数

    • 文件 I/O(open、read、write、
      close、lseek 等)是系统调用

stdio缓冲的缓冲类型

  • 1、无缓冲_IONBF

    • 不对 I/O 进行缓冲(无缓冲)。意味着每个标准 I/O 函数将立即调用 write()或者 read(),并且忽略 buf 和 size 参数,可以分别指定两个参数为 NULL 和 0。标准错误 stderr 默认属于这一种类型,从而保证错误信息能够立即输出。
  • 2、行缓冲_IOLBF

    • 采用行缓冲 I/O。在这种情况下,当在输入或输出中遇到换行符"\n"时,标准 I/O 才会执
      行文件 I/O 操作。对于输出流,在输出一个换行符前将数据缓存(除非缓冲区已经被填满),当输出换行符时,再将这一行数据通过文件 I/O write()函数刷入到内核缓冲区中;对于输入流,每次读取一行数据。对于终端设备默认采用的就是行缓冲模式,譬如标准输入和标准输出。
  • 3、全缓冲_IOFBF

    • 采用全缓冲 I/O。在这种情况下,在填满 stdio 缓冲区后才进行文件 I/O 操作(read、write)。对于输出流,当 fwrite 写入文件的数据填满缓冲区时,才调用 write()将 stdio 缓冲区中的数据刷入 内核缓冲区;对于输入流,每次读取 stdio 缓冲区大小个字节数据。默认普通磁盘上的常规文件默认常用这种缓冲模式。

对stdio缓冲进行设置

  • setvbuf()函数

    • 对文件的 stdio 缓冲区进行设置,譬如缓冲区的缓冲模式、缓冲区的大小、起始地址等

    • #include <stdio.h>
      int setvbuf(FILE *stream, char *buf, int mode, size_t size);

      • stream:FILE 指针,用于指定对应的文件,每一个文件都可以设置它对应的 stdio 缓冲区

      • 如果参数buf不为NULL,则buf指向大小为size的内存区域将被用作该文件的stdio缓冲区。因为stdio库会使用buf指向的缓冲区,所以应该以动态方式(在堆内存中分配,比如使用malloc)或静态方式在堆中为该缓冲区分配空间,而不是在栈上分配函数内的自动变量(局部变量)。

      • 如果buf等于NULL,则stdio库会自动分配一块空间作为该文件的stdio缓冲区(除非参数mode配置为非缓冲模式)

      • mode:参数 mode 用于指定缓冲区的缓冲类型

      • size:指定缓冲区的大小

      • 返回值:成功返回 0,失败将返回一个非 0 值,并且会设置 errno

    • 当stdio缓冲区中的数据被刷新到内核缓冲区或被读取后,这些数据就不再存在于缓冲区中,而是被刷新到了内核缓冲区或被读取走了。

  • setbuf()函数

    • setbuf()函数构建与 setvbuf()之上,执行类似的任务

    • #include <stdio.h>
      void setbuf(FILE *stream, char *buf);

    • setbuf()调用除了不返回函数结果(void)外,就相当于:

      • setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);

      • 要么 将 buf 设置为 NULL 以表示无缓冲 ,要么指向由调 用者分配 的 BUFSIZ 个字节大小的 缓冲区
        (BUFSIZ 定义于头文件<stdio.h>中,该值通常为 8192)

  • setbuffer()函数

    • setbuffer()函数类似于 setbuf(),但允许调用者指定 buf 缓冲区的大小

    • #include <stdio.h>
      void setbuffer(FILE *stream, char *buf, size_t size);

    • setbuffer()调用除了不返回函数结果(void)外,就相当于:

      • setvbuf(stream, buf, buf ? _IOFBF : _IONBF, size);

刷新stdio缓冲

  • 无论采取何种缓冲模式,在任何时候都可以使用库函数fflush()来强制刷新(将输出到stdio缓冲区中的数据写入到内核缓冲区,通过write()函数)stdio缓冲区。该函数会刷新指定文件的stdio输出缓冲区。

    • #include <stdio.h>
      int fflush(FILE *stream);

      • stream 指定需要进行强制刷新的文件,如果该参数设置为 NULL,则表示刷新所有的 stdio 缓冲区

      • 调用成功返回 0,否则将返回-1,并设置 errno

    • 调用fclose()函数也会去刷新stdio缓冲

  • 程序退出时刷新 stdio 缓冲区

9、I/O缓冲小结

10、文件描述符与FILE指针互转

fdopen()函数

  • 可以将文件 I/O 中所使用的文件描述符转换为标准 I/O 中使用的 FILE 指针

  • FILE *fdopen(int fd, const char *mode);

    • 返回值得到文件对应的 FILE 指针

    • mode参数与文件描述符 fd 的访问模式不一致,则会导致调用 fdopen()失败,返回NULL

fileno()函数

  • 可以将标准 I/O 中使用的 FILE 指针转换为文件 I/O 中所使用的文件描述符

  • int fileno(FILE *stream);

    • 返回值得到文件描述符

    • 如果转换错误将返回-1,并且会设置 errno

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

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

相关文章

如何在Ubuntu 24.04或23.04中加密主文件夹

最新版本的 Ubuntu 强制加密整个磁盘&#xff0c;而不仅仅是一个分区&#xff0c;这意味着双系统用户无法完全加密他们的 Ubuntu 机器&#xff0c;因此加密你的Home 文件夹是最佳选择。 对于不熟悉磁盘加密的人来说&#xff0c;这是一种通过加密来保护 Ubuntu 文件的方法。这个…

Java基于Spring Boot框架的校园外卖服务系统设计与实现(附源码,说明文档)

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

集成学习案例-幸福感预测

集成学习案例一 &#xff08;幸福感预测&#xff09; 背景介绍 此案例是一个数据挖掘类型的比赛——幸福感预测的baseline。比赛的数据使用的是官方的《中国综合社会调查&#xff08;CGSS&#xff09;》文件中的调查结果中的数据&#xff0c;其共包含有139个维度的特征&#xf…

HSL和RGB 互转的 原理 分析

定义 HSL即色相、饱和度、亮度&#xff08;英语&#xff1a;Hue, Saturation, Lightness&#xff09;。 色相&#xff08;H&#xff09;是色彩的基本属性&#xff0c;就是平常所说的颜色名称&#xff0c;如红色、黄色等。可以说和光谱对应。取值为0-360度。 …

java语言数据结构(单链表)

前言 不得承认java应用的广泛&#xff0c;所以毅然决定java版本的数据结构和算法专题还是要坚决更新。每日更新2题&#xff0c;希望学习的小伙伴可以关注一波跟上&#xff0c;评论区欢迎讨论交流。 实现原理 节点&#xff08;Node&#xff09;&#xff1a;链表的基本构建单元…

Qt | QLineEdit 类(行编辑器)

01、上节回顾 Qt | QComboBox(组合框)02、QLineEdit 1、QLineEdit 类是 QWidget 类的直接子类,该类实现了一个单行的 输入部件,即行编辑器,见右图 2、验证器(QValidator 类)和输入掩码简介:主要作用是验证用户输入的字符是否符合验证器 的要求,即限制对用户的输入,比…

Windows环境编译MediaInfo源码详细过程

MediaInfo介绍 MediaInfo是一个自由开源的软件&#xff0c;它提供了一种方法来显示多媒体文件的详细信息&#xff0c;包括视频、音频和图像文件。 以下是关于MediaInfo的一些主要介绍&#xff1a; 功能&#xff1a;MediaInfo可以显示文件的格式、编码信息、长度、比特率、帧率…

Tomcat添加服务以及设置开机自启

下载地址连接 Index of /dist/tomcat&#x1f453; 注意点&#xff1a;不要出现中文路径 #环境变量 CATALINA_HOMED:\apache-tomcat-7.0.62 TOMCAT_HOMED:\apache-tomcat-7.0.62 JAVA_HOMED:\tool\jdk1.8.0_111 PATH%CATALINA_HOME%\bin;%CATALINA_HOME%\lib;%CATALINA_HOME%\…

如何使用Vite快速构建vue项目

1、在自己定义的目录下打开cmd命令窗口&#xff1a;如文件夹目录上面输入cmd回车就可以打开 2、检查 node环境&#xff1a;通过node --version看版本号表示安装好了 3、 使用Vite 快速构建Vue项目 npm init vitelatest qiuqiu.admin 注意&#xff1a;如何你电脑没有装vite首…

C/C++常用的内置的宏定义

常用的C/C 内置宏 这是我在VS2015下运行的 cout << "file " << __FILE__ << endl;cout << "line " << __LINE__ << endl;cout << "date " << __DATE__ << endl;cout << "…

[公开课学习]台大李宏毅-自注意力机制 Transformer

自注意力机制 存在一些问题&#xff0c;将vector set/sequence作为input&#xff0c;例如&#xff1a; 文字处理&#xff1a;将文字用one-hot表示&#xff0c;或者向量空间的向量表示&#xff0c;然后进行翻译任务等语音处理&#xff1a;25ms音频作为一个向量&#xff0c;10m…

开源离线AI笔记应用

前言 Reor 是一款人工智能驱动的桌面笔记应用程序&#xff0c;它能自动链接相关笔记、回答笔记中的问题并提供语义搜索。所有内容都存储在本地&#xff0c;支持 Windows、Linux 和 MacOS。Reor 站在 Ollama、Transformers.js 和 LanceDB 等巨头的肩膀上&#xff0c;使 LLM 和嵌…

C# WCF服务(由于内部错误,服务器无法处理该请求。)

由于内部错误&#xff0c;服务器无法处理该请求。有关该错误的详细信息&#xff0c;请打开服务器上的 IncludeExceptionDetailInFaults (从 ServiceBehaviorAttribute 或从 <serviceDebug> 配置行为)以便将异常信息发送回客户端&#xff0c;或打开对每个 Microsoft .NET …

vue3创建响应式数据ref和reactive的区别

reactive和ref在Vue.js中都是用于创建响应式数据的&#xff0c;但它们之间存在一些区别 定义数据类型不同。ref主要用于定义基本数据类型&#xff0c;如字符串、数字、布尔值等&#xff1b;reactive主要用于定义对象&#xff08;或数组&#xff09;类型的数据&#xff0c;但re…

基于单片机的小型自动浇灌系统设计

摘 要:以单片机为主控芯片,结合传感器和计算机,搭建了一套智能化的浇灌系统;利用LabVIEW 设计并编写了基于状态机程序架构的上位机软件,实现了友好的用户交互界面,实时测量、显示与记录等功能,并由主控芯片进行浇灌。经测试,本系统具有结构简单,研制成本低,运…

STM32学习计划

前言&#xff1a; 这里先记录下STM32的学习计划。 2024/05/08 今天我正在学习的是正点原子的I.MX6ULL APLHA/Mini 开发板的 Linux 之ARM裸机第二期开发的视频教程&#xff0c;会用正点原子的I.MX6ULL开发板学习第二期ARM裸机开发的教程&#xff0c;然后是学习完正点原子的I.M…

别出心裁的自动化网页数据采集:Chrome插件和mitmproxy

别出心裁的自动化网页数据采集&#xff1a;Chrome插件和mitmproxy 前言 在信息时代&#xff0c;数据已成为决策的关键。传统的数据采集方法往往依赖于手动操作或简单的自动化脚本&#xff0c;这限制了数据的时效性和精确性。为了克服这些限制&#xff0c;本文介绍了一种结合C…

基于docker安装flink

文章目录 环境准备Flinkdocker-compose方式二进制部署 KafkaMysql Flink 执行 SQL命令进入SQL客户端CLI执行SQL查询表格模式变更日志模式Tableau模式窗口计算 窗口计算滚动窗口demo滑动窗口 踩坑 环境准备 Flink docker-compose方式 version: "3" services:jobman…

与时代同行,Build with AI 2024 线下活动五月再次开放报名

技术开发日新月异&#xff0c;软硬件迭代和应用场景多样化对开发者提出了更多挑战。面对科技发展潮流&#xff0c;GDG (谷歌开发者社区) 一直秉承开放共创的精神&#xff0c;以热忱之心与开发者们一同探索 AI 的广阔发展前景。 在过去的四月里&#xff0c;我们在北京、上海、深…

数据结构之单单单——链表

一.链表 1&#xff09;链表的概念 链表&#xff08;Linked List&#xff09;是一种物理存储结构上非连续&#xff0c;非顺序的储存结构&#xff0c;数据元素的逻辑顺序是通过链表中指针链接次序实现的。要注意&#xff0c;链表也是线性表----->但链表在物理结构上不是线性的…