c - 链表中的字符串被覆盖

标签 c pointers linked-list

我已经查看了本网站上先前给出的同一主题的答案,但我的错误仍然没有消失。该程序是关于学生管理系统的,用户可以在其中动态添加新的学生信息,包括姓名、学位和年龄。当我显示节点的所有信息时,年龄显示正确,但名称和程度被最后一个节点覆盖。

    #pragma warning(disable: 4996)
    #include <stdio.h>
    #include <conio.h>
    #include <malloc.h>
    #include <Windows.h>




struct students{
    char *name;
    int age;
    char *degree;
    struct students* next;

};

int TotalStudents = 0;

struct students* ptrToHead;

void insertAtBeginning(char name[], int age, char degree[]){

    struct students * temp = (students *)malloc(sizeof(struct students));


    temp->name= name;
    temp->age = age;
    temp->degree=degree;
    temp->next = NULL;
    if (ptrToHead != NULL)
    {
        temp->next = ptrToHead;
    }
    ptrToHead = temp;

    //printf("%s\n%d\n%s", temp->name, temp->age, temp->degree);
}

void print(){

    struct students* temp = ptrToHead;
    printf("List of Students: ");
    while (temp != NULL){
        printf("\nStudent's Name: %s", temp->name);
        printf("\nStudent's Age: %d", temp->age);
        printf("\nStudent's Degree: %s", temp->degree);
        printf("\nEND - OF - STUDENT");
        temp = temp->next;

    }
    printf("\n");
}

void MainMenu();
void addStudent();


int main(){

    MainMenu();

    //students * temp= (students *)malloc(sizeof(students));

    //temp->age = 22;
    //temp->degree = "Software Engineering";
    //temp->name = "Fahad Bin Saleem";
    //temp->next = NULL;

    //ptrToHead = temp;

    //

    //printf("Age: %d\n", ptrToHead->age);
    //printf("Name: %s\n", ptrToHead->name);
    //printf("Degree: %s\n", ptrToHead->degree);



    //temp = (students *)malloc(sizeof(students));
    //temp->age = 19;
    //temp->degree = "Electrical Engineering";
    //temp->name = "Rafay Hayat Ali";
    //temp->next = NULL;



    //students * temp1 = ptrToHead;

    //while (temp1->next != NULL){
    //  temp1 = temp1->next;


    //}
    //temp1->next = temp;
    //









    _getch();
    return 0;
}

void MainMenu(){
    int choice;
    printf("Welcome to Student Information Center!\n\n");
    char* mainmenu[] = { "Display All Students", "Add A Student" };

    for (int i = 0; i < 2; i++){
        printf("%d:  %s\n", i + 1, mainmenu[i]);
    }
    printf("\n\nEnter Your Choice: ");
    scanf_s(" %d", &choice);

    if (choice == 2){
        addStudent();
    }
    if (choice == 1){
        print();
    }


}

void addStudent(){
    int NumberOfStudents;
    int choiceOfAdding;
    char tempName[40];
    char tempDegree[40];
    int tempAge;
    system("cls");



    ptrToHead = NULL;

    for (int i = 0; i < 15; i++){
        printf("  ");
    }
    printf("**ADD A STUDENT**");

    printf("\n\nHow many students do you want to add? Enter Choice: ");
    scanf_s(" %d", &NumberOfStudents);

    printf("\n\n");

    for (int i = 0; i < NumberOfStudents; i++){
        printf("\n\n");


        printf("Enter Student's Name:  ");
        fflush(stdin);
        gets_s(tempName, 40);
        printf("Enter Student's Age:  ");
        scanf_s(" %d", &tempAge);
        printf("Enter Student's Degree:  ");
        fflush(stdin);
        gets_s(tempDegree, 40);
        //insert(tempName, tempAge, tempAgeDegree);


        //printf("Where Do You Want To Add This Student?\n\n1: At The Beginning\n\n2: At A Position N\n\n3: At The End");
        //scanf_s(" %d", &choiceOfAdding);
        fflush(stdin);
        TotalStudents++;

        insertAtBeginning(tempName, tempAge, tempDegree);
        /*if (choiceOfAdding == 1){

        }*/

        printf("\n\n");

    }
    MainMenu();


}

最佳答案

让我们一一强调一些问题:

insertAtBeginning 中,您有

    struct students * temp = (students *)malloc(sizeof(struct students));

不要在 C 中强制转换 malloc 的返回值,请阅读它以获取更多详细信息。这不是一个 fatal error ,但无论如何都是不好的形式。

再往下你有temp->name= name;

您分配一个 char[] 作为名称,而不是分配必要的内存并复制您不知道传入名称的生命周期的内容,结果可能是灾难性的。您正在分配一个内存位置,其内容可能会在您不知情的情况下发生变化,并且您存储的名称可能会发生变化以反射(reflect)这一点。 (或更糟糕的是,内存位置将不再保存有效信息) 事实上,这就是每次“添加新学生”时名称都会被覆盖的原因。

为了解决这个问题,您需要:

temp->name= malloc(strlen(name)+1); 
//allocate memory and keep 1 extra for \0
strcpy(temp->name, name);
//copy the value of the parameter into the memory location we just allocated

对于 temp-> Degree= Degree; 你也会遇到同样的问题。

更多问题: 正如 Kaylum 提到的,您在彼此的体内调用 MainMenuAddStudent。 虽然在某些情况下这是可以接受的做法(例如您知道最终会由于基本情况而终止的相互递归),但这不是您想要的行为。

发生的情况是,每次从另一个函数调用其中一个函数时,您都会在彼此之上创建单独的堆栈帧。 这意味着当您有 MainMenu->addStudent->MainMenu->addStudent

原始 MainMenu 堆栈尚未解析,正在等待所有后续函数调用返回,然后再返回。

如果你的程序运行足够长的时间,你肯定会溢出堆栈。

最后一件事:在不需要时尽量避免使用全局变量。

关于c - 链表中的字符串被覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34798145/

相关文章:

c - 我是否在 c 中的堆实现的 add 函数中正确实例化了指针

C程序: Integer array pointer changes values when passed as parameter

c - 双向链表示例

java - 这段代码中的 "this"到底指的是什么?

c - 为什么我收到警告 C4034 : sizeof returns 0?

c - 使用指针返回包含前 n 个斐波那契数的数组

const 指针契约(Contract)只是热空气?

java - ArrayList 和 LinkedList 哪个运行得更快?

c - 如何在c中创建一棵n叉树

C char函数(void)和void函数(void)的区别