IO数据结构总结复习

目录

一、IO

1.标准IO和文件IO

2.系统调用和库函数

3.文件描述符和流指针

4.标准IO

4.1对文件进行操作

4.1.1打开文件

4.1.2操作文件

5.文件IO

5.1相关函数

6.静态库和动态库

6.1静态库制作

6.2动态库制作

二、数据结构

1.线性结构

1.1顺序结构

1.2链式结构

1.3栈

1.4队列

2.树形结构

2.1二叉树

2.2平衡二叉树

2.3赫夫曼树

2.4线索二叉树

2.5树的的顺序存储

2.6树的的链式存储

3.网状结构

3.3网状结构的顺序存储

3.4网状结构的链式存储

4.算法

4.1常见的算法

4.2算法的好坏


一、IO

1.标准IO和文件IO

区别:
标准IO:
1.标准IO是由库函数系统提供的,由ANSI C标准定义
2.是带缓冲区的操作,运行效率较高
3.支持跨平台的
4.标准IO操作的依据一般是流指针
文件IO:
1.文件IO是由操作系统提供的,由POSIX(可移植操作系统接口)定义
2.没有缓冲区,运行效率没有标准IO高
3.不支持跨平台的
4.文件IO操作的依据一般是文件描述符(非负整数)

2.系统调用和库函数

1.系统调用一般提供基础的功能,库函数提供较为复杂的功能
2.系统调用一般不能重写,库函数可以重写
3.系统调用运行的时间属于机器时间,库函数运行时间属于用户时间
4.系统调用运行空间属于内核空间,库函数运行空间属于用户空间
5.系统调用的返回值一般是非负整数,库函数的返回值不一定
6.系统调用的运行效率没有库函数的高
7.系统调用的移植性没库函数的好

3.文件描述符和流指针


文件描述符是一个用于标识已打开文件的整数。在Unix和类Unix系统中,文件描述符是非负整数,通常是一个小的非负整数。每个打开的文件都会被分配一个唯一的文件描述符,用于在后续的文件操作中标识该文件。
流指针是一个用于指示文件位置的指针。它指向文件中的某个位置,可以用来读取或写入数据。流指针通常是一个结构体,包含了文件描述符、当前位置等信息。
在C语言中,文件描述符和流指针是通过文件操作函数来使用的。文件操作函数提供了一系列操作文件的函数,如打开文件、读取文件、写入文件等。

4.标准IO

全缓冲:
缓冲区满了才刷新缓冲区,或者强制刷新缓冲区

行缓冲:
碰到换行符刷新缓冲区、缓冲区满了刷新、或者强制刷新缓冲区

不缓冲:
所有的信息到缓冲区之后直接到文件

4.1对文件进行操作

4.1.1打开文件

fopen:

函数功能:打开由参数1描述的文件,打开的方式由参数2确定
函数参数1:需要被打开的文件的路径
函数参数2:打开的方式
r : 以只读的形式打开文件,文件存在则打开,不存在则报错
r+ : 以读、写的形式打开文件,文件存在则打开,不存在则报错
w : 以只写的形式打开文件,文件存在则清空打开,文件不存在则新建
w+ : 以读、写的形式打开文件,文件存在则清空打开,文件不存在则新建
a : 以追加的形式打开文件,文件存在则追加,文件不存在则新建
a+ : 以可读可写(追加)的形式打开文件,文件存在则追加,文件不存在则新建
函数返回值:成功返回:文件流指针
失败返回NULL,并且更新errno

4.1.2操作文件

fgetc
案例:模拟cat命令
函数功能:从stream指示的文件中读取字符
函数参数:需要读字符的文件流
函数返回值:成功返回读到的字符可以是(EOF,表示读完了),失败返回-1

fputc 

函数功能:给stream写了一个字符c
函数参数1:被写的字符
函数参数2:给谁写
函数返回值:成功返回写入的字符,失败返回-1

以行读写:

fgets 
案例:判断一个文件有多少行
函数功能:按行读
函数参数1:读到哪
函数参数2:读多少(实际读到的是size-1,最后一个空间给\0预留) 所以fgets相较于gets是安全的
函数参数3:从哪读
函数返回值:成功返回非0,返回NULL的时候是出错或者没有可读的字符了

