fgets() 覆盖结构体数据的一部分

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

所以我在这个编码项目上遇到了一些麻烦,它应该是一个有一群假学生的链表。我可以正确地让第一个学生进入,但是当 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 就在那里,因为我看不到我正在使用的调试器中发生了什么。

c pointers linked-list overwrite
1个回答
0
投票

呼应其他人所说的,问题是您依赖于一个悬空指针(指向不再存在的内存的指针),因为您正在使用指向堆栈变量的指针

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)
© www.soinside.com 2019 - 2024. All rights reserved.