Linux下的C语言编程——流概念与内存管理

前言

本文重点讲述了在内存管理当中的链表与动态内存的一种用法,在讲述这种用法之前,先讲解了数据流的概念,通过数据流的缓存,实现了连续申请内存,进行链表实现。

数据流概念

基于流的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;//指向下一个结构体
}mydata;
mydata *append(mydata *start,char *input);//添加结构体
void displaydata(mydata *start);//显示字符串
void freedata(mydata *start);//释放字符串

int main(void)
{
	char input[DATASIZE];//输入字符串
	mydata *start=NULL;//第一个结构体,指向空地址
	printf("ENTER SOME DATA,AND PRESS Ctrl+D WHEN DONE. \n");
	while(fgets(input,sizeof(input),stdin))//满10个字节,就会返回一次1,基于流的操作
	{
		printf("your input words:%s\n",input);//打印一次完成
		start=append(start,input);//将输入信息通过start结构体,插入链表
	}
	displaydata(start);//显示字符串
	freedata(start);//释放链表
	return 0;
}

mydata *append(mydata *start,char *input)
{
	mydata *cur=start,*prev=NULL,*new;//设置3个结构体,分别为“之前”、“当前”、“新的”
	while(cur)//遍历链表,直到cur变为null
	{
		prev=cur;//“之前”变为“当前”,
		cur=cur->next;//继续遍历
	}
	cur=prev;//“当前”变为“之前”,用于配置next,因为“之前”的next为null
	new=malloc(sizeof(mydata));//为new结构体申请内存
	if(!new)//异常处理
	{
		printf("COULDN'T ALLOCATE MEMORY!\n");
		exit(-1);
	}
	if(cur)//如果存在当前地址,则赋值
		cur->next=new;
	else
		start=new;//start地址指向新的结构体地址
	cur=new;//当前地址设为新的结构体地址
	if(!(cur->string=malloc(sizeof(input)+1)))//当前的结构体中的string地址指向新的申请的内存
	{
		printf("ERROR ALLOCATING MEMORY!\n");
		exit(-1);
	}
	strcpy(cur->string,input);//将输入信息放在string后的内存当中
	cur->iscontinuing=!(input[strlen(input)-1]=='\n'||input[strlen(input)-1]=='\r');//判断是否收到结束符
	cur->next=NULL;
	return start;//start地址已被修改为最新的start
}

void displaydata(mydata* start)
{
	mydata *cur;
	int linecounter=0,structcounter=0;//行数,结构体数
	int newline=1;//标志位
	cur=start;
	while(cur)//遍历链表
	{
		if(newline)//判断是否链表末尾
			printf("LINE%d:",++linecounter);
		structcounter++;
		printf("%s",cur->string);//打印字符串
		newline=!cur->iscontinuing;
		cur=cur->next;//指向下一个
	}
	printf("THIS DATA CONTAINED %d LINES AND WAS STORED IN %d STRUCTS.\n",linecounter,structcounter);
}
void freedata(mydata *start)
{
	mydata *cur,*next=NULL;
	cur=start;
	while(cur)//遍历链表
	{
		next=cur->next;//指向下一结构体
		free(cur->string);//释放内存
		free(cur);//释放内存
		cur=next;//指向下一结构体
	}
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔通天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值