繁体   English   中英

C问题 - 无法确定如何将指针指定给列表的开头

[英]C issue - Can't figure how to assign pointer to beginning of list

我有一个简单的任务,教授希望我们这样做。 基本上从文本文件中提取一些数字并加载到链表中。 我不想深入了解细节,但我有一个基本问题。

他为我们提供了这样的功能:

INTLIST* init_intlist( int n ) 
{
INTLIST *lst;
lst = (INTLIST *)malloc(sizeof(INTLIST));
lst->datum = n;
lst->next = NULL;
return lst;
}

此函数用于使用第一个元素初始化链接列表。 然后他要我们用这个签名定义一个函数:

int insert_intlist( INTLIST *lst, int n )

所以我假设他只是想让我们添加到链表中,所以我尝试了这个:

int insert_intlist( INTLIST *lst, int n )
 {
 INTLIST* lstTemp;
 lstTemp = (INTLIST *)malloc(sizeof(INTLIST));
 lstTemp->datum = n;
 lstTemp->next = lst;
 lst = lstTemp;       
 free(lstTemp);          
 }

所以我的思考过程是它创建一个临时节点,分配数据值(Datum)并指定下一个指针指向当前指针所指向的位置。 然后我将主指针重新分配给这个新创建的临时节点。

这样我们就有2个节点:

[新临时节点] - > [上一个初始化节点]

当我单步执行代码时,它看起来很棒......

然后回到main我只有一个打印列表的函数:

                   while (lst!=NULL)
                      {
                       printf("The value is:%d", lst->datum);
                       lst=lst->next;
                      }

问题是这似乎只打印一个数字(即我从文件中读取的第一个数字,我认为这是列表中的最后一个数字,或者至少我认为它是列表中的最后一个数字)。

但它应该继续通过,因为我有10个数字在文件中。 我知道代码非常脏,我会清理它...如果有人需要更多信息,这是我的整个主要功能:

#include <stdio.h>
#include <stdlib.h>
#include "intlist.h"

int main(int argc, char *argv[])
{
  char c;    /* Character read from the file. */
  FILE* ptr;   /* Pointer to the file. FILE is a
       structure  defined in <stdio.h> */
  int index=0;
  //INTLIST* aList[10]; //will use later

    /* Open the file - no error checking done */
  ptr = fopen("1.txt","r");
    /* Read one character at a time, checking 
       for the End of File. EOF is defined 
      in <stdio.h>  as -1    */

  if(ptr==NULL) {
    printf("Error: can't open file.\n");
    /* fclose(file); DON'T PASS A NULL POINTER TO fclose !! */
    return 1;
  }

  //aList[index] = malloc(sizeof(INTLIST)); WE NEED THIS LATER ON....
  INTLIST *lst=NULL;

  while ((c = fgetc(ptr)) != EOF)
  {
        if (c != ' ') 
        {
         //make sure it isnt a space
         int i = c - '0'; //get the value from the text file
             if(c=='\n') 
                 {
                      // aList[index]=lst;
                      // index++;
                      // aList[index] = malloc(sizeof(INTLIST));

                           while (lst!=NULL)
                              {
                               printf("The value is:%d", lst->datum);
                               lst=lst->next;
                              }

                           free(lst);
                           free(aList[index]);
                           return 0;
                          //new line in the file 
                         //create another linked list
                 }

            if (lst==NULL)
             lst = init_intlist(i);
            else
             insert_intlist( lst, i); 
        }
  }

  fclose(ptr);
  system("PAUSE"); 
  return 0;
}

对于可能需要它的人来说,这是intlist.h:

#ifndef __intlist_h__
#define __intlist_h__
/* each entry in the list contains an int */
typedef struct intlist {
int datum;
struct intlist *next;
} INTLIST;
INTLIST *init_intlist( int n ); /* initializes the intlist with initial datum n */
int insert_intlist( INTLIST *lst, int n ); /* Inserts an int (n) into an intlist from the beginning*/
void list_append(INTLIST *list, void *datum); /* Inserts entry to the end of the list */
INTLIST* list_front(INTLIST *list); /*return the element at the front of the list, and remove it 
from the list*/
void list_map( INTLIST *list, void (*f)(void *) ); /*Applies a function to each element of the list */
void list_delete( INTLIST *list ); /* Deletes (and frees) all entries in the list */
#endif

这里有几个问题。

我将从一个坏的错误开始:

int insert_intlist( INTLIST *lst, int n )
 {
 INTLIST* lstTemp;
 lstTemp = (INTLIST *)malloc(sizeof(INTLIST));
 lstTemp->datum = n;
 lstTemp->next = lst;
 lst = lstTemp;       
 free(lstTemp);             //   <<<<<  NO!
 }

你还在使用那个记忆,所以你无法释放它。


