嵌入式-----c语言(9)堆空间的使用和链表(练习)

内存管理:
1.操作野指针会导致程序崩溃


    注意:操作指针时,注意指针指向的空间是否存在?是否可用?

2.避免产生内存溢出:
    1.存储越界
        当使用strcat、strcpy、strcmp函数时可能会产生内存越界
        应该用strncat、strncpy、strncmp函数替代
    2.越界访问    
        数组避免越界访问 
        字符串缺少\0导致的越界访问

3.堆区空间的使用:
    malloc 
    void *malloc(size_t size);
    功能:
        申请size个字节的堆区空间
    参数:
        size:申请空间的大小
    返回值:
        如果成功,返回指向申请空间的指针
        如果失败,返回NULL
    
    free
    void free(void *ptr);
    功能:
        释放堆区空间 
    参数:
        ptr:堆区空间首地址
    返回值:
        缺省

4.内存泄露:
    申请的堆区空间没有被释放

5.malloc使用场景:
    1.函数体内部的局部变量会随函数结束被回收,可以考虑存放到堆区空间中避免随函数结束回收
    2.C语言中可变长数组可以通过malloc实现
        5 
        10
        20
        30
        40
        50

6.内存碎片:

链表:
1.数组:
    1.数组是有限个元素的集合
    2.数组的空间必须连续 
    3.数组的插入和删除效率低

7.单向链表

这使用的头插法,比较高效简单

linklist.c            单向链表的代码实现
linklist.h            单向链表头文件
main.c                主函数

#ifndef __LINKLIST_H__
#define __LINKLIST_H__

/* 链表节点类型 */
typedef struct node 
{
	int data;								//数据域
	struct node *pnext;						//地址域(下一个节点的地址)
}LinkNode;

extern LinkNode *CreateLinkList(void);
extern int InsertHeadLinkList(LinkNode *phead, int tmpdata);
extern void ShowLinkList(LinkNode *phead);
extern int ModifyLinkList(LinkNode *pHead, int OldDate, int NewData);
extern int DeleteLinkList (LinkNode *pHead,int data);
extern int DestroyLinkList(LinkNode **pphead);

#endif	
#include <stdlib.h>
#include <stdio.h>
#include "linklist.h"

/******************************************
 *函数名:CreateLinkList
 *功  能:
 *		创建一个空单向有头链表
 *参  数:
 *      缺省
 *返回值:
 *		成功返回头结点地址 
 *		失败返回NULL
 *注意事项:
 * 
 ******************************************/
LinkNode *CreateLinkList(void)//函数的返回类型为LinkNode *。
{
	LinkNode *pTmpNode = NULL;

	//1.申请空间 
	pTmpNode = malloc(sizeof(LinkNode));
	if (NULL == pTmpNode)
	{
		return NULL;
	}

	//2.对每个成员赋初值
	pTmpNode->pnext = NULL;

	return pTmpNode;
}

/******************************************
 *函数名:InsertHeadLinkList
 *功  能:
 *		单向链表头插法插入元素
 *参  数:
 *		phead:链表头结点地址 
 *		tmpdata:插入数据
 *返回值:
 *		成功返回0 
 *		失败返回-1
 *注意事项:
 * 
 ******************************************/
int InsertHeadLinkList(LinkNode *phead, int tmpdata)
{
	LinkNode *pTmpNode = NULL;

	//1.申请存放数据的空间
	pTmpNode = malloc(sizeof(LinkNode));
	if (NULL == pTmpNode)
	{
		return -1;
	}

	//2.数据存进去
	pTmpNode->data = tmpdata;
	
	//3.地址域赋值为空白节点的pnext
	pTmpNode->pnext = phead->pnext;

	//4.空白节点的pnext指向新申请节点 
	phead->pnext = pTmpNode;
	
	return 0;
}

/******************************************
 *函数名:ShowLinkList
 *功  能:
 *		打印链表中所有节点的数据
 *参  数:
 *		phead:链表头结点地址 
 *返回值:
 *		缺省
 *注意事项:
 * 
 ******************************************/
