【问题标题】:linked list to get input from the user and print it链表从用户那里获取输入并打印出来
【发布时间】:2014-01-10 09:26:21
【问题描述】:

我正在尝试用 c 编写一个程序来获取用户的输入(字符)。用户应该能够输入任意长度的输入(''infinite'')。

这是我最后写的完全没有错误的程序:

代码:

/*
main:

we will try to get an input from the user.
if we succeed, call insert function. 
if we don't succeed, call freeList function.
if we encounter '\n' or EOF, we quit the program.
print the list, the free it.

insert (type void. does not return a value):

if allocation is successful, then we can put a new item in the linked list. 
the item is a type node.
we don't care the number of nodes in the list. 
if allocation is not successful, call free function.

free:
free the memory.

*/

#include <stdio.h>
#include <stdlib.h>
typedef struct list *ptr;
typedef struct list{
    char data;
    ptr next;
}node;  /*describes a linked list.*/
void insert(ptr *H, char c);
void freeList(ptr *H);
void printList(ptr *H);

int main(){
char c;  
printf("enter a string\n");
ptr H=(ptr)malloc(sizeof(node));/*create an empty list. this is its head.*/
while ((c=getchar())!=EOF && c!='\n'){  
    insert(&H,c);
    }
printList(&H); /*print the list*/
freeList(&H); /*free the list*/
printf("\n");
return 0;
}
void insert(ptr *H, char c){
    ptr p1;
    p1=*H;
    ptr T=(ptr)malloc(sizeof(node)); /*try to allocate a new memory cell*/
    if (!T)
    {
        printList(H);       
        freeList(H); /*we should not free H because we will 
            lose the list we've created.*/
    }
    else
    {
        T->data=c;
        while(p1->next)
        {
            p1=p1->next;
        }
        p1->next=T; /*add T to the end of the linked list*/

    }


}
void freeList(ptr *H){
    ptr p1; /*helper pointer*/
    while(*H){      /*while H points to a certain node*/
    p1=*H;
    (*H)=p1->next;
    free(p1);
    }   
}
void printList(ptr *H){ /*a copy of H is sent so no problem working with it.*/
    ptr p1=*H; printf("string is: \n");
    while (p1) /*while H is not null        */
    {
        printf("%c", p1->data);
        p1=p1->next;
    }

}

这段代码确实有效,但任何反馈都是好的。

【问题讨论】:

  • 不要重新定义 free 这是标准函数的名称。
  • 谢谢!这是一个开始:) @manu-fatto
  • 您应该考虑通过诸如gdb 之类的调试器运行您的代码,它会告诉您哪一行导致了分段错误。
  • 尝试获取NULL 指针的地址肯定会导致分段错误 - 您应该将列表的HEAD 设为分配的node 而不是NULL 指针。

标签: c linked-list malloc


【解决方案1】:

尝试获取 NULL 指针的地址可能会导致分段错误 - 您应该将列表的 HEAD 设为已分配节点,而不是 NULL 指针。

通过调试器(例如gdb)运行代码也很有用,它会告诉您导致分段错误的行(并显示调用堆栈)。

解决警告应该相当简单。

  • flag 未使用,因此可以删除。
  • 您应该将*H 而不是H 传递给printList
  • 您应该将H 而不是&amp;H 传递给freeList

或者,您可以将函数更改为采用 ptrs 而不是 ptr *s,因为我认为没有理由通过 node **s(这就是 ptr * 会变成的)。在这种情况下,应该将Hs 传递给函数而不用担心它们的指针类型(尽管正如 WhozCraig 所说,这可能不是一个好主意)。

【讨论】:

  • 谢谢,现在我只有警告,正如我在编辑中描述的那样。
  • 有一个很好的理由将一个指向指针的指针传递给一个插入函数:如果列表头被更新,你必须有一些方法来返回它。传统上,它要么通过输出参数(在 C 中必须通过地址,因此此处为 OP 所具有的指针指向指针)或通过函数返回值(在这种情况下不需要指针指向指针)来完成,但有其自身的警告,例如在功能失败的情况下无法进行调用方错误检测)。
【解决方案2】:

这可能是您正在寻找的内容,代码中的 cmets 可以解释正在发生的事情。使用指针,更重要的是,指针到指针的逻辑是……不寻常的……你第一次接触到它。希望这会有所帮助。

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

typedef struct list *ptr;
typedef struct list
{
    char data;
    ptr next;
} node;

void insert(ptr *H, char c);
void freeList(ptr *H);
void printList(ptr H);

int main()
{
    ptr H = NULL;
    int c;

    printf("enter a string\n");

    while (((c=getchar())!=EOF) && c!='\n')
        insert(&H,(char)c);

    printList(H); /*print the list*/
    freeList(&H); /*free the list*/
    printf("\n");
    return 0;
}

void insert(ptr *H, char c)
{
    // NOTE: while the pointer held in the pointer-to-pointer H
    //  is not NULL, move to the next pointer. Notice how we store
    //  the *address* of the 'next' member in our H variable as we
    //  walk. When we reach the end-of-list the value of the address
    //  held in the pointer whos address we're storing in H will be
    //  null. As a bonus, H will hold the address of the pointer we
    //  need to update, which we do.
    while (*H)
        H = &(*H)->next;

    // allocate new node, assigning to the pointer
    //  dereferenced by the address held in *H
    *H = malloc(sizeof(**H));
    (*H)->data = c;
    (*H)->next = NULL;
}

void freeList(ptr *H)
{
    // NOTE: same logic as before. using H as a pointer-to-pointer
    //  to walk through the chain of pointers. each time we save the
    //  value to a temp, advance to the next pointer, and delete the
    //  saved value.
    while (*H)
    {
        ptr tmp = *H;
        *H = (*H)->next;
        free(tmp);
    }
}

void printList(ptr H)
{
    // NOTE: No need for a pointer-to-pointer here.
    while (H)
    {
        printf("%c", H->data);
        H=H->next;
    }
}

综上所述,我强烈建议完全消除 ptr 意识形态,并简单地使用带有星号的正确声明的指针。 C 程序员希望看到这些。他们喊道:“看!我是指针”=O

【讨论】:

    【解决方案3】:

    一个递归的freeList函数可以是

    void freeList(ptr *H)
    {  
       if(*H!=NULL)
       {
        freeList(&(*H)->next);
        free(*H);
       }
    }
    

    类似printList和insert也可以改写

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-07
      • 1970-01-01
      • 2019-04-11
      • 1970-01-01
      • 2019-06-19
      • 1970-01-01
      • 2021-05-01
      • 2013-09-03
      相关资源
      最近更新 更多