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实现?的主要内容,如果未能解决你的问题,请参考以下文章

单链表创建之--头插法创建带头结点的单链表,超详细

C语言 单链表

c语言数据结构:单链表

编写C语言程序创建一个具有10个结点的单链表并输出该链表的数据

单链表C语言实现附加力扣题

基于C语言的单链表实现