| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1140 人关注过本帖
标题:单链表的基本操作(建立、查找、插入、删除)程序运行到调用函数那块就出错 ...
只看楼主 加入收藏
ssgurt
Rank: 1
等 级:新手上路
帖 子:4
专家分:0
注 册:2016-9-27
结帖率:0
收藏
已结贴  问题点数:20 回复次数:8 
单链表的基本操作(建立、查找、插入、删除)程序运行到调用函数那块就出错了,哪位大神帮我看看
#include <stdio.h>
#include <malloc.h>
#include <string.h>
typedef struct linknode{
  int data;
  struct linknode *next;
}Link, *Links;

void Create_link(Links L,int n)
{
  Link *head,*p,*q;
  int i;
  L=(Links)malloc(sizeof(Link));
  if(!L)
    return;
  L->next=NULL;
  head=L;
  p=head;
  for(i=0;i<n;i++)
  {
    q=(Links)malloc(sizeof(Link));
    scanf("%d",&q->data);
    p->next=q;
    p=q;
  }
  p->next=NULL;
  return;
}
void Get_Element(Links L,int n)
{
  Link *p;
  int i=0;
  p=L->next;
  while(p->next&&i<n-1)
  {
    p=p->next;
    ++i;
  }
  if(!p||i>n-1)
    return;
  printf("%d",p->data);
}
void Insert_list(Links L,int i,int elem)
{
  Link *p, *q;
  int j=0;
  p=L;
  while(p->next&&j<i-1)
  {
    p=p->next;
    j++;
  }
  if(!p||j>i-1)
    return;
  q=(Links)malloc(sizeof(Link));
  q->next=p->next;
  p->next=q;
  q->data=elem;
  return;
}
void Delete_list(Links L,int i)
{
  Link *p, *q;
  int j;
  p=L->next;
 
  for(j=0;j<i-1;j++)
  {
    p=p->next;
  }
  if(!(p->next)||j>i-1)
    return ;
  q=p->next;
  p->next=q->next;
  return;
}

void Traverse(Links L)
{
  Link *p;
  p=L->next;
  while(p->next!=NULL)
  {
    printf("%d",p->data);
  }
}
 
int main()
{
  Link L;
  int num,n,i,j,elem;
  char match[20];
  printf("请输入链表中元素的个数及元素: \n");
  scanf("%d",&num);
  Create_link(&L,num);
  printf("请输入操作次数: \n");
  scanf("%d",&n);
  printf("请选择操作(Get、Insert、Delete): \n");
  while(num!=0&&n!=0)
  {
    for(i=0;i<n;i++)
    {
      scanf("%s",match);
      if(!strcmp(match,"Get"))
      {
        printf("请输入要查找元素的位置: ");
        scanf("%d",&j);
        Get_Element(&L,j);
      }
      if(!strcmp(match,"Insert"))
      {
        printf("请输入要插入元素的位置及元素: ");
        scanf("%d%d",&j,&elem);
        Insert_list(&L,j,elem);
      }
      if(!strcmp(match,"Delete"))
      {
        printf("请输入要删除元素的位置: ");
        scanf("%d",&j);
        Delete_list(&L,j);
      }
    }
  }
  Traverse(&L);
  return 0;
}
搜索更多相关主题的帖子: include return 
2016-09-27 10:42
linlulu001
Rank: 13Rank: 13Rank: 13Rank: 13
等 级:贵宾
威 望:20
帖 子:944
专家分:4047
注 册:2016-4-13
收藏
得分:7 
void Create_link(Links L,int n)这里的L本身就是一个结构体的地址,所以不用开辟空间。
其它的有错再说。
2016-09-27 14:27
书生牛犊
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:星夜征程
等 级:贵宾
威 望:10
帖 子:1101
专家分:5265
注 册:2015-10-27
收藏
得分:7 
程序代码:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
typedef struct linknode{
  int data;
  struct linknode *next;
}Link, *Links;

void Create_link(Links L,int n)//C语言传参是值的复制 ,函数里的L和外面的L不是一个L,只不过你把外面的L地址传了进来,执行完malloc之后,就跟没传一样。

