c/c++语言创建单链表新结点时为啥不直接用结点对象,如直接lnode p;而是非要用指针加malloc或new实现?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c/c++语言创建单链表新结点时为啥不直接用结点对象,如直接lnode p;而是非要用指针加malloc或new实现?相关的知识,希望对你有一定的参考价值。
因为直接创建,节点作为局部变量,将位于堆栈上,等创建节点的函数返回主函数,这些节点也完蛋了。所以要创建在生命期和程序一样长的堆里面。这个任务由malloc或new来完成追问非常感谢!不过我记得还有一个说法,就是自定义类型或结构体不能像int a一样自动申请内存?所以才需要手动申请??但这样的话又和您的回答有些许冲突,从您的回答来看不存在不会自动分配内存的问题,而是会分配到栈中,所以我又迷糊了
追答你可以尝试一下,看看正确的答案究竟是什么
参考技术A 因为你在函数内创建的结点对象是临时对象,在它的作用域外它就释放了,你再用链表去指向它就出错了(指向了一个已释放的地址),而动态分配的内存,不会自动释放,需要你需要的时候手动释放free(ptr)追问非常感谢!不过我记得还有一个说法,就是自定义类型或结构体不能像int a一样自动申请内存?所以才需要手动申请??但这样的话又和您的回答有些许冲突,从您的回答来看不存在不会自动分配内存的问题,而是会分配到栈中,所以我又迷糊了
追答你的那个说法是错误的
struct node ;
struct node mynode; //这里就是自动分配的内存
如同:
int a =208; //以上两个都不需手动释放,因为是自动分配的
又:
int *a =(int*)malloc(sizeof(int));
struct node *ad =(struct node*)malloc(sizeof(struct node));
这两个就需要手动释放,因是自己主动在堆上申请的:
free(a);free(ad);
C语言实现单链表(带头结点)的基本操作
我在之前一篇博客《C语言实现单链表(不带头结点)的基本操作》中具体实现了不带头结点的单链表的11种操作:如计算链表长度、初始化、创建链表、清空链表等等。但是在实际使用中,带头结点的单链表往往比不带头结点的单链表用的更多,使用也更为方便。因为不用单独考虑第一个节点的情况了,第一个节点和其他后续节点的处理全都一样了,简化操作。这篇博客将会来实现带头结点的单链表的11种操作。代码上传至: https://github.com/chenyufeng1991/LinkedList_HeadNode 。
(1)定义带头结点单链表的节点类型
typedef int elemType;
typedef struct NodeList{
int element;
struct NodeList *next;
}Node;
(2)初始化带头结点的单链表【这个很关键】
//1.初始化带头结点的单链表
void InitialList(Node **pNode){
//个人建议每一次malloc分配内存空间后,都要进行判断分配是否成功,也即判断是否为空;
//此时的这个pNode就是一个头结点;
//初始化成功后,其实相当于是一个正常的链表了;
*pNode = (Node *)malloc(sizeof(Node));
if (*pNode == NULL) {
printf("%s函数执行,内存分配失败,初始化单链表失败",__FUNCTION__);
}else{
(*pNode)->next = NULL;
printf("%s函数执行,带头结点的单链表初始化完成\\n",__FUNCTION__);
}
}
(3)尾插法创建带头结点的单链表
//2.创建带头结点的单链表
void CreateList(Node *pNode){
/**
* 就算一开始输入的数字小于等于0,带头结点的单链表都是会创建成功的,只是这个单链表为空而已,也就是里面除了头结点就没有其他节点了。
*/
Node *pInsert;
Node *pMove;
pInsert = (Node *)malloc(sizeof(Node));//需要检测分配内存是否成功 pInsert == NULL ?
memset(pInsert, 0, sizeof(Node));
pInsert->next = NULL;
scanf("%d",&(pInsert->element));
pMove = pNode;
while (pInsert->element > 0) {
pMove->next = pInsert;
pMove = pInsert;
pInsert = (Node *)malloc(sizeof(Node)); //需要检测分配内存是否成功 pInsert == NULL ?
memset(pInsert, 0, sizeof(Node));
pInsert->next = NULL;
scanf("%d",&(pInsert->element));
}
printf("%s函数执行,带头结点的单链表创建成功\\n",__FUNCTION__);
}
(4)打印带头结点的单链表
//3.打印带头结点的单链表
void PrintList(Node *pNode){
/**
* 注意这里,如果单链表为空(只有一个头结点),我也让它打印(打印成功)。只是里面没有元素,打出来是空的而已,所以在控制台上就是一行空的;
*/
Node *pMove;
pMove = pNode->next;
while (pMove != NULL) {
printf("%d ",pMove->element);
pMove = pMove->next;
}
printf("\\n%s函数执行,打印带头结点的单链表成功\\n",__FUNCTION__);
}
(5)清空链表
//4.清除线性表中的所有元素,即释放所有节点(除了头结点),使之成为一个空表
void ClearList(Node *pNode){
Node *pMove;
pMove = pNode->next;
while (pMove != NULL) {
pNode->next = pMove->next;
free(pMove);
pMove = pNode->next;
}
printf("%s函数执行,清空带头结点的链表成功\\n",__FUNCTION__);
}
(6)计算链表长度
//5.返回带头结点的单链表的长度
int SizeList(Node *pNode){
/**
* 当只有一个头结点的时候,size = 0;头节点不计算到链表长度中。
*/
int i = 0;
Node *pMove;
pMove = pNode->next;
while (pMove != NULL) {
i++;
pMove = pMove->next;
}
printf("%s函数执行,带头结点的单链表的长度为:%d\\n",__FUNCTION__,i);
return i;
}
(7)判断链表是否为空
//6.判断带头结点的单链表是否为空,为空则返回1,否则返回0
int IsEmptyList(Node *pNode){
/**
* 当只有一个头结点的时候,该链表就为空
*/
if (pNode->next == NULL) {
printf("%s函数执行,带头结点的链表为空\\n",__FUNCTION__);
return 1;
}
printf("%s函数执行,带头结点的链表非空\\n",__FUNCTION__);
return 0;
}
(8)查找链表某个位置元素
//7.返回单链表中第pos个结点中的元素,若返回-1,表示没有找到
int GetElement(Node *pNode,int pos){
int i = 1;
Node *pMove;
pMove = pNode->next;
while (pMove != NULL) {
if (i == pos) {
printf("%s函数执行,pos=%d位置的值是%d\\n",__FUNCTION__,pos,pMove->element);
return pMove->element;
}
i++;
pMove = pMove->next;
}
printf("%s函数执行,在pos=%d位置没有找到值\\n",__FUNCTION__,pos);
return -1;
}
(9)返回某元素在链表中的内存地址
//8.从单链表中查找具有给定值x的第一个元素,若查找成功则返回该结点data域的存储地址,否则返回NULL
elemType* GetElemAddr(Node *pNode,int x){
Node *pMove;
pMove = pNode->next;
while (pMove != NULL) {
if (pMove->element == x) {
printf("%s函数执行,查找到x=%d的内存地址为:0x%x\\n",__FUNCTION__,x,&(pMove->element));
return &(pMove->element);
}
pMove = pMove->next;
}
printf("%s函数执行,在带头结点的单链表中没有找到x=%d的值,无法获得内存地址\\n",__FUNCTION__,x);
return NULL;
}
(10)修改某个节点的值
//9.把单链表中第pos个结点的值修改为x的值
Node* ModifyElem(Node *pNode,int pos,int x){
int i = 1;
Node *pMove;
pMove = pNode->next;
while (pMove != NULL) {
if (i == pos) {
pMove->element = x;
printf("%s函数执行,把pos=%d位置的值改为%d成功\\n",__FUNCTION__,pos,x);
return pNode;
}
i++;
pMove = pMove->next;
}
printf("%s函数执行,链表为空或者输入pos值非法,修改值失败\\n",__FUNCTION__);
return pNode;
}
(11)表头插入一个节点
//10.向单链表的表头插入一个元素
Node *InsertHeadList(Node *pNode,int x){
Node *pInsert;
pInsert = (Node *)malloc(sizeof(Node));
memset(pInsert, 0, sizeof(Node));
pInsert->element = x;
pInsert->next = pNode->next;
pNode->next = pInsert;
printf("%s函数执行,在表头插入元素%d成功\\n",__FUNCTION__,x);
return pNode;
}
(12)表尾插入一个节点
// 11.向单链表的末尾添加一个元素
Node *InsertTailList(Node *pNode,int x){
Node *pMove;
Node *pInsert;
pInsert = (Node *)malloc(sizeof(Node));
memset(pInsert, 0, sizeof(Node));
pInsert->element = x;
pInsert->next = NULL;
pMove = pNode;
while (pMove->next != NULL) {
pMove = pMove->next;
}
pMove->next = pInsert;
printf("%s函数执行,在表尾插入元素%d成功\\n",__FUNCTION__,x);
return pNode;
}
(13)测试函数
int main(int argc, const char * argv[]) {
Node *pList;
InitialList(&pList);
CreateList(pList);
PrintList(pList);
SizeList(pList);
IsEmptyList(pList);
GetElement(pList, 3);
GetElemAddr(pList, 5);
ModifyElem(pList, 2, 111);
PrintList(pList);
InsertHeadList(pList,1234);
PrintList(pList);
SizeList(pList);
InsertTailList(pList,9999);
PrintList(pList);
SizeList(pList);
ClearList(pList);
PrintList(pList);
return 0;
}
以上是关于c/c++语言创建单链表新结点时为啥不直接用结点对象,如直接lnode p;而是非要用指针加malloc或new实现?的主要内容,如果未能解决你的问题,请参考以下文章