字符串在链表中被覆盖

时间:2016-01-14 19:34:19

标签: 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();


}

1 个答案:

答案 0 :(得分:2)

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

insertAtBeginning你有

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

不要在C中强制转换malloc,请阅读它以获取更多详细信息。这不是致命错误,而是形式不好。

进一步向下temp->name= name;

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

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

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 - &gt; addStudent - &gt; MainMenu - &gt; addStudent

原始MainMenu堆栈尚未解析,并且在它自身返回之前等待所有后续函数调用返回。

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

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