{
  Link *head,*p,*q;
  int i;
  L=(Links)malloc(sizeof(Link));//malloc申请一块存放Link变量的空间,返回一个地址。L=malloc...的结果就是L不再指向main的那个L,后续代码自然全废

  if(!L)
    return;
  L->next=NULL;//这句代码可以不要因为 p->next=NULL;保证了链表尾一定会带上NULL

  head=L;
  p=head;
  for(i=0;i<n;i++)
  {
    q=(Links)malloc(sizeof(Link));//所以你是建立了一个带头结点的链表咯。
    scanf("%d",&q->data);
    p->next=q;
    p=q;
  }
  p->next=NULL;
  return;
}


void Get_Element(Links L,int n)
{
  Link *p;
  int i=0;
  p=L->next;
  while(p->next&&i<n-1)
  {
    p=p->next;
    ++i;
  }
  if(!p||i>n-1)
    return;
  printf("%d",p->data);
}
void Insert_list(Links L,int i,int elem)
{
  Link *p, *q;
  int j=0;
  p=L;
  while(p->next&&j<i-1)
  {
    p=p->next;
    j++;
  }
  if(!p||j>i-1)
    return;
  q=(Links)malloc(sizeof(Link));
  q->next=p->next;
  p->next=q;
  q->data=elem;
  return;
}
void Delete_list(Links L,int i)
{
  Link *p, *q;
  int j;
  p=L->next;


  for(j=0;j<i-1;j++)
  {
    p=p->next;
  }
  if(!(p->next)||j>i-1)
    return ;
  q=p->next;
  p->next=q->next;
  return;
}

void Traverse(Links L)
{
  Link *p;
  p=L->next;
  while(p->next!=NULL)
  {
    printf("%d",p->data);
  }
}


int main()
{
  Link L;
  int num,n,i,j,elem;
  char match[20];
  printf("请输入链表中元素的个数及元素: \n");
  scanf("%d",&num);
  Create_link(&L,num);
  printf("请输入操作次数: \n");
  scanf("%d",&n);
  printf("请选择操作(Get、Insert、Delete): \n");
  while(num!=0&&n!=0)//你确定是要用while不是if  ? 这样的程序进来了就出不去了

  {
    for(i=0;i<n;i++)
    {
      scanf("%s",match);
      if(!strcmp(match,"Get"))//换成 if(match[0]=='G')怎么样?如果你接受了这个想法 试着再把这个if elseif elseif 换成switch case

      {
        printf("请输入要查找元素的位置: ");
        scanf("%d",&j);
        Get_Element(&L,j);
      }
      if(!strcmp(match,"Insert"))
      {
        printf("请输入要插入元素的位置及元素: ");
        scanf("%d%d",&j,&elem);
        Insert_list(&L,j,elem);
      }
      if(!strcmp(match,"Delete"))
      {
        printf("请输入要删除元素的位置: ");
        scanf("%d",&j);
        Delete_list(&L,j);
      }
    }
  }
  Traverse(&L);
  return 0;
}
这段代码很淡腾,我没想好怎样才能用尽可能少的修改令其达到理想的运行结果。我建议推倒重写。不要用void函数。让函数返回一个链表。具体代码稍后补充。





φ(゜▽゜*)♪
2016-09-27 15:12
书生牛犊
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:星夜征程
等 级:贵宾
威 望:10
帖 子:1101
专家分:5265
注 册:2015-10-27
收藏
得分:0 
程序代码:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
typedef struct linknode {
    int data;
    struct linknode *next;
} Link, *Links;

Links Create_link(int n) { //如果给定n<=0,本函数将建立一个空链表,NULL
    Links head=NULL;
    Links p=head;
    for(size_t i=0; i<n; i++) {
        Links temp=(Links)malloc(sizeof(Link));//少用q,p来做指针,容易混淆,出错了也很难查出来。pqijk做循环用用就行了。做变量名还是长一点的好
        scanf("%d",&temp->data);
        if(p) {
            p->next=temp;
            p=temp;
        } else {
            head=temp;
            p=head;
        }
    }
    if(head)
        p->next=NULL;
    return head;
}


void Get_Element(Links L,int n) {//不用担心,这里的L不等于外面的L,此刻这里的L因为赋值的缘故指向了外面的L,我令这里的L指向别的地方不会影响到外面的L的
    while(L&&n>0) {   //安全起见,最好是另外用一个P来做这些迭代。现在我之所以这么写,只是想向你证明一些什么 ,不建议你这么用。只是让你知道这么回事
        L=L->next;   //你自己写的代码就是犯了 指针指向的糊涂。你在CreateLink对L做的一切,并没有影响到main里的L。
        --n;     //
    }
    if(n)return;
    printf("%d\n",L->data);
}
Links Insert_list(Links L,int i,int elem) {
    Links p=L;
    Links beforeLinks=NULL;
    for(; p&&i>0; p=p->next,--i)beforeLinks=p; //用beforeLinks记录下待插入结点的父节点
    if(i) { //写程序,出错的地方一定要顺手写上提示性语句,方便做数据测试和用户使用。最不济在程序打包的时候把这些注释掉。
        printf("给定的插入位置不合理,请检查后重新输入。\n");
        return L;
    }
    Links temp=(Links)malloc(sizeof(Link));
    temp->data=elem;
    temp->next=p;
    if(beforeLinks) {
        beforeLinks->next=temp;
        return L;
    } else { //表示i==0,元素被插到链表头部
        return temp;
    }
}
Links Delete_list(Links L,int i) {//传递一个链表进函数, 处理完传递一个链表回到main,我个人觉得这样用指针比较不容易出错。思路清晰。
    Links p=L;
    Links beforeLinks=NULL;
    for(; p&&i>0; p=p->next,--i)beforeLinks=p;
    if(i) {
        printf("链表已空或给定删除位置不合理,请检查后重新输入。\n");
        return L;
    } else if(!p) {
        printf("该位置本身没有元素。\n");
        return L;
    }
    if(beforeLinks)beforeLinks->next=p->next;
    else L=L->next;//即i==0,删除头结点

   

    free(p);//释放结点所指空间

    return L;
}

void Traverse(Links L) {//鉴于这个函数不会修改链表,所以才选择void,   

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

int main() {
    Links L=NULL;
    int num,n,i,j,elem;
    char match[20];
    printf("请输入链表中元素的个数及元素: \n");
    scanf("%d",&num);
    L=Create_link(num);
    printf("请输入操作次数: \n");
    scanf("%d",&n);

    for(i=0; i<n; i++) {
        printf("请选择操作(Get、Insert、Delete、Print): \n");
        scanf("%s",match);
        switch(match[0]) {
            case 'G':
                printf("请输入要查找元素的位置: ");
                scanf("%d",&j);
                Get_Element(L,j);
                break;
            case 'I':
                printf("请输入要插入元素的位置及元素: ");
                scanf("%d%d",&j,&elem);
                L=Insert_list(L,j,elem);
                break;
            case 'D':
                printf("请输入要删除元素的位置: ");
                scanf("%d",&j);
                L=Delete_list(L,j);
                break;
            case 'P'://随时做输出,是我为了自己测试开的后门

                Traverse(L);break;

            default :
                --i;
                printf("操作无效,请重新输出。\n");
                break;
        }

    }
    Traverse(L);
    return 0;
}
图片附件: 游客没有浏览图片的权限,请 登录注册






φ(゜▽゜*)♪
2016-09-27 16:25
书生牛犊
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:星夜征程
等 级:贵宾
威 望:10
帖 子:1101
专家分:5265
注 册:2015-10-27
收藏
得分:0 
写代码的时候用到指针的话,你自己务必搞清楚指针自己是谁,它每个时刻应该指向了谁。如果搞不清楚那就printf("%p",&_)输出看看。
程序代码:
#include <stdio.h>
#include <malloc.h>
#include <string.h>

void fun1(int *a) {
    *a=1;//关键是*号,这是向a所指向的地址上写数据的一个运算符。
    printf("fun1 a & %d\n",&a);//输出a,的地址
    printf("fun1 a = %d\n",a);//输出a保存的数据,也是一个指针

    printf("如果你在这里面用了malloc,看看会发生什么事吧\n");
    a=(int*)malloc(sizeof(int));
    printf("fun1 a & %d\n",&a);
    printf("fun1 a = %d\n",a);
    printf("看到了吗?这里的a自己的地址没变,但是,他所保存的信息已经变了,这时候*a=5又是另一个int变量的事了\n");
    *a=5;
}
void fun2(int a) {
    a=2;
}

int* fun3(){
    int *a=(int*)malloc(sizoef(int));
    *a=3;
    return a;
}


int main() {
    int a=0;
    printf("调用fun1函数之前:\n");
    printf("main a & %d\n",&a);
    printf("main a = %d\n",a);

    printf("-----------------\n") ;
    fun2(a);
    fun1(&a);
    printf("-----------------\n") ;

    printf("回到main函数之后:\n");
    printf("main a & %d\n",&a);
    printf("main a = %d\n",a);

    printf("总结,指针说白就是一个变量,这个变量保存的数据是地址。是在计算机内存中一个真实的地方。");
    printf("任何变量、函数都有地址,指针自己也有。") ;
    printf("而和其他类型数据一样,我们可以修改他所保存的数据。所以指针用不好也很头疼,因为编译器检查不了这样的问题。");
    printf("C语言函数传参机制就是复制。复制值。而不是真的传递这个变量。");
    printf("他会在函数内部对应形参列表建立几个对应类型的变量,并把外面的值复制赋值给函数内部的变量。") ;
    printf("这是为什么fun2做的会是无用功。(我想这一定所有学指针的人都懂的。不懂得拉出去枪毙)") ;
    printf("*a=1,是访问a所保存的地址,并向那个地址写数据。但他并不能检查这块地址是否有效。因为计算机编码说到底只有01。") ;
    printf("(有些地址被计算机列为不可修改的地址。如果你试图向他们写入数据就会导致程序崩溃)");
    printf("比如:int*p=NULL; *p=1;或者Link*p=NULL;p->Next;都会直接奔溃(后者出错更加常见,程序运行一碰到NULL->..就炸了)") ;
   

    printf("原则上,我推荐fun3()这样内部建立全部数据然后传递一个指针出来,");
    printf("除非必要,尽量避免像fun1()那样传个地址进来做操作。光是写*号就能让你的代码看起来七荤八素");
   

    printf("慎用指针!");

    printf("慎用指针!");
    printf("慎用指针!");
    printf("懒得逐行打'\n'了,将就着代码页看吧");

    return 0;
}




φ(゜▽゜*)♪
2016-09-27 17:07
ssgurt
Rank: 1
等 级:新手上路
帖 子:4
专家分:0
注 册:2016-9-27
收藏
得分:0 
回复 3楼 书生牛犊
我改好了,其实只要在Create_list(Links &L,int n)这里加个取地址符,另外再在子函数的一些小毛病处修改下程序就能运行了。而且我发现这个取地址符非留不可,Links不是结构体的指针类型吗?Links &L是为甚么又对指针类型的L用& ??
2016-09-28 00:13
word123
Rank: 10Rank: 10Rank: 10
等 级:贵宾
威 望:13
帖 子:333
专家分:1622
注 册:2014-4-5
收藏
得分:7 
如果你想在一个函数内部改变主函数中的变量值,要么传引用,要么传指针。。。
主函数L是一个变量,你想要函数执行完之后值被改变。Create_list(Links &L,int n)。。你这里就是传的一个引用值

若函数Create_list(Links *L,int n)
主函数调用Create_list(&L,n);         就是传指针(取变量L的地址)
2016-09-28 01:08
ssgurt
Rank: 1
等 级:新手上路
帖 子:4
专家分:0
注 册:2016-9-27
收藏
得分:0 
回复 7楼 word123
那么Links *L和Links &L是等效的吗?那不就是struct linknode **L和struct linknode *&L,指针再指针,这样的定义是表示地址的地址?这样的用法真不太懂
2016-09-28 13:46
linlulu001
Rank: 13Rank: 13Rank: 13Rank: 13
等 级:贵宾
威 望:20
帖 子:944
专家分:4047
注 册:2016-4-13
收藏
得分:0 
你知道Links声明的是struct linknode指针类型。
那么Link声明的是struct linknode结构体你自己应该也懂吧。
一开始我就提醒你L是主函数里声明的结构体地地址。
你将已经声明好的结构体地址传递给子函数L,你想将这个作为头指针本来是没问题,可是你非要加一句 L=(Links)malloc(sizeof(Link));
此时L的值由主函数结构体L的地址变成新开辟的空间地址,新开辟空间的值又如何能影响主函数L的值呢。
你自己仔细思考下,你的代码是不是我说的这个情况。
至于你说只要在Create_list(Links &L,int n)这里加个取地址符就能运行,主函数的L类型没修改能通过编译????
2016-09-28 14:59
快速回复:单链表的基本操作(建立、查找、插入、删除)程序运行到调用函数那块就 ...
数据加载中...
 
   



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

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