我有一个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,但这也不起作用
主要总结评论:
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;
}
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.