前言
本文重点讲述了在内存管理当中的链表与动态内存的一种用法,在讲述这种用法之前,先讲解了数据流的概念,通过数据流的缓存,实现了连续申请内存,进行链表实现。
数据流概念
基于流的IO操作与基于文件描述符的IO操作十分类似。
对流进行操作的第一步是将其打开,可以调用库函数fopen()函数打开一个流,函数会返回一个FILE结构指针,结构体指针包括所开文件的描述符,为流准备的缓冲区指针、大小等。
当执行程序时,三个流会自动打开,分别是标准输入,标准输出和标准错误输出。对应的指针分别是stdin,stout,stderr。
当流被打开之后,就可以执行IO操作了,通过FILE指针,调用相应的库函数进行IO操作。
常见的流操作函数有:
函数 | 作用 |
---|---|
fopen、freopen、fdopen | 打开一个流、打开一个文件对应到流、打开一个流对应到文件 |
fclose | 关闭流 |
setbuf | 设置是否打开缓冲 |
setbuffer | 定义缓冲区大小 |
setlinebuf | 设定为行缓冲 |
setvbuf | 是以上三个函数的实现函数,可通过参数实现以上3个函数 |
fflush | 将缓冲区数据强制写入文件 |
fpurge | 将缓冲区内数据完全清楚 |
fread、fwrite | 直接读取或者写入,可指定读取、写入大小 |
feof | 检查是否到文件末尾 |
ferror | 检查是否出现了读写错误 |
printf、fprintf | 输出到“标准输出流”,输出到指定“流” |
sprintf、snprintf | 输出到字符串、snprintf可控制输出大小 |
scanf、fscanf、sscanf | 输入到“标准输入流”,输入到指定流,从一个字符串输入数据 |
fgetc、getc、getchar | 输出字符 |
fputc、putc、putchar | 输入字符 |
ungetc | 退回字符到流 |
fgets、gets | 读取指定大小数据,余下数据下次读取,gets不能 |
fputs、puts | 同上 |
静态内存与动态内存
静态内存 | 动态内存 | |
---|---|---|
优点 | 1、由编译器分配内存,无需释放,不会内存泄漏。 2、可直接使用变量名调用变量,无需使用指针。 | 1、随时分配,可自由释放 2、自定义大小,减少资源浪费 |
缺点 | 1、无法动态设置内存大小,容易溢出。 2、设置过大,容易造成资源浪费 | 1、管理复杂,容易内存泄漏 2、容易引起程序崩溃 |
链表与动态内存结合
动态内存在申请时,需要知道申请的大小,然后再进行申请,但经常是无法预知将要进行申请的大小的,可以使用链表的方式将其分块保存。
下面介绍一种经典用法:
main函数的主要部分如图所示:
获取输入信息主要由fgets函数完成,该函数基于流进行操作,存在着缓存信息,这里暂不做详细分析。
下面重点图解“添加至链表”
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DATASIZE 10//设置一次存储字符串的大小
typedef struct stringdata
{
char *string;//指向字符串地址
int iscontinuing;//结束符标志
struct stringdata *next;