5-1动态内存分配,分配的是堆内存的空间

  • 分配内存函数 (都集中在库函数 stdlib.h  中)
void *malloc (unsigned int num_bytes); //指定分配内存空间大小,大小为 num_bytes字节,其值是随机值。
void *calloc (unsigned num ,unsigned size); //参数包含元素的数量和每个元素的字节数,内存空间为num*sie
void *realloc(void *ptr,size_t size); //调用该函数对内存空间进行重新分配,ptr指向已有的内存空间,size用来指定重新分配后所得整个空间大小

    在使用动态分配之前,首先要判断是否分配成功。

  • 内存的释放函数原型:
void free(void *ptr);   //动态分配的内存使用结束后,要及时释放,

  内存释放后建议把指针指向NULL

5-2队列(初始化,入队,出队,判断空,判断满)

  • 单向队列

  

  • 循环队列  (队头和队尾有两种情况会指向同一位置,一是队列空了,二是队列满了)
#define QueueSize_UartLen 8
typedef struct
{
int front; //队头
int rear; //队尾
int counter; //记录队列元素的个数
int uart_data[QueneSize_UartLen]; //定义数组用来存储队列的元素
}CIRQUEUE_UART; //定义结构体,用typedef把结构体重新命名为CIRQUEUE_UART void InitQueue(CIRQUEUE_UART *queue) //初始化形参,CIRQUEUE_UART类型的指针变量queue,队列的初始化
{
queue->front=0; //->与指向结构体变量的指针相连,表示指向结构体变量指针的成员(左边为指针,注意与 . 的区别)
queue->rear=0;
queue->counter=0;
} int Inqueue(CIRQUEUE_UART *queue,int data) //入队
{
if(QueueFull(queue)) //队满判断
{
return 0; //输出队满提示
}
else
{
queue->uart_data[queue->rear]=data; //queue->rear指向队尾待插入数据位置
queue->counter++; //计数器加1
queue->rear=(queue->rear+1)%QueueSize_UartLen; //然后指queue->rear向下一个待插入数据的位置
return 1;
}
} int OutQueue(CIRQUEUE_UART *queue,int *p_data) //出队 通过指针p_data取出队的数据
{
if(QueueEmpty(queue))
{
return 0;
}
else
{
*p_data=queue->data(front); //先把出队的数据元素取出放在p_data
queue->counter--; //计数器减1
queue->front=(queue->front+1)%QueueSize_UartLen; //然后指queue->front向下一个位置
return 1;
}
} int QueueEmpty(CIRQUEUE_UART *queue) //判断队空
{
return queue->count==0;
} int QueueFull(CIRQUEUE_UART *queue) //判断队满
{
return queue->counter==QueueSize_UartLen;
}
  • 链式队列

  构成链表中的每一个存储节点都包括一个值域和一个指针域,而指针域指向的是下一个存储节点的,则称该链表为单链表,在一个单链表中第一个节点的指针称为表头指针,最后一个节点被称为表尾节点,表尾节点的指针域的值为空。

  在一个单链表中,除表头节点外,每一个每个结点都由前一个结点的指针域所指向,第一个节点只能有另设的表头指针所指向。当访问一个单链表时候,只能从表头指针出发,首先访问第一个节点,然后由第一个节点的指针域指向第二个节点的地址。

  空队列时,头指针front和尾指针rear都指向头结点。

  

  单链表只要头节点就可以访问所有的链表元素,融入队列的特性,一个指针是不不够的。队列删除(出队)在对头,插入(入队)在队尾。

  头指针front指向链队的头结点,每个结点对应一个数据;尾指针rear指向终端结点。

typedef struct LinkNode_t       //队列结点结构
{
int data;
struct LinkNode_t *next;
}LinkNode;
typedef struct LinkPoint_t //队列链表结构
{
struct LinkNode_t *front;
struct LinkNode_t *rear;
}LinkQueue;
LinkQueue *queue;
LinkNode *node; LinkQueue LinkQueueInit() //初始化,建立一个带有队头的空队列
{
queue_t=(LinkQueue)malloc(sizeof(LinkQueue)); //因为在LinkQueue中定义了一个结构体指针,必须对其进行分配内存。
node=(LinkQueue)malloc(sizeof(LinkNode)); //同上
node->next=NULL;
queue_t->front=queue->rear=node;
return queue_t;
} void InlinkQueue(LinkQueue *queue,int data) //入队
{
node=(LinkNode)malloc(sizeof(LinkNode));
node->data=data;
node->next=queue->rear->next; //node->next指向data插入前、尾部指针指向的next的位置(queue->rear->next)。
queue->rear->next=node; //新插入的数据或结点成了新的队尾,队尾指针queue->rear->next指向新插入的node结点
queue->rear=node; //最后让新插入的数据或结点成为新的队尾。
} void OutQueue(LinkQueue *queue) //出队
{
int data;
if(!LQEmpty(queue)) //判空
{
node=queue->front->next;
queue->front->next=node->next;
data=node->data;
if(node==queue->rear) //如果只有一个元素,当他出队时队列就成了空队,需要修改为尾部指针
{
queue->rear=queue->front;
}
free(node);
return data;
}
} int LQEmpty(LinkQueue *queue) //对空判断
{
if(queue->front==queue->rear)
{
return 1;
}
else
{
return 0;
}
}

  链队没有判断队满的情况,实际操作没有必要,因为链队继承了动态链表的操作。入队时会进行动态分配内存空间,出队时,则进行了释放。

  补充:结构体中定义另外一个结构体。

5-3堆栈(初始化,进栈,出栈,栈空的判断,栈满的判断,取栈顶元素)

  

1.采用指向栈顶、栈底两个指针时:
typedef struct
{
int top;
int data[10];
int bottom;
}stack_rf;
stack_rf *p_rf_data; // p_rf_data->top-p_rf_data->bottom==10; //判断栈是否为满
p_rf_data->top-p_rf_data->bottom==0; //判断栈是否为空 *(p_rf_data->top-1) //栈顶元素
*(p_rf_data->bottom) //栈底元素 2.只采用栈顶一个指针时:
#define Len_Uart 10;
typedef struct
{
int top;
int uart_data[Len_Uart];
}stack_uart; void InitStack(stack_uart *stack)
{
stack->top=0; //栈的初始化
} int PushStack(stack_uart *stack,int data) //进栈
{
if(StackFull(stack)) //栈满判断
{
//输出栈满提示
return(0);
}
else
{
stack->uart_data[stack->top]=data;
stack->top++;
return(1);
}
} int PopStack(stack_uart *stack) //出栈
{
int data;
if(StackEmpty(stack)) //栈空判断
{
return 0; //输出栈空提示
}
else
{
stack->top--;
data=stack->data[stack->top];
return data;
}
} int StackEmpty(stack_uart *stack) //栈空判断
{
return(stack->top==0);
} int StackFull(stack_uart *stack) //栈满判断
{
return(stack->top==Len_Uart);
} int StackTop(stack_uart *stack,int *p_topdata) //取栈顶元素
{
if(StackEmpty())
{
//输出栈空提示
return 0;
}
else
{
*p_topdata=stack->uart_data[stack->top-1];
return 1;
}
}

5-4链表(链表建立,链表初始化,链表插入,链表删除)

  

  单链表:头结点没有值域,只有链域。专门存放第一个结点的地址。尾结点,有值域也有链域,链域始终为NULL。

             

  循环链表:由单链表演变而来,循环链表的尾结点的链域指向链表头的结点

  两者区别:(1)单链表需要专门创建一个头结点存放第一个节点的地址,尾部节点链域为NULL;循环链表不需要,只是最后一个链域指向表头结点。

       (2)链尾判断,单链表只需要判断链域值是否为NULL;循环链表只需要判断该结点的链域值是否指向链表头结点。

typedef struct LinkNode    //定义链表结点类型
{
int data;
struct LinkNode *next;
}*List; List InitList(void) //链表初始化
{
List linknode_t;
linknode_t=(list)malloc(sozeof(list)); //动态分配内存空间给linknode_t
if(!linknode_t)
{
//输出失败提示
return 0;
}
else
{
linknode_t->next=linknode_t;
return linknode_t;
}
} List g_DebiList;
int main(void) //在main中调用InitList()函数
{
g_DevList=InitList();
return 0;
} 链表的操作
typedef struct DEVICE_PROPERTY_t
{
int data;
struct DEVICE_PROPERTY_t *next;
}DEVICE_PROPERTY_t;
typedef unsigned char uint8_t;
#define DEVICELIST_MAX 5;
DEVICE_PROPERTY_t g_RegDeviceList[DEVICELIST_MAX];
DEVICE_PROPERTY_t *g_LastRegDevice;
uint8_t g_DeviceCnt=0; voide DevListInit(void) //链表初始化
{
uint8_t i;
for(i=0;i<DEVICELIST_MAX;i++)
{
g_RegDeviceList[i].next=NULL;
}
g_lastRegDevice=NULL;
g_DeviceCnt=0
} DEVICE_PROPERTY_t *FindVacancy(void) //寻找插入点
{
uint8_t i;
if(g_DeviceCnt<DEVICELIST_MAX)
{
for(i=0;i<EEVICELIST_MAX;i++)
{
if(g_RegDeviceList[i].next==NULL)
{
return(&g_RegDeviceList[i]);
}
}
return 0;
}
else
{
return(NULL);
}
} uint8_t Insert(uint8_t data) //链表插入
{
DEVICE_PROPERTY_t *tempptr,*ptr;
temptr =FindVacancy();
if(tempptr!=null)
{
tempptr->data=data;
if(!g_DeviceCnt)
{
tempptr->next=tmpptr;
g_ListRegDevice=tempptr;
}
else
{
ptr=g_LastRegDevice->next; //暂存原来尾结点的链域
g_LastRegDevice->next=tempptr; //让原来尾结点的链域指向新插入的结点,即g_LastRegDevice->next=tempptr;
tempptr->next=ptr; //让新插入的结点成为尾结点,即链域指向原来尾结点链域所指向的位置
}
g_DeviceCnt++;
return 1;
}
return 0;
} uint8_t DeleteDevicefromlist(uint8_t data) //链表删除(data即为要删除的结点)
{
uint8_t i,j;
DEVICE_PROPERTY_t *nextdevice;
for(i=0;i<g_DeviceCnt;i++) //通过判断来指定结点的值域是否是要删除的值域data
{
if(g_LastRegDevice->data==data)
{
nextdevce=g_ListRegDevice->next; //将该结点的链域指向的结点指针,也就是将要删除的结点的下一个结点
g_LastRegDevice->next=NULL; //把该节点的链域置为NULL
g_DeviceCnt--;
g_LastRegDevice=nextdevice; //让删除结点的下一个结点成为尾结点(删除是操作的逆过程)
if(g_DeviceCnt)
{
for(j=0;j<g_DeviceCnt-1;j++)
{
g_ListRegDevice->next=nextdevice;
}
g_ListRegDevice->next=nextdevice;
}
return 1;
}
g_LastRegDevice=g_LastRegDevice->next;
}
return 0;
}

5-5树

  树为非线性结构,对于二叉树首先是二叉树的创建和遍历

