深入理解 C++ 指针(十)---指针与链表问题

红色部分所示的程序语句有问题,改正后的程序在下面。
list1.c

struct listNode
{     int data;
     struct listNode *nextPtr;
};

typedef struct listNode LISTNODE;
typedef LISTNODE * LISTNODEPTR;
void list(LISTNODEPTR *, int);
void printlist(LISTNODEPTR);
main()
{
    LISTNODEPTR newPtr=NULL;
    int i,a;
    for(i=0;i<3;i++)
     {
       printf("please enter a number\n");
        scanf("%d,",&a);
        list(&newPtr,a);
        // 此处给的是newPtr的地址, 注意!
      }
      printlist(newPtr);

    free(newPtr);
     // 链表的释放不能这样写,这样,只释放了newPtr指向的一个节点。
     // 可以先找到链表的尾,然后反向释放;或者,利用 printlist的顺序释放,
     // 改函数printlist,或在此函数里释放。
    return 0;
}

void list(LISTNODEPTR *sPtr, int a)
{
    LISTNODEPTR newPtr,currentPtr;
    newPtr=malloc(sizeof(LISTNODEPTR));
    // 此处错, LISTNODEPTR 是指针类型,不是结构类型,
    // malloc返回void指针,应该强制转换类型,此处会告警不报错,但应有良好的编程风格与习惯。
    if(newPtr!=NULL){
        newPtr->data=a;
        newPtr->nextPtr=NULL;
         currentPtr=*sPtr;
    }
    if(currentPtr==NULL){
     // 此处条件不确切,因为currentPtr没有初始化,
     // 如newPtr一旦为NULL,此句及以下就有问题。
    newPtr->nextPtr=*sPtr;
    *sPtr=newPtr;}
     // 在第一个数来的时候,main里的newPtr通过sPtr被修改指向此节点。
     // 在第二个数来的时候,main里的newPtr通过sPtr被修改指向此节点。
     // 在第三个数来的时候,main里的newPtr通过sPtr被修改指向此节点。
     // 最后,main里的newPtr指向第三个数。
}

void printlist(LISTNODEPTR currentPtr)
{
    if(currentPtr==NULL)
        printf("The list is empty\n");
    else{
        printf("This list is :\n");
       while(currentPtr!=NULL){
            printf("%d-->",currentPtr->data);
            // main里的newPtr指向第三个数。你先打印了最后一个数。
            // currentPtr=currentPtr->nextPtr->data;
            // 此句非法, 类型不同, 有可能让你只循环一次,如data为0。
       }
       printf("NULL\n\n");
    }
}
    // 对类似程序能运行,但结果似是而非的情况,应该多利用跟踪调试,看变量的变化。


改正后的正确程序
struct listNode{
    int data;
    struct listNode *nextPtr;
};
typedef struct listNode LISTNODE;
typedef LISTNODE * LISTNODEPTR;

LISTNODEPTR list(LISTNODEPTR , int); // 此处不同
void printlist(LISTNODEPTR);
void freelist(LISTNODEPTR); // 增加

main()
{
    LISTNODEPTR newPtr=NULL;
    int i,a;
    for(i=0;i<3;i++){
        printf("please enter a number\n");
        scanf("%d,",&a);
        newPtr = list(newPtr,a); // 此处注意
    }
    printlist(newPtr);
    freelist(newPtr); // 此处
    return 0;
}

LISTNODEPTR list(LISTNODEPTR sPtr, int a)
{
    if ( sPtr != NULL )
        sPtr->nextPtr = list( sPtr->nextPtr, a ); // 递归,向后面的节点上加数据。
    else
    {
        sPtr =(LISTNODEPTR) malloc(sizeof(LISTNODE)); // 注意,是节点的尺寸,类型转换
        sPtr->nextPtr = NULL;
        sPtr->data = a;
    }
    return sPtr;
}

void freelist(LISTNODEPTR sPtr )
{
    if ( sPtr != NULL )
    {
        freelist( sPtr->nextPtr ); // 递归, 先释放后面的节点
        free( sPtr ); // 再释放本节点
    }
    else //
    return ; // 此两行可不要
}

void printlist(LISTNODEPTR currentPtr)
{
    if(currentPtr==NULL)
        printf("The list is empty\n");
    else
    {
        printf("This list is :\n");
        while(currentPtr!=NULL)
        {
            printf("%d-->",currentPtr->data);
            currentPtr=currentPtr->nextPtr; // 这里不一样
        }
        printf("NULL\n\n");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值