void ShowLinkList(LinkNode *phead)
{
	LinkNode *p = NULL;

	p = phead->pnext;
	while (p != NULL)
	{
		printf("%d ", p->data);
		p = p->pnext;
	}
	printf("\n");

	return;
}
/******************************************
 *函数名:ModifyLinkList
 *功  能:
 *		修改链表中节点的数据
 *参  数:
 *		phead:链表头结点地址 
        OldData:旧的数据
		NewData:新的数据
 *返回值:
 *		修改的数据的个数
 *注意事项:
 * 
 ******************************************/

int ModifyLinkList(LinkNode *pHead, int OldDate, int NewData)
{
	int cnt = 0;
	LinkNode *pTmpNode = NULL;

	pTmpNode = pHead->pNnext;
	while(pTmpNode != NULL)
	{
		if(pTmpNode->data == OldDate)
		{
			pTmpNode->data == NewData;
			cnt++;
		}
		pTmpNode = pTmpNode->pNnext;
	}

	return cnt;
}

/******************************************
 *函数名:DeleteLinkList
 *功  能:
 *		删除链表中节点
 *参  数:
 *		phead:链表头结点地址 
		data:要删除的数据
 *返回值:
 *		删除的节点的个数
 *注意事项:
 * 
 ******************************************/
int DeleteLinkList (LinkNode *pHead,int data)
{
	int cnt = 0;
	LinkNode *ptmpnode = NULL;
	LinkNode *pfrontnode = NULL;

	ptmpnode = phead->pnext;
	pfrontnode = phead;

	while(ptmpnode != NULL)
	{
		if(ptmpnode->data == data)
		{
			pfrontnode->pnext = ptmpnode->pnext;
			free(ptmpnode);//释放掉申请的空间,此时ptmpnode变为野指针
			ptmpnode = pfrontnode->pnex;
			cnt++;
		}
		else
		{
			ptmpnode = ptmpnode->pnext;
			pfrontnode = pfrontnode->pnext;
		}

	}

	return cnt;
}
/******************************************
 *函数名:DestroyLinkList
 *功  能:
 *		销毁列表
 *参  数:
 *		phead:链表头结点地址 
 *返回值:
 *		成功返回0
		失败返回-1
 *注意事项:
 * 
 ******************************************/

 int DestroyLinkList(LinkNode **pphead)
 {	
	LinkNode *ptmpnode = NULL;
	LinkNode *pfreenode = NULL;
	
	ptmpnode = *phead;
	while(ptmpnode != NULL)
	{
		pfreenode = ptmpnode;
		ptmpnode = ptmpnode->pnext;
		free(pfreenode);
		pfreenode = ptmpnode;
	}
	**pphead = NULL;//函数想要内改变外面的值需要用指针。
	return 0;
 }
#include <stdio.h>
#include "linklist.h"

int main(void)
{
	LinkNode *plinklist = NULL;
	int i = 0;
	int ret = 0;

	plinklist = CreateLinkList();
	if (NULL == plinklist)
	{
		printf("创建失败\n");
		return -1;
	}

	for (i = 0; i < 10; i++)
	{
		ret = InsertHeadLinkList(plinklist, i);
		if (-1 == ret)
		{
			printf("%d 插入失败!\n", i);
		}
	}

	ShowLinkList(plinklist);
    ModifyLinkList(plinklist,5,500);
    ModifyLinkList(plinklist,3,500);
    ModifyLinkList(plinklist,2,500);
    ShowLinkList(plinklist);
    DeleteLinkList(plinklist,500);
    ShowLinkList(plinklist);
    DestroyLinkList(&plinklist)
	return 0;
}

结果如下:

注意:

是所有的节点的遍历。

主要是找最后一个节点。

关于在linux操作系统中粘贴,复制,剪切

进入之后按Esc------输入v是选择------输入y是复制-----d是剪切-------p是粘贴。