typedef struct tree_node   //运用链式存储结构
{
char data; //一个值域两个链域,值域存储结点本身的数值
struct tree_node *lchild,*rchild; //链域分别存储结点左子树和又子树的地址
}BT_Node;
BT_Node *tree; //定义一个指针tree,用来执行那个即将建立的树 BT_Node *Creat_BTree(BT_Node *tree) //创建二叉树
{
char ch;
ch=getchar(); //从键盘输入一个字符,
if(ch=='*')
{
tree=NULL;
}
else //如果不是字符,则分配存储空间
{
tree=(BT_Node *)malloc(Tree_NodeLen);
tree->data=ch;
tree->lchild=Creat_BTree(tree->lchild); //调用创建函数本身,创建结点的左子树和又子树(这是函数的递归调用)
tree->rchild=Creat_BTree(tree->rchild);
}
return(tree);
}

 二叉树分为:前序遍历,中序遍历,后序遍历

示例:二叉树3种遍历方式的应用 

#include <stdio.h>
#include <malloc.h> typedef struct tree_node
{
char data;
struct tree_node *lchild,*rchild;
}BT_Node; #define Tree_NodeLen sizeof(BT_Node)
BT_Node *tree;
BT_Node *Creat_BTree(BT_Node *tree);
void Visit_Node(BT_Node *tree);
void Pre_Order(BT_Node *tree);
void Mid_Order(BT_Node *tree);
void After_Order(BT_Node *tree);
int main(void)
{
printf("请输入树节点:\n");
tree=Creat_BTree(tree);
if(tree)
{
printf("\n前序遍历:\n");
Pre_Order(tree);
printf("\n"); printf("\n中序遍历:\n");
Mid_Order(tree);
printf("\n"); printf("\n后序遍历:\n");
After_Order(tree);
printf("\n");
}
printf("\n");
return 0;
} BT_Node *Creat_BTree(BT_Node *tree)
{
char ch;
ch=getchar();
if(ch=='*')
{
tree=NULL;
}
else
{
tree=(BT_Node *)malloc(Tree_NodeLen);
tree->data=ch;
tree->lchild=Creat_BTree(tree->lchild);
tree->rchild =Creat_BTree(tree->rchild );
}
return(tree);
} void Visit_Node(BT_Node *tree)
{
printf(" ");
putchar(tree->data);
printf("\t");
} void Pre_Order(BT_Node *tree)
{
if(!tree)
{
return ;
}
else
{
Visit_Node(tree);
Pre_Order(tree->lchild );
Pre_Order(tree->rchild );
}
} void Mid_Order(BT_Node *tree)
{
if(!tree)
{
return;
}
else
{
Mid_Order(tree->lchild );
Visit_Node(tree);
Mid_Order(tree->rchild );
}
} void After_Order(BT_Node *tree)
{
if(!tree)
{
return;
}
else
{
After_Order(tree->lchild );
After_Order(tree->rchild );
Visit_Node(tree);
}
}

