-1

I'm learning about disjoint dynamic memory, so I'm trying to make my own program. I need someone to help me see my problems and show me how to fix them.

I'm almost done with my program, but still have some problems in my program. My problem: my saveData() function and reload() function do not work correctly.

  • I'm not sure whether the saveData() function does get all the data I need
  • my reload() function just output it has brought back data from the bin file (in saveData() function) and then exit program with some weird code (ex: 8500241654)

Without the above problem, my program works well. Please check the 3 problems in my program in .h file and .c file

C Program Description:

"You will write a program that will store the information about automobiles. The information is about make, mode, yearBuilt, and cost (use struct). The user will choose from menu what they want to do (add auto, display auto with orders of cost or make, use switch).

When the program begins, if there was a previous data file of automobile information it will be loaded automatically. The program will begin where the user last left off. If there is no previous data file, then the program will ask the user how many automobiles record will be needed and the program will start fresh.

When the program ends, all data will be saved to a bin file. All memory will be released from the heap. "

P/s: thank you so much, and appreciate your help. <Here is my .h file>

// FUNCTION PROTOTYPES
typedef struct {
    char make[50]; // ex: Ford, Honda, Toyota
    char model[50]; // ex: Corolla, Camry
    int yearBuilt; // ex: 2001, 2022
    int cost; // ex: 20500, 8999, 15000
} AUTOMOBILE; // 108 bytes

void addAuto(AUTOMOBILE* a[], int* eSize, int size);
int compareChars(const void* a, const void* b);
void displayAuto(AUTOMOBILE* autos[], int eSize);
void displayMenu();
void freeMemory(AUTOMOBILE* autos[], int size);
int getInt(char m[]);
int getCh(char m[]);
void quitProgram(int* temp);
AUTOMOBILE** reload(AUTOMOBILE* a[], int* eSize, int* size);
void saveData(AUTOMOBILE *a[], int eSize, int size);
void sortByCost(AUTOMOBILE* autos[], int eSize);
void sortByMake(AUTOMOBILE* autos[], int eSize);

// FUNCTIONS

void addAuto (AUTOMOBILE *a[], int* eSize, int size) {
    char again = 'N';
    char autoMake[50];
    char autoModel[50];
    do {
        if (*eSize == size) {
            printf("No room to add more automobile...it is full!\n");
            system("pause");
            return;
        }
        printf("\nAdding a new automobile to the array of items\n");
        // add make
        printf("What is the automobile's make (uppercase first letter, ex: Honda)? ");
        scanf("%s", a[*eSize]->make);
        // add model
        printf("What is the automobile's model (uppercase first letter, ex: Camry)? ");
        scanf("%s", a[*eSize]->model);
        // add year built
        a[*eSize]->yearBuilt = getInt("When was the automobile built (ex: 2022)? ");
        // add cost
        a[*eSize]->cost = getInt("How much does the automobile cost (ex: 45500)? ");
        *eSize += 1;
        printf("\nWould you like to add another item? [Y/N]: ");
        scanf(" %c", &again);
    } while (toupper(again) == 'Y');
} // end addAuto

int compareChars(const void* a, const void* b) {
    const char* arg1 = *(const char**) a;
    const char* arg2 = *(const char**) b;

    return strcmp(arg1, arg2);
} // end compareChars

void displayAuto(AUTOMOBILE *autos[], int eSize) {
    char option;
    printf("\nChoose your desired order");
    printf("\n[C]ost low to high");
    printf("\n[M]ake ascending order");
    option = getCh("\nEnter option: ");
    if (option == 'C' || option == 'c')
        sortByCost(autos, eSize);
    else if (option == 'M' || option == 'm')
        sortByMake(autos, eSize);
} // end displayAuto

void displayMenu() {
    printf("\n[A]dd one automobile");
    printf("\n[D]isplay all automobiles by");
    printf("\n\t[C]ost low to high");
    printf("\n\t[M]ake ascending order"); // ascending order: A-Z
    printf("\n[Q]uit program\n");
} // end displayMenu

void freeMemory(AUTOMOBILE* autos[], int size) {
    for (int i = 0; i < size; i++) {
        free(autos[i]);
    }
    free(autos);
} // end freeMemory

int getCh(char m[]) {
    char result;
    char badValue = 'F';
    // loop until get integer value
    do {
        badValue = 'F';
        printf("%s", m);
        scanf(" %c", &result);
        // if "result" isn't an alphabet, do the loop again
        if (isalpha(result) == 0) {
            printf("\nYou must enter a valid character!\n");
            badValue = 'T';
        } // end If
    } while (badValue == 'T');
    return result;
} // end getCh

