| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2476 人关注过本帖
标题:数据结构单链表基础问题!
只看楼主 加入收藏
星野
Rank: 2
来 自:河北
等 级:论坛游民
帖 子:73
专家分:26
注 册:2016-4-13
结帖率:82.35%
收藏
 问题点数:0 回复次数:5 
数据结构单链表基础问题!
程序代码:
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int ElemType;
  
typedef struct LNode{
    ElemType data;
    struct LNode *next;
}LNode,*LinkList;
void CreateList_L(LinkList L,int n)
{
    int i;
    LinkList p;
    L=(LinkList)malloc(sizeof(LNode));
    L->next=NULL;
    for(i=n;i>0;--i)
    {
        p=(LinkList)malloc(sizeof(LNode));
        scanf("%d",&p->data);
        L->next=p->next;
        p->next=L;
    }
}
Status GetElem_L(LinkList L,int i,ElemType e)
{
    int j;
    LinkList p;
    p=L->next;j=1;
    while(p&&j<i)
    {
        p=p->next;
        ++j;
    }
    if(!p||j>i)
        return ERROR;
    e=p->data;
    return OK;
}
Status ListInsert_L(LinkList L,int i,ElemType e)
{
    int j;
    LinkList p,s;
    p=L;j=0;
    while(p&&j<i-1)
    {
        p=p->next;
        ++j;
    }
    if(!p||j>i-1)
        return ERROR;
    s=(LinkList)malloc(sizeof(LNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return OK;
}
Status ListDelete_L(LinkList L,int i,ElemType e)
{
    int j;
    LinkList p,q;
    p=L;j=0;
    while(p->next&&j<i-1)
    {
        p=p->next;
        ++j;
    }
    if(!(p->next)||j>i-1)
        return ERROR;
    q=p->next;
    p->next=q->next;
    e=q->data;
    free(q);
    return OK;
  
}
  
void main()
{
    LinkList p,L;
    int n;
    int i;
    ElemType e;
    scanf("%d",&n);
    CreateList_L(L,n);
    p=L->next;
    while(p)
    {
        printf("%d ",p->data);
        p=p->next;
    }
    printf("\n");
    
    scanf("%d ",&i);
    GetElem_L(L,i,e);
    printf("%d\n",e);
    scanf("%d %d",&i,&e);
    ListInsert_L(L,i,e);
    for(p=L->next;p;p=p->next)
    {
        printf("%d ",p->data);
    }
    printf("\n");
    scanf("%d",&i);
    ListDelete_L(L,i,e);
    for(p=L->next;p;p=p->next)
    {
        printf("%d ",p->data);
    }
    printf("\n");
}

编辑和组建没有问题,但是运行的时候,突然中断了,这又是什么情况啊,哪里出问题了嘛?
2016-09-22 13:58
若夏未央
Rank: 1
等 级:新手上路
威 望:1
帖 子:3
专家分:5
注 册:2016-9-21
收藏
得分:0 
一般是指针指向出现了问题,用调试功能即可找出具体是哪一句,一定要学会用调试。
2016-09-22 17:51
星野
Rank: 2
来 自:河北
等 级:论坛游民
帖 子:73
专家分:26
注 册:2016-4-13
收藏
得分:0 
回复 2楼 若夏未央
什么是调试啊   不会   我是刚刚学、
2016-09-22 18:13
若夏未央
Rank: 1
等 级:新手上路
威 望:1
帖 子:3
专家分:5
注 册:2016-9-21
收藏
得分:0 
就是程序编译后,不要点运行,点调试(debug)。然后程序会执行,但在有问题的地方会停下来,那条语句也会被标识出来。还可以在先在某一行设置断点,再调试,程序在执行到这一行时会停下来,点击下一行,程序会一行一行地执行,这样可以随时查看变量的值,出现错误也会停止。
2016-09-23 12:21
书生牛犊
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:星夜征程
等 级:贵宾
威 望:10
帖 子:1101
专家分:5265
注 册:2015-10-27
收藏
得分:0 
调试的过程中应该也是可以通过某些方法观测到程序中每一个变量当时时刻的具体内容。(不同的软件这个观测的实现方法不一样。通常是可以通过鼠标指针悬停在某个需要观测的变量上面,这时候会弹出一个小标签指示当前变量当前值)

我自己的话,感觉这个编译不是特别方便,所以我会喜欢在程序中多个位置添加printf()语句输出一些关键的变量的值,然后看程序在每一个时刻哪些变量的值和我脑子里所设想的是否一致。
在涉及到比较多指针、递归、循环等等的程序里,我觉得这个方法特别适用。

Debug有时候是会停在出问题的地方,但这通常只是导致程序无限循环或奔溃的决堤口,不一定是第一个出现问题的地方,比如这个程序如果DEBUG的话,程序应该是停在了P=L->NEXT;(L本身还没有被初始化,取L->NEXT的行为导致程序崩溃)

程序代码:
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int ElemType;

 

typedef struct LNode{
    ElemType data;
    struct LNode *next;
}LNode,*LinkList;
void CreateList_L(LinkList L,int n)//形参L,是CrateList函数里面的一个变量,复制了main函数里的L的数据,但是两个L不是一个L

{
    int i;
    LinkList p;
    printf("Lbefore Create =%p,%p\n",&L,L);//目前这个L是复制来自main函数,但只是复制了L上面保存的数据,不是L的地址

    L=(LinkList)malloc(sizeof(LNode));//这一步是申请了一块LNode变量的空间,并把申请到的地址赋值给L

    printf("Lafter Create =%p,%p\n",&L,L);//L的地址还是CreatList_L里的L,但是L上的数据变了

    L->next=NULL;
    for(i=n;i>0;--i)
    {
        p=(LinkList)malloc(sizeof(LNode));
        scanf("%d",&p->data);
        L->next=p->next;
        p->next=L;
    }
}
Status GetElem_L(LinkList L,int i,ElemType e)
{
    int j;
    LinkList p;
    p=L->next;j=1;
    while(p&&j<i)
    {
        p=p->next;
        ++j;
    }
    if(!p||j>i)
        return ERROR;
    e=p->data;
    return OK;
}
Status ListInsert_L(LinkList L,int i,ElemType e)
{
    int j;
    LinkList p,s;
    p=L;j=0;
    while(p&&j<i-1)
    {
        p=p->next;
        ++j;
    }
    if(!p||j>i-1)
        return ERROR;
    s=(LinkList)malloc(sizeof(LNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return OK;
}
Status ListDelete_L(LinkList L,int i,ElemType e)
{
    int j;
    LinkList p,q;
    p=L;j=0;
    while(p->next&&j<i-1)
    {
        p=p->next;
        ++j;
    }
    if(!(p->next)||j>i-1)
        return ERROR;
    q=p->next;
    p->next=q->next;
    e=q->data;
    free(q);
    return OK;

 

}

 

int main()
{
    LinkList p,L;
    int n;
    int i;
    ElemType e;
    scanf("%d",&n);            //&L取L的地址,L是L上面保存的数据,两者都是指针。就像月饼盒子,大盒子套小盒子,都是盒子,但一个是装的月饼,一个装的盒子。不一样

    printf("Lmain %p,%p\n",&L,L);//L是个指针,所以我用%p来输出地址,%d本身也行,但是是十进制的,比较长。

    CreateList_L(L,n);
    printf("Lresult %p,%p\n",&L,L);//你的问题就是出在了指针传递的问题上,CreatList_L函数没有把建立的L传递到外面来

    p=L->next;
    while(p)
    {
        printf("%d ",p->data);
        p=p->next;
    }
    printf("\n");
  

    scanf("%d ",&i);
    GetElem_L(L,i,e);
    printf("%d\n",e);
    scanf("%d %d",&i,&e);
    ListInsert_L(L,i,e);
    for(p=L->next;p;p=p->next)
    {
        printf("%d ",p->data);
    }
    printf("\n");
    scanf("%d",&i);
    ListDelete_L(L,i,e);
    for(p=L->next;p;p=p->next)
    {
        printf("%d ",p->data);
    }
    printf("\n");
    return 0;
}

图片附件: 游客没有浏览图片的权限,请 登录注册

其实一个程序如果申明了指针变量,通常我们都会习惯性地给他初始化为NULL。因为指针比别的变量类型更加难以琢磨,没有初始化的指针没人知道他是什么值,有些时候,这个错误在程序执行的时候凑巧就不会被发现的。万一好巧不巧他就正好等于Create函数里malloc之后的那个值呢?这样可能你的程序运行就没错了。。。一个好的习惯是不管什么变量,在声明的时候就尽量给他初始化,尤其是指针。

写一个程序不是一蹴而就的,应该在写的过程中就开始有所侧重的进行阶段兴检验。程序短一点,比较不会头大。

调试这种比较长的代码的时候,方法比较简单就是从头到尾让程序一步一步执行,然后你自己脑子里面也照着这个流程运行,一旦发现哪一步计算机执行的结果和你自己设想的不一致,这里就是问题根源了。
--------------------------------------------------
补充:刚刚在给你写另外的createList_L的时候又发现了别的错误。前面给出的只是第一个错误。是不是最后一个,不清楚。我还没有打算给你检查其他几个函数怎么样,其他几个函数很有可能也有错误,那,我建议你自己就着示例自己测试吧。


[此贴子已经被作者于2016-9-23 16:04编辑过]


φ(゜▽゜*)♪
2016-09-23 15:54
书生牛犊
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:星夜征程
等 级:贵宾
威 望:10
帖 子:1101
专家分:5265
注 册:2015-10-27
收藏
得分:0 
程序代码:
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int ElemType;

typedef struct LNode {
    ElemType data;
    struct LNode *next;
} LNode,*LinkList;
LinkList CreateList_L(int n) { //我喜欢这种思路直接的,CreateList将创建并返回一个链表并返回这个表头
    int i;
    LinkList L=NULL;
    LinkList p=L;
    for(i=n; i>0; --i) {
        int temp;
        scanf("%d",&temp);
        if(L==NULL) { //如果指针L为空,那么需要对链表头结点进行处理
            L=(LinkList)malloc(sizeof(LNode));//为了程序的健壮性着想,一般推荐每一句malloc后面都跟一个对指针的判断,若为NULL则malloc失败
            if(L==NULL) {
                printf("内存不足,分配空间失败。\n");
                exit(1);//报告错误,使程序异常退出
            }
            L->data=temp;
            p=L;
        } else {
            p->next=(LinkList)malloc(sizeof(LNode));
            if(p->next==NULL) {
                printf("内存不足,分配空间失败。\n");
                exit(1);//报告错误,使程序异常退出
            }
            p->next->data=temp;
            p=p->next;
        }
    }
    if(L!=NULL)//当n==0,L理应是NULL,这时候如果取p->next 就是NULL->next会导致程序奔溃。所以需要这个判断

    p->next=NULL;//出来循环的时候p指向最后一个有效结点,所以这时候要处理p->next;
    return L;
}

int main() {
    int n;
    scanf("%d",&n);
    LinkList L=CreateList_L(n);
    LinkList p=L;
    printf("测试输出[");
    while(p){
        printf("%d ",p->data);
        p=p->next;
    }
    printf("]");

    return 0;
}

图片附件: 游客没有浏览图片的权限,请 登录注册

这里特别希望提示到你这样一个技巧。有时候遇到无限循环的问题的时候我们不是很能判定清楚到底程序现在是卡在了那个部位,所以我喜欢在出现函数调用,while循环等出入口的位置用两个标记括起来,看得清楚些。
又比如未来在做一些字符的读写的时候读%c特别容易出现空格、回车等等肉眼看不到的字符,这时候也需要用括号。

做链表的数据测试,关键的也就 0,1,多  这三种情况模拟过后不出问题他才是真的健壮可靠了。


.

φ(゜▽゜*)♪
2016-09-23 16:29
快速回复:数据结构单链表基础问题!
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.029852 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved