【问题标题】:Creating linked list of strings创建字符串的链表
【发布时间】:2019-04-06 15:36:41
【问题描述】:

我不熟悉数据结构和链表。 我正在使用 C 中的树进行名为 Amazon 产品可用性检查器的项目。所以我想在树的每个节点中存储字符串,但是在存储字符串时,代码没有显示任何错误,但输出也没有被打印出来。我已将节点传递给打印函数以打印字符串,但没有打印任何内容。

我只分享了一个字符串和一个节点的代码。我正在开发 ubuntu,我正在使用 C 语言进行编码。

这是我的代码:

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

typedef struct node {
    char clothing[10];
    struct node *next;
} node;

// 1) creating node

node *create(char const ch[]) {
    int i;
    node *head = NULL;
    node *temp = NULL;
    node *p = NULL;
    temp = (struct node *)malloc(sizeof(struct node));
    temp->clothing[10] = ch[10];
    temp->next = NULL;
    return temp;
}

// 2) print 

void print(node *head) {
    node *p = head;
    while (p != NULL) {
        printf("%s", p->clothing);
        p = p->next;
    }
}

int main() {
    node *head = create("clothing");
    print(head);
}

【问题讨论】:

  • 这里显示代码最受赞赏的方式是minimal reproducible example。你提出了更多的代码难题。另外,不清楚你在问什么。
  • 请了解缩进和 cmets。两者都有助于使您的代码更具可读性和更少的断裂性。
  • createtempp 中没有使用,所以删除它们。并使用strcpy 复制字符串。 temp -&gt; clothing[10] = ch[10] 正在分配一个字符,实际上该字符超出了范围,因此您正在破坏内存。
  • @TomKarzes 你能详细说明你的答案吗?这将意味着很多。谢谢。
  • @chqrlie 是的,当然......我不知道如何接受堆栈溢出的答案......谢谢!!

标签: c string linked-list


【解决方案1】:

您的create 函数不正确:

  • 您没有测试潜在的malloc 失败
  • 您不复制字符串,而只是通过尝试写入超出数组末尾的clothing[10] 导致未定义的行为。顺便说一句,您阅读了ch[10],这很可能也超出了范围。如果ch 太长,您应该复制字符串,同时避免缓冲区溢出。

这是一个改进的版本:

#incude <string.h>
#incude <stdlib.h>

node *create(char const ch[]) {
    temp = malloc(sizeof(node));
    if (temp != NULL) {
        temp->next = NULL;
        temp->clothing[0] = '\0';
        strncat(temp->clothing, ch, sizeof(temp->clothing) - 1);
    }
    return temp;
}

从 C99 开始,有一种方法可以分配字符串的副本,而不受其大小的限制,并且不需要单独的分配和 node 结构中的指针。它被称为灵活数组。以下是它的工作原理:

typedef struct node {
    struct node *next;
    char clothing[];
} node;

node *create(char const ch[]) {
    size_t size = strlen(ch) + 1;
    temp = malloc(sizeof(node) + size);
    if (temp != NULL) {
        temp->next = NULL;
        memcpy(temp->clothing, ch, size);
    }
    return temp;
}

【讨论】:

  • @chqrlie 非常感谢!!它工作得很好。这意味着很多。
【解决方案2】:
node *addnode(node *after, const char *str)
{
    node *nptr;

    nptr = malloc(sizeof(*nptr));
    nptr -> partstr = malloc(strlen(str) + 1);
    /* error checking you need to add after every malloc */
    strcpy(nptr -> partstr, str);
    if(!after)
    {
        nptr -> prev = NULL;
        nptr -> next = NULL;
    }
    else
    {
        after -> next -> prev = nptr;
        nptr -> next = after -> next;
        after -> next = nptr;
        nptr -> prev = after;
    }
    return nptr;
}

【讨论】:

  • 你的函数与OP的结构node不对应,没有char*partstr;也没有prev链接
  • 但是更好:)
【解决方案3】:

我已将节点传递给打印函数以打印字符串,但没有打印任何内容。

在做

temp -> clothing[10] = ch[10];

您从字符串中写入(并且可能被读取)一个字符,temp -&gt; clothing 中的最大索引为 9

你想要类似的东西

strcpy(temp -> clothing, ch);

但要注意不要出门衣服,因为ch太长了

可以的

strncpy(temp -> clothing, ch, sizeof(temp -> clothing) - 1);
temp -> clothing[sizeof(temp -> clothing) - 1] = 0; /* useful if strlen(ch) >= 10 */

您确定不想将 char clothing[10]; 替换为 char * clothing; 以不限制为 10 吗?

【讨论】:

  • 请不要提倡使用strncpy,这个功能被广泛地误解并导致生产代码中的无数错误。顺便说一句,您不需要在代码中进行测试,只需强制终止符即可。看到这个:randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already
  • 当正确使用它时,它会按预期工作 ;-) 但我鼓励 OP 不要使用恒定的数组大小,而是使用 char* ^^ 是的,添加该术语的测试是无用的
  • 也许吧,但我遇到的大多数程序员,无论是面对面还是在线,都没有正确使用它。它的行为是违反直觉的,更不用说效率低下了。你知道它用空值填充目标数组到作为第三个参数传递的大小吗?
  • @chqrlie to pad 可能很有用,如果常量大小很大,则表明不是正确的方法,但 char * 更好。我个人认为我从未为我使用过 strncpy :-)
  • 填充几乎总是无用的,就像这个特定示例中的情况一样。这个函数首先在早期的 Unix 系统中用于将登录信息复制到内核结构中。当时登录名被限制为 6 个字母,而且空间非常宝贵,因此省略空终止符是一种节省内存的方法。它永远不应该成为 C 标准,但它是原始 C 库的一部分,人们使用它,从第一天开始就大多不正确。
猜你喜欢
  • 1970-01-01
  • 2021-05-29
  • 2021-09-25
  • 2016-02-13
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多