在C中正常阻塞后检测到堆损坏

时间:2018-01-11 18:33:41

标签: c heap corruption

我有一个数据库应用程序,在添加和删除一些记录后,我进入案例6以释放内存并退出应用程序。我知道当我退出程序时,内存自动获得免费,但我按照老师的说法这样做。与删除记录然后我尝试释放最后一条记录时获得的堆损坏相同的问题。下面你可以找到我的程序。我知道它有点长,但经过几天和几个小时我无法确定问题。您将在下面找到我的代码。

    #include <stdio.h>
    #include <malloc.h>
    #include <string.h>

    typedef struct StudentDynamic
    {
        char* firstName;
        char* lastName;
        float grade;
    }StudentDynamic;

    void exportCSV(char *filename, StudentDynamic* pStudents, int nStudents)
    {
    printf("\n Creating %s.csv file. \n ", filename);
    FILE *fp;
    filename = strcat(filename, ".csv");
    fp = fopen(filename, "wb+");
    fprintf(fp, "Student No., First Name, Last Name, Grade");
    for (int i = 0; i<nStudents; ++i)
    {
    fprintf(fp, "\n%d", i + 1);
    fprintf(fp, ",%s ", pStudents[i].firstName);
    fprintf(fp, ",%s ", pStudents[i].lastName);
    fprintf(fp, ",%f ", pStudents[i].grade);
    }
    fclose(fp);
    printf("\n File %s succesfully created!\n", filename);
    }

    void printStudents(StudentDynamic* pStudents, int nStudents)
    {
    printf("==========");
    printf(" List of Students");
    printf(" ========== \n");
    for (int i = 0; i < nStudents; ++i)
    {
    printf("%d. %12s %12s %8.2f", i + 1,
        pStudents[i].firstName,
        pStudents[i].lastName,
        pStudents[i].grade);
    printf("\n");
    }
    }


    void rewriteFile(StudentDynamic* pStudents, int nStudents)
    {
    for (int i = 0; i < nStudents - 1; ++i)
    for (int j = i + 1; j < nStudents; ++j)
    {
        if (pStudents[i].grade > pStudents[j].grade)
        {
            StudentDynamic aux;
            aux = pStudents[i];
            pStudents[i] = pStudents[j];
            pStudents[j] = aux;
        }
    }

    FILE *rwF;
    rwF = fopen("logfile.bin", "wb");

    for (int i = 0; i<nStudents; ++i)
    {
    fprintf(rwF, "%s\n", pStudents[i].firstName);
    fprintf(rwF, "%s\n", pStudents[i].lastName);
    if (i + 1 == nStudents)
    {
        fprintf(rwF, "%f", pStudents[i].grade);
        break;
    }
    fprintf(rwF, "%f\n", pStudents[i].grade);
    }
    fclose(rwF);
    }


    int main()
    {
    int nStudents, i = 0;
    StudentDynamic* pStudents = NULL;
    char auxfirstName[255], auxlastName[255];
    float auxGrade, updGrade;
    FILE *pFile;
    pFile = fopen("logfile.bin", "rb");
    if (pFile == NULL)
    {
    printf("Could not open file or is empty! Exiting...");
    exit(2);
    }
    while (!feof(pFile) && pFile != " ")
    {
    pStudents = (StudentDynamic*)realloc(pStudents, sizeof(StudentDynamic)*(i + 2));
    fscanf(pFile, "%s", auxfirstName);
    pStudents[i].firstName = (char*)malloc(strlen(auxfirstName) + 1);
    strcpy(pStudents[i].firstName, auxfirstName);

    fscanf(pFile, "%s", auxlastName);
    pStudents[i].lastName = (char*)malloc(strlen(auxlastName) + 1);
    strcpy(pStudents[i].lastName, auxlastName);

    fscanf(pFile, "%f", &auxGrade);
    pStudents[i].grade = auxGrade;

    strcpy(auxfirstName, "");
    strcpy(auxlastName, "");
    auxGrade = 0;
    i++;
    }
    nStudents = i;

    for (int i = 0; i < nStudents - 1; ++i)
    for (int j = i + 1; j < nStudents; ++j)
    {
        if (pStudents[i].grade > pStudents[j].grade)
        {
            StudentDynamic aux;
            aux = pStudents[i];
            pStudents[i] = pStudents[j];
            pStudents[j] = aux;
        }
    }
    fclose(pFile);

    char choice;
    printf("\t\t================== STUDENT DATABASE APPLICATION ==================");
    printf("\n\n");
    printf(" \n\t\t\t============================================");
    printf("\n \t\t\t  1. Create Student");
    printf("\n \t\t\t  2. Update Record");
    printf("\n \t\t\t  3. Delete Record");
    printf("\n \t\t\t  4. Export DB to CSV");
    printf("\n \t\t\t  5. List Students");
    printf("\n \t\t\t  6. Exit Program");
    printf(" \n\t\t\t============================================");
    printf("\n\n");
    printf("  Select Your Choice : ");
    getch();
    while (1)
    {
    choice = getchar();
    switch (choice)
    {
    case '1':
        nStudents++;
        pStudents = (StudentDynamic*)realloc(pStudents, sizeof(StudentDynamic) * (nStudents + 1));
        printf("Details of the new student:\n");
        printf("First name: ");
        scanf("%s", auxfirstName);
        pStudents[nStudents - 1].firstName = (char*)malloc(strlen(auxfirstName) + 1);
        strcpy(pStudents[nStudents - 1].firstName, auxfirstName);

        printf("Last Name: ");
        scanf("%s", auxlastName);
        pStudents[nStudents - 1].lastName = (char*)malloc(strlen(auxlastName) + 1);
        strcpy(pStudents[nStudents - 1].lastName, auxlastName);

        printf("Grade: ");
        scanf("%f", &auxGrade);
        pStudents[nStudents - 1].grade = auxGrade;
        i++;
        rewriteFile(pStudents, nStudents);
        printf("\n  Enter Another Choice : ");
        break;


    case '2':
        int idtoUpdate;
        printf("Update Records for student number: ");
        scanf("%d", &idtoUpdate);
        idtoUpdate = idtoUpdate - 1;
        if (idtoUpdate>nStudents)
            printf("Your number is bigger than number of Students. Enter a correct number.");
        else
        {
            int auxI = idtoUpdate;
            printf("\n");
            printf("Change details for student number %d. \n", auxI + 1);
            printf("type 1 for Yes / type 0 for Next step\n");

            int changeChoice = 0, changeCount;
            printf("Want to change First name?:");
            scanf("%d", &changeChoice);
            changeCount = 0;
            if (changeChoice == 1)
            {
                changeCount++;
                printf("Change First name: ");
                scanf("%s", auxfirstName);
                pStudents[auxI].firstName = (char*)malloc(strlen(auxfirstName) + 1);
                strcpy(pStudents[auxI].firstName, auxfirstName);
            }

            changeChoice = 0;
            printf("Want to change Last name?:");
            scanf("%d", &changeChoice);
            if (changeChoice == 1)
            {
                changeCount++;
                printf("Change Last Name: ");
                scanf("%s", auxlastName);
                pStudents[auxI].lastName = (char*)malloc(strlen(auxlastName) + 1);
                strcpy(pStudents[auxI].lastName, auxlastName);
            }

            changeChoice = 0;
            printf("Want to change the Grade?:");
            scanf("%d", &changeChoice);
            if (changeChoice == 1)
            {
                updGrade = 0;
                changeCount++;
                printf("Change Grade: ");
                scanf(" %f", &updGrade);
                pStudents[auxI].grade = updGrade;
            }
            if (changeCount != 0)
                rewriteFile(pStudents, nStudents);
        }
        printf("\n  Enter Another Choice : ");
        break;

    case '3':
        int idtoDelete;
        printf("Delete Records for student number: ");
        scanf("%d", &idtoDelete);
        idtoDelete = idtoDelete - 1;
        if (idtoDelete>nStudents)
            printf("Your number is bigger than number of Students. Enter a correct number.");
        else
        {
            for (int i = idtoDelete; i < nStudents - 1; ++i)
            {
                strcpy(pStudents[i].firstName, pStudents[i + 1].firstName);
                strcpy(pStudents[i].lastName, pStudents[i + 1].lastName);
                pStudents[i].grade = pStudents[i + 1].grade;
            }
            free(pStudents[nStudents-1].firstName);
            free(pStudents[nStudents - 1].lastName);
            nStudents--;

            rewriteFile(pStudents, nStudents);
        }
        printf("\n  Enter Another Choice : ");
        break;

    case '4':
        char str[10];
        printf("\n Enter the filename (max. 10 characters): ");
        scanf("%s", str);
        exportCSV(str, pStudents, nStudents);
        printf("\n  Enter Another Choice : ");
        break;

    case '5':
        printf("\n");
        for (int i = 0; i < nStudents - 1; ++i)
            for (int j = i + 1; j < nStudents; ++j)
            {
                if (pStudents[i].grade > pStudents[j].grade)
                {
                    StudentDynamic aux;
                    aux = pStudents[i];
                    pStudents[i] = pStudents[j];
                    pStudents[j] = aux;
                }
            }
        printStudents(pStudents, nStudents);
        printf("\n  Enter Another Choice : ");
        break;

    case '6':
        for (int i = 0; i < nStudents-1; ++i)
        {
            free(pStudents[i].firstName);
            free(pStudents[i].lastName);
        }
        free(pStudents);

        printf("\n");
        printf("\t\t     Thank you for using my application.");
        printf("\n\n");
        exit(0);
    }
    }
    return 0;
    }

2 个答案:

答案 0 :(得分:0)

在为一个额外记录分配空间的地方,您可以使用:

    pStudents = (StudentDynamic*)realloc(pStudents, sizeof(StudentDynamic)*(i + 2));

我认为你在那里创造了太多的记录,应该是i + 1

稍后您使用的代码

    pStudents = (StudentDynamic*)realloc(pStudents, sizeof(StudentDynamic) * (nStudents + 1));

这似乎是正确的。由于它是您遇到问题的最后一个学生记录,因此这是一个问题,当您在文件中阅读时,您最后会有一个额外的记录。你在数组的末尾有一个额外的记录,其中没有任何记录。

答案 1 :(得分:0)

删除记录时,您可能会将长学生姓名复制到短暂的缓冲区中。

分配了

firstname,以便它足够长以适合学生的名字。

当你删除一条记录时,下一个学生的名字可能会更长,会被复制到短缓冲区中,在末尾运行并破坏堆

strcpy(pStudents[i].firstName, pStudents[i + 1].firstName);  //copy many characters
strcpy(pStudents[i].lastName, pStudents[i + 1].lastName);    //into short buffers

不是使用字符串副本,而是可以释放旧名称,并重新分配指针。

free(pStudents[i].firstName);
pStudents[i].firstName = pStudents[i + 1].firstName;

此外,当您更改学生姓名时,看起来您分配的内存更多,但不会释放旧内存