提问人:danilogames220 提问时间:10/22/2023 最后编辑:chqrliedanilogames220 更新时间:10/23/2023 访问量:79
向链表添加内容时,列表中的其他项目采用最后添加的项目的名称
When adding something to linked list, the other items on the list take the name of the last item added
问:
我有一个用 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 program! ---\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;
}
我没有使用扫描用户输入,而是尝试为此制作另一个数组。找不到任何关于此的内容,还尝试询问 ChatGPT,但没有帮助。textInput
答:
大致总结一下评论:
addLast(&list, uInput, numInput)
反过来,
(*thing)->name = name;
将每个节点的成员设置为相同的指针值:指向 中存在的数组的第一个元素的指针。每次使用命令时,都会覆盖 的内容,结果是列表中的所有节点共享相同的字符串,该字符串始终是最近的输入名称。name
uInput
main
uInput
add
list->name = "joe";
、 和 不要共享此问题,因为每个字符串文本都是指向不同的1、静态分配的只读字符数组的指针。list->next->name = "james";
addLast(&list, "jane", 30);
相反,您必须创建每个字符串的副本,并在每个关联节点中存储指向该副本的指针。
这可以通过为字符串的长度(以字节为单位)分配内存,并为 null 终止字符 () 分配一个额外的字节来完成。'\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
请注意,使用这种方法时,通过将指向动态分配的字符串 () 的指针和指向静态分配的字符串(字符串文字)的指针混合来创建列表,当涉及到前者时,会产生问题。一般建议是避免混合使用这两种类型的指针。malloc
free
(addLast(&list, “简”, 30);
在下面的示例中会很好,其中 list->name = “joe”;
将导致未定义的行为。)
或者,将成员更改为数组,并将输入复制到该数组。使用此方法时,请注意缓冲区溢出。name
其他问题包括:
single 仅释放列表中第一个节点的内存。free(list);
代码的一般重复(特别是)。addLast
当输入错误的内容时,将 () 用于用户输入可能会导致令人沮丧的结果,并且输入缓冲区变得一团糟。一般的建议是将整行输入读入缓冲区,然后根据需要处理该数据(通常为 、、 等)。这不是万无一失的,但它确实大大简化了问题。scanf
scanf_s
fgets
sscanf
strtol
strtok
函数的实现应放在源文件 () 中,而不是头文件 () 中。.c
.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.
1. 相同字符串值的字符串文字可能占用也可能不占用相同的内存(即,即使内容相等,也不能保证指向字符串文字的两个指针比较相等)。裁判。
评论
uInput
uInput
(*thing)->name = name;
struct node *t = *thing; t->name = name;
(*thing)->name);
一旦你完成了对它们的工作。(*thing)->name = name;
(*thing)->name = malloc(strlen(name) + 1); /* check if ok */ strcpy((*thing)->name, name);