所以我在这个编码项目上遇到了一些麻烦,它应该是一个有一群假学生的链表。我可以正确地让第一个学生进入,但是当 fgets() 再次运行时,它会覆盖第一个结构中除前 4 个字符之外的所有数据。我对 C 还很陌生。
我检查了所有的指针,认为其中一个可能是问题,但对我来说没有什么突出的,我还认为这可能是内存分配问题,但我不太确定我到底需要如何/何时做任何事情就这样。
这是代码的链接:https://www.onlinegdb.com/EvK1kxplR
这是生的
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
struct student
{
char name[50];
int age;
char status[10];
char password[25];
struct student* nextStudent;
} Student;
void AddStudent(struct student** start, char name[50], int age, char status[10], char password[25]);
void InsertStudent(struct student** current, struct student newStu);
int main()
{
struct student* primaris = NULL;
struct student primFULL;
char command[100];
fgets(command, sizeof(command), stdin);
if(strcmp(command, "db\n") != 0)return 1;
while(1)
{
memset(command, 0, sizeof(command));
printf("db> ");
if(primaris != NULL)
primFULL = *primaris;
fgets(command, sizeof(command), stdin);
switch(tolower(command[0]))
{
case 'q': //quit
return 0;
case 'h': //help
printf("Welcome to COMP-232 Student Database\nValid commands are:\nadd <name>,<age>,<class>,<password>\nwhere:\n\tname is student's name.\n\tage is student's age.\n\tyear is what year the student is in.\n\tpassword is students's password.\ndelete <name> - Deletes name from database.\nlist - Lists all records in database.\nprint <name> - Prints values for name.\nquit - Exits program.\nhelp - Displays this helpful message.\n");
break;
case 'a': //add
char* trash = strtok(command, " ");
char* name = strtok(NULL, ",");
int age = atoi(strtok(NULL, ","));
char* stat = strtok(NULL, ",");
char* pWord = strtok(NULL, ",");
AddStudent(&primaris, name, age, stat, pWord);
primFULL = *primaris;
break;
case 'l': //list
struct student* current = primaris;
while(current != NULL)
{
primFULL = *current;
printf("%s", current->name);
current = current->nextStudent;
}
break;
}
}
}
void AddStudent(struct student** start, char name[50], int age, char status[10], char password[25])
{
struct student temp;
strncpy(temp.name, name, sizeof(temp.name));
temp.age = age;
strncpy(temp.status, status, sizeof(temp.status));
strncpy(temp.password, strtok(password, "\n"), sizeof(temp.password));
temp.nextStudent = NULL;
if(*start == NULL)
{
*start = &temp;
printf("%p", (*start)->nextStudent);
return;
}
while((*start)->nextStudent != NULL)
{
if(strcmp(temp.name, (*start)->nextStudent->name) < 0)
{
InsertStudent(start, temp);
return;
}
start = &(*start)->nextStudent;
}
return;
}
void InsertStudent(struct student** current, struct student newStu)
{
newStu.nextStudent = *current;
(*current)->nextStudent = &newStu;
}
primaris 是链表的开始,primFULL 就在那里,因为我看不到我正在使用的调试器中发生了什么。
呼应其他人所说的,问题是您依赖于一个悬空指针(指向不再存在的内存的指针),因为您正在使用指向堆栈变量的指针
temp
。
正如 @Gerhard 指出的那样,应该使用
malloc
分配内存,因为您希望该内存比函数的堆栈帧寿命更长(您显然是这样做的)。
像这样的错误并不罕见,尤其是当你刚刚开始时。我建议使用标志
-fsanitize=address
或在 valgrind 中运行,两者都会捕获此错误。例如,使用 -fsantize=address
运行会产生以下错误,准确指示发生了什么;从该函数返回后,我们尝试使用旧的堆栈内存。
==216298==ERROR: AddressSanitizer: stack-use-after-return on address 0x7f25ca209030 at pc 0x56b42000f747 bp 0x7ffc2b8abac0 sp 0x7ffc2b8abab0
...(etc)