fputs

函数功能:给文件写
函数参数1:从哪写
函数参数2:给谁写
函数返回值:成功返回非负整数,失败返回-1

以对象读写:


fread:
fwrite:
案例:数据的读和写
myhead.h
myread.c
函数功能:读
函数参数1:读到哪
函数参数2:一次读多少
函数参数3:总共读多少次数
函数参数4:从哪读
函数返回值:成功返回成功读或写的成员的个数,失败返回0
函数功能:写
函数参数1:从哪写
函数参数2:一次写读多少
函数参数3:总共写多少次
函数参数4:往哪写
函数返回值:成功返回成功读或写的成员的个数,失败返回0

fprintf

案例:每隔3秒获取时间写入文件
函数功能:往指定的流里面输出东西
函数参数1:指定的流
函数参数2……:同printf

fscanf 
函数功能:从指定的流里面获取信息
函数参数1:指定的流
函数参数2……:同scanf

关闭文件:
fclose:
main函数传参:
标准IO相关函数:
函数功能:关闭由参数stream指示的流
函数参数:需要被关闭的流
函数返回值:成功返回0,失败返回-1并且设置errno

fflsh
函数功能:强制刷新由参数 1 指定的流
函数参数如果为 NULL ,则会刷新所有已打开的输出流
函数返回值:成功返回 0 ,失败返回 -1 并且更新 errno
feof
判断文件是否到末尾

fseek
函数功能:给指定的流从参数 3 描述的位置移动参数 2 个大小的位置
参数 1 :给谁移动光标
参数 2 :移动多少
参数 3 :从那开始:
SEEK_SET 从文件开头移动
SEEK_CUR 从文件当前光标指向的位置开始移动
SEEK_END 从文件末尾开始移动
返回值:
成功返回 0 ,失败返回 -1 并且更新 errno
ftell
函数功能:计算由参数 stream 指示的流当前光标处在的位置
函数参数:指定的文件流
函数返回值:成功返回当前处在的位置,失败返回 -1 ,并更新 errno
fileno
函数功能:获取文件流指针里面的文件描述符

5.文件IO

5.1相关函数


open
函数功能:打开文件
函数参数 1 :需要打开的文件路径
函数参数 2 :打开的方式
必须包含如下的其中一个
O_RDONLY : 只读
O_WRONLY : 只写
O_RDWR : 可读可写
还可以有以下的:
O_APPEND: 以追加的形式打开
O_CREAT : 文件存在则打开,不存在则按照 mode 参数描述的权限创建一个普通文件
函数参数 3 :如果文件存在则打开,不存在则按照此参数描述的创建一个普通文件
函数返回值:成功返回文件描述符(非负的最小整数) file description fd
失败返回 -1 ,并且更新 errno
read
函数功能:从 fd 描述的文件中读取 count 个字节的数据给 buf 开始的空间
函数参数 1 :从哪读
函数参数 2 :读到哪
函数参数 3 :读多少
函数返回值:成功返回实际上读到的数目,失败返回 -1 ,并且更新 errno
write
函数功能:把数据从 buf 指示的空间里面写道 fd 里,写了 count 个
函数参数 1 :往哪写
函数参数 2 :从哪写
函数参数 3 :写多少
函数返回值:成功返回写入的个数,失败返回 -1 并且更新 errno
close
函数功能:关闭文件
函数参数:需要关闭的文件的文件描述符
函数返回值:成功返回0,失败返回-1并且更新errno

6.静态库和动态库

6.1静态库制作

步骤1:将c源文件生成对应的.o文件

1: ~/test/3static_lib$ gcc -c add.c -o add.o
2: ~/test/3static_lib​$ gcc -c sub.c -o sub.o 
3: ~/test/3static_lib​$ gcc -c mul.c -o mul.o 
4: ~/test/3static_lib​$ gcc -c div.c -o div.o


步骤2:使用打包工具ar将准备好的.o文件打包为.a文件 libtest.a

1: ~/test/3static_lib$ ar -rcs libtest.a add.o sub.o mul.o div.o


2)静态库使用
静态库制作完成之后,需要将.a文件和头文件一起发布给用户。
假设测试文件为main.c,静态库文件为libtest.a头文件为head.h
编译命令:

1:~/test/4static_test$ gcc test.c -L./ -I./ -ltest -o test


参数说明:

-L:表示要连接的库所在目录
-I./: I(大写i) 表示指定头文件的目录为当前目录
-l(小写L):指定链接时需要的库,去掉前缀和后缀
 

2.3动态库的制作及使用
共享库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。
动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。
按照习惯,一般以“.so”做为文件后缀名。共享库的命名一般分为三个部分:

前缀:lib
库名称:自己定义即可
后缀:.so
所以最终的动态库的名字应该为:libxxx.so

6.2动态库制作

1)找到函数定义的地方,将.c文件编译成.o文件(.o文件里面的是机器语言):

gcc   -c    add.c    -o    add.o

2)把.o文件编译生成libadd.so(注意lib是前缀,add才是库名,.so是后缀):

gcc    -fPIC    -shared    add.o  -o   libadd.so

也可以一步到位:gcc    -fPIC    -shared    add.c  -o   libadd.so

注意我这里头文件没有跟.c文件放同一个目录,所以要指定一下头文件的位置gcc    -fPIC    -shared    add.o  -o   libadd.so  -I../include         (等一下我们讲指定的问题)

3)把生成的库放到/lib下:

4)编译命令

gcc    main.c  -o   main   -Iinclude/    -Llib/   -ladd

要永久设置则修改文件  gedit ~/.bashrc   

二、数据结构

1.线性结构

  • 存储方式简单,可以通过下标或指针直接访问元素。
  • 插入和删除操作相对容易,只需要调整指针或移动元素的位置。
  • 查询操作的效率较高,可以通过下标或指针快速定位元素。

1.1顺序结构

数据元素按照顺序存储在连续的内存空间中,可以通过下标直接访问元素。

1.2链式结构

链式结构:数据元素通过指针链接在一起,每个元素包含数据和指向下一个元素的指针。

1.3栈

一种特殊的线性结构,遵循"先进后出"(LIFO)的原则,只能在栈顶进行插入和删除操作。

1.4队列

一种特殊的线性结构,遵循"先进先出"(FIFO)的原则,可以在队尾插入元素,在队头删除元素。

2.树形结构

  • 树形结构能够更好地表示具有层次关系的数据,如文件系统、组织结构等。
  • 树形结构的遍历方式有多种,如前序遍历、中序遍历、后序遍历等。
  • 二叉树的特殊性使得它的插入、删除和查询操作的时间复杂度较低。

2.1二叉树

二叉树:每个节点最多有两个子节点的树结构。

2.2平衡二叉树

一种特殊的二叉树,左右子树的高度差不超过1,以提高搜索效率。

2.3赫夫曼树

一种特殊的二叉树,用于数据压缩,频率高的字符在树的顶部,频率低的字符在树的底部。

2.4线索二叉树

在二叉树的节点中添加指向前驱和后继节点的线索,以提高遍历效率。

2.5树的的顺序存储

用数组的方式存储树的节点,通过计算节点的索引和父节点的索引之间的关系来访问节点。

2.6树的的链式存储

通过指针链接节点来存储树的结构。

3.网状结构

  • 网状结构能够更好地表示元素之间的多对多关系,如社交网络、交通网络等。
  • 网状结构的存储方式可以选择顺序存储或链式存储,根据具体情况选择合适的方式。
  • 网状结构的遍历和搜索操作相对复杂,通常需要使用图算法来解决。

3.3网状结构的顺序存储

通过矩阵或数组来表示元素之间的关系。

3.4网状结构的链式存储

通过指针链接元素来表示元素之间的关系。

4.算法

  • 可读性:算法的代码是否易于理解和维护。
  • 可靠性:算法在各种输入情况下是否能够正确地得到预期的结果。
  • 可扩展性:算法是否能够处理大规模的数据集。
  • 时间复杂度和空间复杂度:算法的执行时间和所需的内存空间是否在可接受的范围内。

4.1常见的算法

常见的算法包括排序算法、搜索算法、图算法等,用于解决各种问题。

4.2算法的好坏

算法的好坏可以通过时间复杂度和空间复杂度来评估,好的算法应该具有较低的时间复杂度和空间复杂度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值