int getInt(char m[]) {
    int result = 0;
    char badValue = 'F';
    // loop until get integer value
    do {
        badValue = 'F';
        printf("%s", m);
        if (scanf("%i", &result) != 1) {
            printf("\nYou must enter a valid real numeric value!\n");
            badValue = 'T';
        } // end If
    } while (badValue == 'T');
    return result;
} // end getInt

void quitProgram(int *temp) {
    printf("\nThank you for using program!\n");
    *temp = 1;
} // end quitProgram

AUTOMOBILE** reload(AUTOMOBILE* a[], int* eSize, int* size) { 
    *eSize = 0;
    FILE* fp = fopen("binaryDocument.bin", "rb");
    if (fp == NULL) {
        printf("\nNo information has been reload!\n");
        system("pause");
        return a;
    } // end if
    printf("\nI have brought back the previous saved data into the array!\n");
    system("pause");
    // get the size
    fread(size, sizeof(int), 1, fp); 
    // memory allocation for [size] pointers, [size] * 4 bytes of space
    // use the size to allocate the space for the pointer array
    a = calloc(*size, sizeof(AUTOMOBILE*)); 
    if (a == NULL) {
        printf("Allocation of memory failed...\n");
        exit(-1);
    }
    // go through each one of them, and allocate 108 bytes each and allow these pointers to refer to it
    for (int i = 0; i < size; i++) {
        a[i] = calloc(1, sizeof(AUTOMOBILE));
        if (a[i] == NULL) {
            printf("Allocation of memory at autos[%i] failed...\n", i);
            exit(-1);
        }
    }
    // get the eSize and use the eSize to reload the array
    fread(eSize, sizeof(int), 1, fp); 
    fread(a, sizeof(AUTOMOBILE*), *eSize, fp);
    fclose(fp);
    return a;
} // end reload

void saveData(AUTOMOBILE *a[], int eSize, int size) { // PROBLEM HERE
    FILE* fp = fopen("binaryDocument.bin", "wb");
    if (fp == NULL) {
        printf("\nCould not save the information to a binary file\n");
        system("pause");
        return;
    } // end if
    fwrite(&size, sizeof(int), 1, fp);
    fwrite(&eSize, sizeof(int), 1, fp);
    fwrite(a, sizeof(AUTOMOBILE*), eSize, fp);
    fclose(fp);
} // end saveData

void sortByCost(AUTOMOBILE *autos[], int eSize) {
    int temp = 0;
    int autoCost[1000];
    for (int i = 0; i < eSize; i++) {
        autoCost[i] = autos[i]->cost;
    }
    for (int i = 0; i < eSize; ++i) {
        for (int j = i + 1; j < eSize; ++j) {
            if (autoCost[i] > autoCost[j]) {
                temp = autoCost[i];
                autoCost[i] = autoCost[j];
                autoCost[j] = temp;
            }
        }
    }
    printf("\nAutomobiles are displayed from low to high in term of cost: \n");
    for (int l = 0; l < eSize; l++) {
        for (int k = 0; k < eSize; k++) {
            if(autoCost[l] == autos[k]->cost)
                printf("%i\t%s\t%s\t%i\n", autoCost[l], autos[k]->make, autos[k]->model, autos[k]->yearBuilt);
        }
    }
} // end sortByCost

void sortByMake(AUTOMOBILE *autos[], int eSize) {
    qsort(autos, eSize, sizeof(AUTOMOBILE*), compareChars);
    printf("\nAutomobiles are displayed A-Z: \n");
    for (int i = 0; i < eSize; i++) {
        printf("%s\t%s\t%i\t%i\n", autos[i]->make, autos[i]->model, autos[i]->yearBuilt, autos[i]->cost);
    }
} // end sortByMake

<Here is my .c file>

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "DJDMHeader.h"
//****************************************************

