【问题标题】:Storing strings from pointers in Linked lists从链接列表中的指针存储字符串
【发布时间】:2022-01-20 23:16:51
【问题描述】:

最近开始练习链表。我知道基本的算法和概念,并想到了实现 LL 来存储用户输入的一堆字符串。

但显然我不断收到Segmentation fault

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

typedef struct _node{
    char *s;
    struct _node *next;
}
node;

int main()
{
    node *head = NULL;
    int a = 0;
    char ch;
    char *str = malloc(10);
    do
    {
        printf("\nDude %i:", a);
        fgets(str, 10, stdin);

        node *n = malloc(sizeof(node));
        if(n == NULL)
        {
            printf("\ninsufficient memory");
            return 1;
        }
        
        if(a == 0)
        {
            strcpy(n->s, str);
            n->next = NULL;
            head = n;
        }

        else
        {
            strcpy(n->s, str);
            n->next = head;
            head = n;
        }
        
        a++;
        printf("\n continue?(y/n): ");
        scanf("\n%c", &ch);
        
    }while(ch == 'y');
    
    for(node *temp = head; temp != NULL; temp = temp -> next)
    {
        printf("\n%s", temp->s);
    }
    return 0;
}

我确实知道我的逻辑/代码在某个地方存在缺陷,因为我正在触摸我不应该触摸的内存,但似乎无法指出哪里,因为这是我第一次处理链表。

【问题讨论】:

  • 您的调试器会准确地告诉您段错误发生的位置。在尝试学习 C 时,学习使用调试器不是可选的,尤其是 C 中的内存引用数据结构。投票结束这个问题是因为缺少调试信息——但我保证,一旦你启动调试器在您的程序中,您将很快能够自己找出问题所在,或者您可以在这里提出更好的问题!
  • @MarcusMüller 是对的,只要在调试器中运行代码,调试器肯定会告诉你哪一行触发了分段错误。
  • ... 这与我必须做的事情完全相同,甚至试图弄清楚你的代码是做什么的。所以,不管是我们还是你这样做,不同的是你的任务是成为一个有能力的 C 开发者
  • 我明白了。谢谢您的帮助!我将从现在开始使用调试器。
  • @acertainwanderer 当我学会这样做时,真的让我的生活变得轻松多了:)

标签: c pointers linked-list segmentation-fault singly-linked-list


【解决方案1】:

当您为malloc 分配struct 的空间时,您只是为指向_node 结构中的字符串的指针分配空间。在执行strcpy 之前,您需要分配一些内存来存储字符串并将指针s 指向它。 即

n->s = malloc(sizeof(char)*100);

请记住,您还需要制定策略来取消分配此内存。

正如其他人所暗示的,这些错误通常很容易通过使用gdb 查看/调试来发现。请记住,使用-g 标志进行编译以获得有用的调试信息很有用。

【讨论】:

  • 只有在存储字符串时才需要分配一些内存吗?
  • 不一定。当您使用指针(尤其是内部结构)时,您需要malloc。如果要静态分配,则需要使用值。因此,例如,您可以通过执行char x[10] 之类的操作来静态分配一些字符。此内存在超出范围时被释放。
  • 啊,我指的是如果我存储数值,我只需要为指向结构的指针分配内存。因为,到目前为止,为结构成员单独分配内存对我来说是全新的,所以我认为只有字符串是这种情况。虽然看到我需要创建一个单独的块来释放这个有点特殊的指针(给我)让我重新考虑使用指针而不是数组,因为很明显,动态性伴随着它的权衡。
  • 您可以通过在作用域中声明结构和字符串来静态分配它们。您需要将 struct 中的内容类型从指向实际值的指针更改。这当然会带来空间成本。很高兴您开始就这些事情提出问题。 C 中的编程就是权衡这类问题并进行权衡。
  • 哦!我不敢相信我忘记了这个基本概念-感谢您跟上我的愚蠢怀疑并简洁地解释它。所以权衡这种权衡也是可取的。我明白了。
【解决方案2】:

您捕获“分段错误”的原因是因为在复制实际字符串 strcpy(n-&gt;s, str) 之前,您没有为结构 nodes 变量分配内存。 所以,为s分配内存:

n->s = (char *) malloc(10 * sizeof(char));

【讨论】:

    【解决方案3】:

    请注意,您不能将任何内容写入未分配的空间,因此您需要为每个节点中的字符串调用malloc。 如果字符串长度是固定的,那么可以在struct node的定义中指定长度,避免malloc的问题。

    此外,建议始终free 将不再引用的对象。

    经过一些修改,下面的代码可能会有所帮助:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define LEN 10
    
    typedef struct node {
        char str[LEN];
        struct node *next;
    } Node;
    
    int main() {
        Node *head = NULL;
        int n = 0;
        char c = 'y';
        while (c == 'y') {
            Node *node = malloc(sizeof(Node));
            printf("Node #%d: ", n);
            scanf(" ");
    
            /* Store the string directly into the node. */
            fgets(node->str, 10, stdin);
            /* Remove the newline character. */
            node->str[strcspn(node->str, "\n")] = 0;
    
            node->next = head;
            head = node;
            ++n;
            printf("Continue? (y/N): ");
            scanf("%c", &c);
        };
    
        Node *curr = head;
        while (curr != NULL) {
            printf("%s\n", curr->str);
            Node *temp = curr;
            curr = curr->next;
    
            /* Remember to free the memory. */
            free(temp);
        }
    
        return 0;
    }
    

    【讨论】:

    • 将输入存储在他的节点中肯定更有效,而且我似乎完全忘记了释放我的记忆。真的有必要删除换行符吗?虽然如果需要这样做是有道理的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-17
    • 1970-01-01
    • 2017-04-22
    • 2011-05-19
    相关资源
    最近更新 更多