其次,提供给您插入的proto类型无法返回列表的新前端,因此您无法更改列表的前面。 这意味着您必须将新节点添加到后面 ,而不是像前一样添加到前面。

此外,提供的int返回类型可能意味着他预计列表中的节点数量,这没有问题,因为您无论如何都必须走列表才能找到后面的节点。

再试一次,你根本没有做得很糟糕。

使用以下代码:

int insert_intlist( INTLIST *lst, int n )
 {
 INTLIST* lstTemp;
 lstTemp = (INTLIST *)malloc(sizeof(INTLIST));
 lstTemp->datum = n;
 lstTemp->next = lst;
 lst = lstTemp;       
 free(lstTemp);          
 }

这有几个问题。 首先, free(lstTemp)似乎正在释放你刚刚插入列表中的节点,你可能不想这样做。

其次,您将指向列表的指针传递给函数 - 这意味着函数无法修改该指针,因此当您指定指针时,您只需要更改它的本地副本。

你有两个选择:你可以传入一个指向那个指针的指针(这样你就可以修改原始指针),或者你可以聪明一点,找出一种避免需要的方法(但我不会马上泄露秘密) ...)

这一行:

lst = lstTemp;  

仅更改函数内部的lst值。 它不会传播回调用者具有的指针的副本。

您可以使用指向指针的指针,或者如果您无法更改函数签名,请插入除列表头部之外的其他位置。

虽然处理这个的典型方法是指向列表中的第一个元素 - 相反,你有某种列表结构,它包含指向第一个元素的指针,以及关于列表的一些其他信息(比如,有多少个元素)它有)。 然后你传递一个指向该结构的指针。

在C中,参数按“值”传递给函数,这意味着在您输入函数时会复制它们,并且您对它们所做的任何更改都不会反映回调用者。 这意味着当你修改lst以指向新分配的内存时,它实际上并没有修改调用者指向列表的指针。

编辑:正如dmckee指出的那样,你不应该在插入功能中释放内存,因为你仍在使用它。 这肯定是一个错误,但它不是导致你的问题的那个。

在C中, 一切都按值传递。 如果您希望函数更改某些内容,则需要将其地址传递给该函数。 因为在int insert_intlist( INTLIST *lst, int n ) ,你想要更改列表头,你需要传递一个指向它的指针,即第一个参数应该是INTLIST **lst (尽管也见下文)。 但函数原型是给出的,不能改变。

这意味着您无法在列表的开头添加数字 - 调用者无法知道您这样做了。 因此,您必须遍历lst指向的列表,然后在链的任何位置添加新节点。 教授可能希望你最后添加节点,但他可能会要求其他一些条件。

有了这些信息,让我们看一下原型的评论:

/* Inserts an int (n) into an intlist from the beginning*/
int insert_intlist( INTLIST *lst, int n );

评论或原型是错误的。 如果你的教授给你这个文件,就不能编写insert_intlist()来满足评论,因为它不能将新头返回给调用者。 原型应该是:

/* Inserts an int (n) into an intlist from the beginning
   and returns the new head */
INTLIST *insert_intlist( INTLIST *lst, int n );

要么:

/* Inserts an int (n) into an intlist from the beginning */
int insert_intlist( INTLIST **lst, int n );

(注意** 。)

标题还包括:

/*return the element at the front of the list, and remove it from the list*/
INTLIST* list_front(INTLIST *list);

这是对的。 请注意,您需要在list_front()修改列表的头部,因此您将返回新的头部。

最后,你不希望free()在任何insert_intlist() 你想把新节点保留在列表中,不是吗? 一旦调用者完成列表,他将不得不调用list_delete() ,它将遍历链表,并释放每个节点。

我同意Alok。 我有同样的问题/教授。 我是C编程的新手,我一直在网上寻找表格和C网页寻求帮助。 我遇到过支持Alok的消息来源。

我用了

INTLIST * list_add(INTLIST ** p,int i){

 INTLIST *n; 
    n = (INTLIST *) malloc(sizeof(INTLIST)); 
        if (n == NULL) 
    return NULL;   
    n->next = *p; /* the previous element (*p) now becomes the "next" element */

     *p = n;       /* add new empty element to the front (head) of the list */

      n->datum = i;
    return p; }

从我的主要我可以传入

INTLIST *列表

list_add(&list,1); list_add(&list,2);

因此,当我打印列表时,它打印2 1

教授建议:

INTLIST * mylist [N];

其中N是输入文件的行数。 然后mylist [i]是指向第i个链表的指针。

好的好:创建用于测试目的的INTLIST * mylist [2];

我称之为相同的功能:

list_add(&list [0],1); list_add(&list [0],2);

打印出2 1 ...很棒,

但是当我这样做时:

list_add(&list [1],3); list_add(&list [1],4);

我收到了分段错误..

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM