向链接列表添加内容时,列表中的其他项目采用最后添加的项目的名称

问题描述 投票:0回答:1

我有一个c控制台应用程序,它接受用户的输入来对列表执行操作。

当用户输入“add”来添加项目时,它将添加该项目,但它将采用使用“add”命令创建的最后一个项目的名称

列表.h

typedef struct node {
    char* name;
    int value;
    struct node * next;
}node_js;

static node_js* currentNode;

void printList(node_js* thing) {
    currentNode = thing;

    while (currentNode != NULL) {
        printf("%s\n", currentNode->name);
        printf(">%d\n", currentNode->value);

        currentNode = currentNode->next;
    }
    printf("\n");
}

void addLast(node_js** thing,const char* name, int val) {
    if (*thing == NULL) {
        *thing = (node_js*)malloc(sizeof(node_js));
        //(*thing)->name = name;
        (*thing)->name = name;
        (*thing)->value = val;
        (*thing)->next = NULL;
    }
    else {
        currentNode = *thing;

        while (currentNode->next != NULL) {
            currentNode = currentNode->next;
        }

        currentNode->next = (node_js*)malloc(sizeof(node_js));
        //currentNode->next->name = strdup(name);
        currentNode->next->name = name;
        currentNode->next->value = val;
        currentNode->next->next = NULL;
    }
}

void removeLast(node_js** thing) {
    if (*thing == NULL) {
        return;
    }

    if ((*thing)->next == NULL) {
        free(*thing);
        *thing = NULL;
        return;
    }

    currentNode = *thing;

    while (currentNode->next->next != NULL) {
        currentNode = currentNode->next;
    }

    free(currentNode->next);
    currentNode->next = NULL;
}

main.c

//the problem is on the addLast() inside the while(1), the probelm only occur with items that are
//added when user inputs "add"
#include <stdio.h>
#include <stdlib.h> #include "list.h"

static int numInput; static char textInput[32];

static char uInput[16];

node_js * list = NULL;

int main() { printf("--- Welcome to the progam! ---\n>Type 'exit', 'quit' or 'q' to exit\n>Type 'help' for a list of the commands\n\n");

//make list
list = (node_js*)malloc(sizeof(node_js));

list->name = "joe";
list->value = 10;
list->next = (node_js*)malloc(sizeof(node_js));

list->next->name = "james";
list->next->value = 20;
list->next->next = NULL;

    addLast(&list, "jane", 30); //here it works fine

while (1) {
    printf("input: ");
    scanf_s("%s", textInput, sizeof(textInput));

    if (strcmp(textInput, "quit") == 0 || strcmp(textInput, "q") == 0 ||  strcmp(textInput, "exit") == 0) {
        printf("Bye!");
        free(list);
        exit(1);
    }
    if (strcmp(textInput, "print") == 0) {
        printList(list);
    }
    if (strcmp(textInput, "add") == 0) {
        printf("name: ");
        scanf_s("%s", uInput, sizeof(uInput));/*the problem is on the addLast() inside the while(1), the probelm only occur with items that are added when user inputs "add"*/
        printf("number: ");
        scanf_s("%d", &numInput, sizeof(numInput));

        addLast(&list, uInput, numInput);
        printf("--- added (%s, %d) ---\n", uInput, numInput);

        
    }
    if (strcmp(textInput, "remove") == 0){
        removeLast(&list);
        printf("--- Removed last item of list ---\n");
    }

}
free(list);
return 0;

}

我没有使用 textInput 扫描用户输入,而是尝试为此创建另一个字符。 Codunt 在这方面找到了任何东西,并尝试询问 chatgpt,但这也不起作用

arrays c string linked-list
1个回答
0
投票

主要总结评论:

addLast(&list, uInput, numInput)

反过来,

(*thing)->name = name;

为列表中的每个节点提供相同的指针,指向main中存在的same

uInput
数组。每次使用
uInput
命令时,
add
的内容都会被覆盖。结果是列表中的所有节点共享相同的字符串,并且其字符串值始终等于最近的输入。

相反,您必须创建每个字符串的副本,并在每个关联节点中存储指向该副本的指针。

这可以通过为字符串长度(以字节为单位)分配内存,再加上一个用于空终止字符

'\0'
)的额外字节来完成。

一般模式是

char *create_copy_of_a_string(const char *a_string)
{
    char *copy = malloc(1 + strlen(a_string));

    if (copy)
        strcpy(copy, a_string);

    return copy;
}

在许多平台上(例如,POSIX,以及即将推出的 C23),

strdup
都可用,它就是这样做的。


其他问题包括:

单个

free(list);
仅释放列表中第 first 节点的内存。

代码的一般重复(尤其是

addLast
)。

使用

scanf
(
scanf_s
) 进行用户输入可能会在输入错误时导致令人沮丧的结果,并且输入缓冲区会变得混乱。一般建议是使用 fgets 将输入的整个
lines
读取到缓冲区中,然后根据需要处理该数据(通常为
sscanf
strtol
strtok
等)。这并不是万无一失的,但它确实大大简化了问题。

函数的实现应放置在 source 文件 (

.c
) 中,而不是 header 文件 (
.h
) 中。


在下面的粗略示例中,库函数的签名(

printList
addLast
removeLast
)保持不变。这并没有为干净地处理/传播错误留下太多空间,因此错误处理在很大程度上是疏忽的。特别是,一个健壮的程序应该处理
malloc
(
calloc
) 返回
NULL
的事件,并避免取消引用空指针值。

否则,它会被重构相当多的量(为了简洁起见,进行了简化)。

list.h

#ifndef LIST_H
#define LIST_H

typedef struct node {
    char *name;
    int value;
    struct node *next;
} node_js;

void printList(node_js *);
void addLast(node_js **, const char *, int);
void removeLast(node_js **);

#endif

list.c

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

#include "list.h"

void printList(node_js *node)
{
    while (node) {
        printf("<%s> <%d>\n", node->name, node->value);
        node = node->next;
    }
}

void addLast(node_js **head, const char *name, const int value)
{
    node_js *node = calloc(1, sizeof *node);

    /* create a copy of the string */
    node->name = malloc(1 + strlen(name));
    strcpy(node->name, name);

    node->value = value;

    if (!*head)
        *head = node;
    else {
        node_js *current = *head;

        while (current->next)
            current = current->next;

        current->next = node;
    }
}

void removeLast(node_js **node)
{
    if (!*node)
        return;

    while ((*node)->next)
        node = &(*node)->next;

    free((*node)->name);
    free(*node);
    *node = NULL;
}

main.c

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

#define match(x, y) (0 == strcmp((x), (y)))

static int read_a_line(char *buf, int len)
{
    if (!fgets(buf, len, stdin))
        return 0;

    /* remove the newline character, if present */
    buf[strcspn(buf, "\n")] = 0;

    return 1;
}

static int add_to_list(node_js **list)
{
    char name[256];
    char value[256];

    printf("Name: ");
    if (!read_a_line(name, sizeof name))
        return 0;
    printf("Value: ");
    if (!read_a_line(value, sizeof value))
        return 0;

    /* assume this succeeds */
    addLast(list, name, strtol(value, NULL, 10));
    return 1;
}

int main(void)
{
    node_js *list = NULL;

    puts("------- Welcome to the program! -------");

    while (1) {
        char selection[256];

        printf("Enter a command (quit, print, add, remove): ");

        if (!read_a_line(selection, sizeof selection) || match(selection, "quit"))
            break;

        if (match(selection, "print"))
            printList(list);
        else if (match(selection, "add"))
            add_to_list(&list);
        else if (match(selection, "remove")) {
            removeLast(&list);
        } else
            printf("Invalid selection <%s>\n", selection);
    }

    while (list) {
        node_js *next = list->next;
        free(list->name);
        free(list);
        list = next;
    }

    puts("Goodbye.");
}

使用中:

------- Welcome to the program! -------
Enter a command (quit, print, add, remove): add
Name: foo
Value: 123
Enter a command (quit, print, add, remove): add
Name: bar
Value: 456
Enter a command (quit, print, add, remove): add
Name: qux
Value: 789
Enter a command (quit, print, add, remove): print
<foo> <123>
<bar> <456>
<qux> <789>
Enter a command (quit, print, add, remove): remove
Enter a command (quit, print, add, remove): print
<foo> <123>
<bar> <456>
Enter a command (quit, print, add, remove): quit
Goodbye.
© www.soinside.com 2019 - 2024. All rights reserved.