8.内核链表

(1).链表节点的定义

单向链表是节点里面包含数据,在定义结构体的时候就已经定义好了要存放的数据类型,这样必须提前要知道存什么类型的数据。不方便使用。

 

现在内核链表就是数据里面包含节点。定义一个node结构体,这个node结构体只包含了这个节点。用户在使用的时候自己去定义data结构体,这个data结构体成员有前面定义的node结构体,也有自己去定义的数据。

  

这样可以在不知道数据类型的情况下实现这个功能,就是把存什么数据这个交给使用者,不是代码编写的人。具体的使用如下:

这里链表节点的地址等同于数据包含的小节点的地址,但是要进行强制类型转换。

#ifndef __KERLIST_H__
#define __KERLIST_H__

/* 链表节点类型 */
typedef struct node 
{
	struct node *pnext;						//链表下一个节点的地址 
}LinkNode;

extern LinkNode *CreateKerList(void);
extern int InsertHeadKerList(LinkNode *pHead, LinkNode *pNewNode);
extern int ForeachKerList(LinkNode *pHead, int (*pfun)(LinkNode *pTmpNode));
extern LinkNode *SearchKerList(LinkNode *pHead, int (*pcmpfun)(LinkNode *pTmpNode));
extern int DestroyKerList(LinkNode **pHead);

#endif
#include "kerlist.h"
#include <stdlib.h>

/*******************************************************
 *函数名: CreateKerList
 *功  能:
 *		创建一个空内核链表
 *参  数:
 *		缺省
 *返回值:
 *		成功返回表头地址
 *		失败返回NULL
 ******************************************************/
LinkNode *CreateKerList(void)
{
	LinkNode *pTmpNode = NULL;

	pTmpNode = malloc(sizeof(LinkNode));	
	if (NULL == pTmpNode)
	{
		return NULL;
	}

	pTmpNode->pnext = NULL;

	return pTmpNode;
}

/*******************************************************
 *函数名: InsertHeadKerList
 *功  能:
 *		头插法插入节点
 *参  数:
 *		pHead:链表头节点地址
 *		pNewNode:要插入的数据节点地址 
 *返回值:
 *		成功返回0
 *		失败返回-1
 ******************************************************/
int InsertHeadKerList(LinkNode *pHead, LinkNode *pNewNode)
{
	if (NULL == pNewNode || NULL == pHead)
	{
		return -1;
	}

	pNewNode->pnext = pHead->pnext;
	pHead->pnext = pNewNode;
	
	return 0;
}

/*******************************************************
 *函数名: InsertTailKerList
 *功  能:
 *		尾插法插入节点
 *参  数:
 *		pHead:链表头节点地址
 *		pNewNode:要插入的数据节点地址 
 *返回值:
 *		成功返回0
 *		失败返回-1
 ******************************************************/
int InsertTailKerList(LinkNode *pHead, void *pNewNode)
{
	LinkNode *pTmpNode = NULL;

	if (NULL == pNewNode || NULL == pHead)
	{
		return -1;
	}
	
	pTmpNode = pHead;
	while (pTmpNode->pnext != NULL)
	{
		pTmpNode = pTmpNode->pnext;
	}

	((LinkNode *)pNewNode)->pnext = NULL;
	pTmpNode->pnext = pNewNode;
	
	return 0;
}

/*******************************************************
 *函数名: ForeachKerList
 *功  能:
 *		遍历链表中每个节点元素
 *参  数:
 *		pHead:链表头节点地址
 *		pfun:对每个链表节点所做的操作
 *返回值:
 *		成功返回0
 *		失败返回-1
 ******************************************************/
int ForeachKerList(LinkNode *pHead, int (*pfun)(LinkNode *pTmpNode))
{
	LinkNode *pTmpNode = NULL;
	int ret = 0;

	pTmpNode = pHead->pnext;
	while (pTmpNode != NULL)
	{
		ret = pfun(pTmpNode);
		if (-1 == ret)
		{
			return -1;
		}
		pTmpNode = pTmpNode->pnext;
	}

	return 0;
}