// MAIN FUNCTION
int main() {    
    int size = 0;                   
    int eSize = 0;
    AUTOMOBILE** autos = NULL; // create the variable to make the array of automobile pointers
    int i, temp = 0;
    char choice;
    // reload data
    autos = reload(autos, &eSize, &size);
    // case: nothing to reload, start fresh
    if (size == 0) {
        // get integer value for variable size
        size = getInt("How many automobiles will you have at the most: ");
        // memory allocation for [size] pointers, [size] * 4 bytes of space
        autos = calloc(size, sizeof(AUTOMOBILE*));
        if (autos == NULL) {
            printf("Allocation of memory failed...\n");
            exit(-1);
        }
        // go through each one of them, and allocate 108 bytes each and allow these pointers to refer to it
        for (i = 0; i < size; i++) {
            autos[i] = calloc(1, sizeof(AUTOMOBILE));
            if (autos[i] == NULL) {
                printf("Allocation of memory at autos[%i] failed...\n", i);
                exit(-1);
            }
        }
    }
    

    while (temp == 0) {
        displayMenu();
        choice = getCh("What is your choice?: ");
        // switch
        switch (choice) {
        case 'a':
        case 'A':
            addAuto(autos, &eSize, size);
            break;
        case 'd':
        case 'D':
            displayAuto(autos, eSize);
            break;
        case 'q':
        case 'Q':
            quitProgram(&temp);
            break;
        default:
            printf("\nPlease choose the existed choices!\n");
        }
    }
    // Save data
    saveData(autos, eSize, size); 
    // Free memory
    freeMemory(autos, size);
    return 0;   
}

If anything about my program or my question make you unhappy (or something like that), please tell me, I will edit again. So much thanks.

  • The read and write functions appear to be reading/writing an array of pointers but not the actual data. Since the data doesn't appear to be allocated sequentially in one block you'll need to loop and read/write each item. – Retired Ninja Jul 31 '22 at 05:47
  • can you show me how to do it, sir? I'm learning about it, but I don't have any examples for this content (I searched on google and found nothing, or I was not able to find the right one). – C beginner Jul 31 '22 at 05:49
  • `typedef struct { ... } AUTOMOBILE; // 108 bytes`.. NO! [NEVER assume](https://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member) that `sizeof struct == sizeof all the fields`. – Zakk Jul 31 '22 at 08:17
  • thanks for letting me know about the size of struct, but can you help me solve my problem, sir? – C beginner Jul 31 '22 at 08:58
  • 1 problem per question, simplify your code to demonstrate said problem (eliminate what works), hard-code data for instance is preferable to interactive programs. See [mre]. – Allan Wind Jul 31 '22 at 11:16

1 Answers1

0

You either operate on an array:

#include <stdio.h>

typedef struct {
    char make[50]; // ex: Ford, Honda, Toyota
    char model[50]; // ex: Corolla, Camry
    int yearBuilt; // ex: 2001, 2022
    int cost; // ex: 20500, 8999, 15000
} AUTOMOBILE;

// array
void saveData(AUTOMOBILE *a, int eSize, int size) {
    FILE *fp = fopen("binaryDocument.bin", "wb");
    if (!fp) {
        printf("\nCould not save the information to a binary file\n");
        return;
    }
    fwrite(&size, sizeof(int), 1, fp);
    fwrite(&eSize, sizeof(int), 1, fp);
    fwrite(a, sizeof(*a), eSize, fp);
    fclose(fp);
}

int main() {
    AUTOMOBILE a[] = {
        { "Ford", "Model T", 1908, 1000 },
        { "Honda", "Accord", 2022, 20000 }
    };
    saveData(a, sizeof(a) / sizeof(*a), 42);
}

or as an array of pointers:

#include <stdio.h>

typedef struct {
    char make[50]; // ex: Ford, Honda, Toyota
    char model[50]; // ex: Corolla, Camry
    int yearBuilt; // ex: 2001, 2022
    int cost; // ex: 20500, 8999, 15000
} AUTOMOBILE; // 108 bytes

// array of pointers
void saveData(AUTOMOBILE *a[], int eSize, int size) {
    FILE *fp = fopen("binaryDocument.bin", "wb");
    if (!fp) {
        printf("\nCould not save the information to a binary file\n");
        return;
    }
    fwrite(&size, sizeof(int), 1, fp);
    fwrite(&eSize, sizeof(int), 1, fp);
    for(unsigned i = 0; i < eSize; i++) {
        fwrite(a[i], sizeof(**a), 1, fp);
    }
    fclose(fp);
}

int main() {
    AUTOMOBILE *a[] = {
        &(AUTOMOBILE) { "Ford", "Model T", 1908, 1000 },
        &(AUTOMOBILE) { "Honda", "Accord", 2022, 20000 }
    };
    saveData(a, sizeof(a) / sizeof(*a), 42);
}

What you call size is usually referred to as max_size or capacity. eSize vs size is confusing. In either case, size is an artifact of your in memory representation so you don't need to persist that.

Prefer unsigned types when the value cannot be negative.

Types (AUTOMOBILE) are not by convention upper case (which is used for constants like enums and defined symbols).

Allan Wind
  • 23,068
  • 5
  • 28
  • 38