C指针(4)——数据结构中指针的应用(非常重要)的更多相关文章

  1. 【转载】C/C++杂记:深入理解数据成员指针、函数成员指针

    原文:C/C++杂记:深入理解数据成员指针.函数成员指针 1. 数据成员指针 对于普通指针变量来说,其值是它所指向的地址,0表示空指针.而对于数据成员指针变量来说,其值是数据成员所在地址相对于对象起始 ...

  2. C/C++杂记:深入理解数据成员指针、函数成员指针

    1. 数据成员指针 对于普通指针变量来说,其值是它所指向的地址,0表示空指针. 而对于数据成员指针变量来说,其值是数据成员所在地址相对于对象起始地址的偏移值,空指针用-1表示.例: 代码示例: str ...

  3. 21深入理解C指针之---通过指针传递数据

    一.在C程序设计中,主要活动就是操纵数据 1.数据传递:将数据作为参数传入参数和将数据作为数据返回两种 2.函数: 1).函数类型:主要是指函数返回数据的类型,可以是基本类型或复杂数据类型,即使函数无 ...

  4. [Data Structure] 数据结构中各种树

    数据结构中有很多树的结构,其中包括二叉树.二叉搜索树.2-3树.红黑树等等.本文中对数据结构中常见的几种树的概念和用途进行了汇总,不求严格精准,但求简单易懂. 1. 二叉树 二叉树是数据结构中一种重要 ...

  5. 浅析数据结构中栈与C实现

    最近在搞摄像头驱动,o()︿︶)o 唉,别提有多烦,一堆寄存器就有人受的了--特么这不是单片机的开发,这是内核驱动开发-- 今天放松一下,我们来看看数据结构中的栈,这节的知识点可以说是数据结构中最容易 ...

  6. SCIP:构造数据抽象--数据结构中队列与树的解释

    现在到了数学抽象中最关键的一步:让我们忘记这些符号所表示的对象.不应该在这里停滞不前,有许多操作可以应用于这些符号,而根本不必考虑它们到底代表着什么东西. --Hermann Weyi <思维的 ...

  7. 你必须知道的指针基础-7.void指针与函数指针

    一.不能动的“地址”—void指针 1.1 void指针初探 void *表示一个“不知道类型”的指针,也就不知道从这个指针地址开始多少字节为一个数据.和用int表示指针异曲同工,只是更明确是“指针” ...

  8. 不可或缺 Windows Native (18) - C++: this 指针, 对象数组, 对象和指针, const 对象, const 指针和指向 const 对象的指针, const 对象的引用

    [源码下载] 不可或缺 Windows Native (18) - C++: this 指针, 对象数组, 对象和指针, const 对象,  const 指针和指向 const 对象的指针, con ...

  9. C++中,指针数组和数组指针

    这俩兄弟长得实在太像,以至于经常让人混淆.然而细心领会和甄别就会发现它们大有不同. 前者是指针数组,后者是指向数组的指针.更详细地说. 前: 指针数组;是一个元素全为指针的数组. 后: 数组指针;可以 ...

随机推荐

  1. 如何深入理解一套MQ消息中间件

    怎样算是理解了一套MQ中间件呢?原来一知半解的我列了几个维度:demo跑起来,理解其投递次数的语义,理解其事务的特性等等.这是一种角度,但总有种看山不是山的一知半解的感觉.再问一层,比如为什么Kafk ...

  2. 一个典型的后台软件系统的设计复盘——(二)如何id一个事物

    这个话题,可以从类与对象说起. Dog dog1 = new Dog(); 哪个是类,哪个是对象?这个问题搞不清楚,后面就无从说起了.然后两个程序员之间沟通说,那个狗有问题.除非两人很默契,不然另一人 ...

  3. Manifold Learning: ISOMAP

    转:http://hi.baidu.com/chb_seaok/item/faa54786a3ddd1d7d1f8cd0b 在常见的降维方法中,PCA和LDA是最为常用的两种降维方法.PCA是一种无监 ...

  4. day13 面向对象练习

    //1 public class Area_interface { public static void main(String[] args) { Rect r = new Rect(15, 12) ...

  5. linux 配置 tftp

    环境:ubuntu 目的:搭建嵌入式板子网络环境 1)下载tftpd-hpa tftp-hpa 前者是服务器,后者是客户端 $sudo apt-get install tftpd-hpa tftp-h ...

  6. MongoDB删除文档

    db.collection.deleteOne() 删除单个文档db.collection.deleteMany() 删除多个文档db.collection.remove() 删除单/多个文档,db. ...

  7. MongoDB创建集合、删除集合

    创建集合 createCollection() 方法 在 MongoDB 中,创建集合采用 db.createCollection(name, options) 方法. 语法格式 createColl ...

  8. MySQL语法三:数据控制语句

    数据控制语句MCL(GRANT,REVOKE,COMMIT,ROLLBACK)

  9. CRUD是什么?数据结构、增查删改

    http://blog.csdn.net/penginpha/article/details/6920444 CRUD是指在做计算处理时的增加(Create).查询(Retrieve)(重新得到数据) ...

  10. BZOJ 3289: Mato的文件管理 【莫队 + 树状数组】

    任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=3289 3289: Mato的文件管理 Time Limit: 40 Sec  Memory ...