0

I have a database application and after adding and deleteting some records i enter to case 6 to free memory and exit app. I know when I exit the program memory automatic gets free but I do this as teacher says. Same problem with heap corruption I get when delete a record and then i try to free the last record. Below you can find my program. I know it's a bit longer but after much days and hours i can't determine the problem. Below you will find my code.

    #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;
    }
trincot
  • 317,000
  • 35
  • 244
  • 286
dxerok
  • 1
  • 5

2 Answers2

0

In one place when you allocate space for an extra record, you use:

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

I think you are creating one too many records there, should be i + 1

Later on in the code you use

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

and that appears correct. Since it is the last student record where you have the problem, then this is the issue, when reading in the file you have an extra record at the end. You have an extra record at the end of the array within nothing in it.

Sean F
  • 4,344
  • 16
  • 30
  • Ok, now i put i+1 and for example: I have 6 records, delete the first one free working and then when i free for other record get heap corruption. – dxerok Jan 11 '18 at 18:46
0

When you are deleting a record, you may be copying a long student name into a short buffer.

firstname was allocated so that it was just long enough to fit the students name.

When you delete a record, the next student's name, which could be longer, is copied into the short buffer, running over the end, and destroying the heap

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

Rather than using string copy, you could just free the old names, and reassign the pointers.

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

Also, when you change student names, it looks like you allocate more memory, but don't free the old memory