/*******************************************************
 *函数名: SearchKerList
 *功  能:
 *		查找链表中的元素
 *参  数:
 *		pHead:链表头节点地址
 *		pcmpfun:匹配条件 
 *返回值:
 *		成功返回找到节点的地址
 *		失败返回NULL
 ******************************************************/
LinkNode *SearchKerList(LinkNode *pHead, int (*pcmpfun)(LinkNode *pTmpNode))
{
	LinkNode *pTmpNode = NULL;
	
	pTmpNode = pHead->pnext;
	while (pTmpNode != NULL)
	{
		if (pcmpfun(pTmpNode))
		{
			return pTmpNode;
		}
		pTmpNode = pTmpNode->pnext;
	}
	
	return NULL;
}

/*******************************************************
 *函数名: DestroyKerList
 *功  能:
 *		销毁内核链表
 *参  数:
 *		pHead:链表头节点地址
 *返回值:
 *		成功返回0
 *		失败返回-1
 ******************************************************/
int DestroyKerList(LinkNode **pHead)
{
	if (*pHead != NULL)
	{
		free(*pHead);//只需要销毁头节点,因为后面的是用户自己创建的需要用户自己去销毁
	}
	*pHead = NULL;

	return 0;
}
#include "kerlist.h"
#include <stdio.h>

typedef struct data
{
	LinkNode node;
	int data;
}datatype;

int PrintData(LinkNode *pTmpNode)
{
	datatype *pTmp = (datatype *)pTmpNode;//将pTmpNode强制类型转换并赋值给pTmp
	
	printf("%d ", pTmp->data);

	return 0;
}

int compare(LinkNode *pTmpNode)
{
	datatype *ptmp = (datatype *)pTmpNode;
	
	if (ptmp->data == 2)
	{
		return 1;
	}
	
	return 0;
}

int main(void)
{
	LinkNode *phead = NULL;
	LinkNode *pnode = NULL;
	datatype data[10];
	int i = 0;

	phead = CreateKerList();
	
	for (i = 0; i < 10; i++)
	{
		data[i].data = i+1;
		InsertHeadKerList(phead, (LinkNode *)&data[i]);
	}
	
	ForeachKerList(phead, PrintData);
	
	pnode = SearchKerList(phead, compare);
	printf("pnode->data: %d\n", ((datatype *)pnode)->data);
	DestroyKerList(&phead);

	return 0;
}
#include "kerlist.h"
#include <stdio.h>

typedef struct student 
{
	LinkNode node;
	char name[32];
	char sex;
	int age;
	int score;
}stu_t;

int PrintStuInfo(void *pdata)
{
	stu_t *ptmp = pdata;

	printf("姓名:%s\n", ptmp->name);
	printf("性别:%c\n", ptmp->sex);
	printf("年龄:%d\n", ptmp->age);
	printf("成绩:%d\n", ptmp->score);

	return 0;
}

int compare(void *pnode)
{
	stu_t *pstu = pnode;
	if (pstu->score > 90)
	{
		return 1;
	}

	return 0;
}

int main(void)
{
	stu_t a = {
  
  {NULL}, "zhangsan", 'm', 19, 100};
	stu_t b = {
  
  {NULL}, "lisi", 'm', 19, 70};
	stu_t c = {
  
  {NULL}, "wanger", 'f', 19, 90};
	LinkNode *pHead = NULL;
	LinkNode *pTmpNode = NULL;

	pHead = CreateKerList();
	InsertTailKerList(pHead, &a);
	InsertTailKerList(pHead, &b);
	InsertTailKerList(pHead, &c);
	ForeachKerList(pHead, PrintStuInfo);
	pTmpNode = SearchKerList(pHead, compare);
	printf("%s\n", ((stu_t *)pTmpNode)->name);
	DestroyKerList(&pHead);

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值