Disjoint Dynamic Memory Allocation

huangapple go评论63阅读模式
英文:

Disjoint Dynamic Memory Allocation

问题

Here's the translated code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

typedef struct
{
    char make[100];
    char model[100];
    int yearBuilt;
    float cost;
} Automobile;

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);
char getChoice(char *option);
Automobile **loadAutos(int *eSize, int *size);
void myFlush();
void saveAutos(Automobile **autos, int eSize, int size);
void sortByCost(Automobile **autos, int eSize);
void sortByMake(Automobile **autos, int eSize);

int main()
{
    int size = 0;
    int eSize = 0;
    int i = 0;
    char option;
    Automobile **autos = NULL;
    autos = loadAutos(&eSize, &size);
    if (size == 0)
    {
        printf("\n\nHow many cars will you have (at the most)?: ");
        scanf("%i", &size);
        PAUSE;
        autos = calloc(size, sizeof(Automobile *));
        if (autos == NULL)
        {
            printf("Failed to allocate memory! Exiting the program.\n");
            PAUSE;
            exit(-1);
        } 
        for (int i = 0; i < size; i++)
        {
            autos[i] = calloc(1, sizeof(Automobile));
            if (autos[i] == NULL)
            {
                printf("Failed to allocate memory! Exiting the program.\n");
                for (int j = 0; j < i; j++)
                {
                    free(autos[j]);
                }
                free(autos);
                exit(-1);
            }
        }
    }
    do
    {
        getChoice(&option);
        switch (option)
        {
        case 'A':
            if (autos[eSize] == NULL)
            {
                printf("Failed to allocate memory! Exiting the program.\n");
                exit(-1);
            }
            addAuto(autos, &eSize, size);
            break;
        case 'D':
            displayAuto(autos, eSize);
            break;
        case 'Q':
            printf("Exiting program...\n");
            printf("Thank you for using the Automobile Inventory System!\n");
            printf("See you next time :)\n");
            break;
        default:
            printf("Invalid choice. Please try again.\n");
            PAUSE;
            break;
        } 
        printf("\n");
    } while (option != 'Q');
    saveAutos(autos, eSize, size);
    freeMemory(autos, size);
    return 0;
} 

void addAuto(Automobile **a, int *eSize, int size)
{
    if (*eSize == size)
    {
        printf("No room to add more automobile...it is full!\n");
        PAUSE;
        return;
    }
    printf("Enter Automobile make: ");
    scanf("%s", a[*eSize]->make);
    printf("Enter Automobile model: ");
    scanf("%s", a[*eSize]->model);
    printf("Enter Automobile yearBuilt: ");
    scanf("%i", &a[*eSize]->yearBuilt);
    printf("Enter Automobile cost: $");
    scanf("%f", &a[*eSize]->cost);
    FLUSH;
    *eSize += 1;
} 

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

    return strcmp(arg1, arg2);
} 

void displayAuto(Automobile **autos, int eSize)
{
    char option;
    printf("\n[C]ost low to high");
    printf("\n[M]ake ascending order");
    printf("\nEnter any one option: ");
    scanf(" %c", &option);
    FLUSH;
    if (option == 'C' || option == 'c')
        if (eSize == 0)
        {
            printf("You have to add at least one car....\n");
            PAUSE;
        }
        else
        {
            sortByCost(autos, eSize);
            PAUSE;
        }
    else if (option == 'M' || option == 'm')
        if (eSize == 0)
        {
            printf("You have to add at least one car....\n");
            PAUSE;
        }
        else
        {
            sortByMake(autos, eSize);
            PAUSE;
        }
} 

void displayMenu()
{
    CLS;
    printf("*****************************************************************\n");
    printf("*******Welcome to Santa's Car show!******************************\n");
    printf("*****************************************************************\n");
    printf("[A]dd one automobile\n");
    printf("[D]isplay all automobiles\n");
    printf("     [C]ost low to high\n");
    printf("     [M]ake ascending order\n");
    printf("[Q]uit program\n");
    printf("Enter your choice: ");
} 

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

char getChoice(char *option)
{
    displayMenu();
    scanf("%c", &*option);
    FLUSH;
    return toupper(*option);
} 

Automobile **loadAutos(int *eSize, int *size)
{
    FILE *file = fopen("autos.bin", "rb");
    if (file == NULL)
    {
        printf("No previous saved data...\n");
        return NULL;
    }

    fread(size, sizeof(int), 1, file);
    fread(eSize, sizeof(int), 1, file);

    Automobile **autos = calloc(*eSize, sizeof(Automobile *));
    if (autos == NULL)
    {
        printf("Allocation of memory failed...\n");
        exit(-1);
    }

    for (int 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);
        }
    }

    for (int i = 0; i < *eSize; i++)
    {
        if (fread(autos[i], sizeof(Automobile), 1, file) != 1)
        {
            printf("Failed to read data from file.\n");
            exit(-1);
        }
    }
    fclose(file);
    printf("Previous saved data has been loaded into the inventory array!\n");
    PAUSE;
    return autos;
}

void myFlush()
{
    while (getchar() != '\n');
} 

void saveAutos(Automobile **autos, int eSize, int size)
{
    FILE *file = fopen("autos.bin", "wb");
    if (file == NULL)
    {
       

<details>
<summary>英文:</summary>

Written in C. The program seems to work fine but after the second reload it crashes but then when you try to run it again it allows you to use it. However, after a couple of times it displays the error message:
HEAP CORRUPTIN DETECTED: after Normal Block (#78)
Not sure how to fix the heap. I assume I am freeing the memory incorrectly or something to that sort.

#define _CRT_SECURE_NO_WARNINGS
#define PAUSE system("pause")
#define CLS system ("cls")
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <ctype.h>

typedef struct
{
char make[100];
char model[100];
int yearBuilt;
float cost;
}Automobile;

void addAuto(Automobile** a, int* eSize, int size);
int compareChars(const void* a, const void* b);
void displayAuto(Automobile** autos, int eSize);
void displayMenu(); //function prototypes
void freeMemory(Automobile** autos, int size);
char getChoice(char* option);
Automobile** loadAutos(int* eSize, int* size);
void myFlush();
void saveAutos(Automobile** autos, int eSize, int size);
void sortByCost(Automobile** autos, int eSize);
void sortByMake(Automobile** autos, int eSize);

int main()
{
int size = 0;
int eSize = 0;
int i = 0;
char option;
Automobile** autos = NULL;
autos = loadAutos(&eSize, &size);
if (size == 0)
{
printf("\n\nHow many cars will you have (at the most)?: ");
scanf("%i", &size); FLUSH;
PAUSE;
autos = calloc(size, sizeof(Automobile*));
if (autos == NULL)
{
printf("Failed to allocate memory! Exiting the program.\n");
PAUSE;
exit(-1);
} // end of if statement
for (int i = 0; i < size; i++)
{
autos[i] = calloc(1, sizeof(Automobile));
if (autos[i] == NULL)
{
printf("Failed to allocate memory! Exiting the program.\n");
for (int j = 0; j < i; j++)
{
free(autos[j]);
}
free(autos);
exit(-1);
}
}
}
do
{
getChoice(&option);
switch (option)
{
case 'A': // Add an automobile
if (autos[eSize] == NULL)
{
printf("Failed to allocate memory! Exiting the program.\n");
exit(-1);
}
addAuto(autos, &eSize, size);
break;
case 'D': // Display automobiles
displayAuto(autos, eSize);
break;
case 'Q': // Quit program
printf("Exiting program...\n");
printf("Thank you for using the Automobile Inventory System!\n");
printf("See you next time :)");
break;
default:
printf("Invalid choice. Please try again.\n");
PAUSE;
break;
} //Ends the switch and all the cases
printf("\n");
} while (option != 'Q');
saveAutos(autos, eSize, size);
freeMemory(autos, size);
return 0;
} // end of main

void addAuto(Automobile** a, int* eSize, int size)
{
if (*eSize == size)
{
printf("No room to add more automobile...it is full!\n");
PAUSE;
return;
}
printf("Enter Automobile make: ");
scanf("%s", a[*eSize]->make);
printf("Enter Automobile model: ");
scanf("%s", a[*eSize]->model);
printf("Enter Automobile yearBuilt: ");
scanf("%i", &a[*eSize]->yearBuilt);
printf("Enter Automobile cost: $");
scanf("%f", &a[*eSize]->cost); FLUSH;
*eSize += 1;
} // 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("\n[C]ost low to high");
printf("\n[M]ake ascending order");
printf("\n\tEnter any one option: ");
scanf(" %c", &option); FLUSH;
if (option == 'C' || option == 'c')
if (eSize == 0)
{
printf("You have to add at least one car....\n");
PAUSE;
}
else
{
sortByCost(autos, eSize);
PAUSE;
}
else if (option == 'M' || option == 'm')
if (eSize == 0)
{
printf("You have to add at least one car....\n");
PAUSE;
}
else
{
sortByMake(autos, eSize);
PAUSE;
}
} // end displayAuto

void displayMenu()
{
CLS;
printf("\n");
printf("Welcome to Santa's Car show!
\n");
printf("
***********************\n");
printf("[A]dd one automobile\n");
printf("[D]isplay all automobiles\n");
printf(" [C]ost low to high\n");
printf(" [M]ake ascending order\n");
printf("[Q]uit program\n");
printf("Enter your choice: ");
} // end of displayMenu

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

char getChoice(char* option)
{
displayMenu();
scanf("%c", &*option); FLUSH;
return toupper(*option);
} // ends getChoice function

Automobile** loadAutos(int* eSize, int* size)
{
FILE* file = fopen("autos.bin", "rb");
if (file == NULL)
{
printf("No previous saved data...\n");
return NULL;
}

fread(size, sizeof(int), 1, file);
fread(eSize, sizeof(int), 1, file);
// allocate memory for the array of pointers and the structs in a single step
Automobile** autos = calloc(*eSize, sizeof(Automobile*));
if (autos == NULL)
{
printf(&quot;Allocation of memory failed...\n&quot;);
exit(-1);
}
for (int i = 0; i &lt; *size; i++)
{
autos[i] = calloc(1, sizeof(Automobile));
if (autos[i] == NULL)
{
printf(&quot;Allocation of memory at autos[%i] failed...\n&quot;, i);
exit(-1);
}
}
// read the array of pointers and the structs from the file in a single step
for (int i = 0; i &lt; *eSize; i++)
{
if (fread(autos[i], sizeof(Automobile), 1, file) != 1)
{
printf(&quot;Failed to read data from file.\n&quot;);
exit(-1);
}
}
fclose(file);
printf(&quot;Previous saved data has been loaded into the inventory array!\n&quot;);
PAUSE;
return autos;

}

void myFlush()
{
while (getchar() != '\n');
} // ends myFlush function

void saveAutos(Automobile** autos, int eSize, int size)
{
FILE* file = fopen("autos.bin", "wb");
if (file == NULL)
{
printf("Failed to open file for writing.\n");
return;
}

fwrite(&amp;size, sizeof(int), 1, file);
fwrite(&amp;eSize, sizeof(int), 1, file);
// write the array of pointers and the structs to the file in a single step
for (int i = 0; i &lt; eSize; i++)
{
fwrite(autos[i], sizeof(Automobile), 1, file);
}
fclose(file);

} // ends saveAutos

void sortByCost(Automobile** autos, int eSize)
{
int temp = 0;
float 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 terms of cost: \n");
for (int l = 0; l < eSize; l++)
{
for (int k = 0; k < eSize; k++)
{
if (autoCost[l] == autos[k]->cost)
printf("$%.2f\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$%.2f\n", autos[i]->make, autos[i]->model, autos[i]->yearBuilt, autos[i]->cost);
}
} // end sortByMake


Thank you in advance :).
</details>
# 答案1
**得分**: 3
代码中混淆了变量 `size` 和 `eSize` 在 `loadAutos()` 函数中,这导致了指针数组的分配问题。
据我所知,`size` 是为存储汽车信息分配的容量,而 `eSize` 是实际使用的汽车槽的数量。
在二进制保存期间,首先写入的是 `size`(容量),然后是 `eSize`(已使用容量)。然后写入 `eSize` 个 `Automobile` 结构到文件中。
但在加载期间,两个大小都被读取,然后分配了一个包含 `eSize`(已使用容量)个指针的数组,然后为 `size`(容量)个指针分配了 `Automobile`。然后加载 `eSize`(已使用容量)个 `Automobile`。
所以在我们想象中运行这个代码,有3辆汽车在100个空间中:
- 我们保存了100个空间,只有3辆汽车在使用。
- 写入100
- 写入3
- 写入3个结构
- 在加载时,我们分配了一个包含3个汽车指针的数组,然后为它们分配了100辆汽车(比我们分配的多了97辆)
- 读取100
- 读取3
- 为3辆汽车分配指针
- 为100辆汽车分配结构
- 加载3个结构
在加载中,你在 `a` 数组的末尾进行了覆写,因为你混淆了 `eSize` 和 `size`。在堆上超出分配块的末尾写入数据会导致堆破坏。
使用简洁明了的变量名,而不是 `a`、`size`、`eSize`。应该使用 "size" 和 "eSize" 这样清晰的变量名来避免这个错误。
给变量取代表其含义的清晰而简洁的名称,比如 "autosCapacity" 和 "capacityUsed"。
如果这是一个作业,请确保添加注释,否则会被扣分。
<details>
<summary>英文:</summary>
The code is mixing up the variables `size` and `eSize` in `loadAutos()` during the allocation of the pointer-array.
As far as I can tell, `size` is the capacity allocated for storing car information, and `eSize` is how many of the automobile-slots are actually *used*. 
During the binary-save, the first integer written is `size` (capacity), then `eSize` (capacity-used).  Then `eSize` lots of `Automobile` structures are written to the file.
But during the load, the sizes are both read, and then an array of pointers `eSize` (capacity-used) is allocated, then for `size` (capacity) worth of pointers, an `Automobile` is allocated. Then `eSize` (capacity-used) lots of an `Automobile` loaded.
So running this this in our imaginations with 3 cars in 100 spaces:
- We save 100 spaces, being used only by 3 cars.
- write 100
- write 3
- write 3 structures
- On load, we allocate an array of 3 car pointers, then allocate 100 cars into them (97 **more than** what we allocated)
- read 100
- read 3
- allocate pointers for 3
- allocate structures for 100
- load 3 structures
You&#39;re overwriting the end of the `a` array in the load because you&#39;ve confused eSize and size.   Writing past the end of blocks allocated on the heap causes Heap Corruption.
Use clean and concise variable names, not `a`, `size`, `eSize`.  It&#39;s &quot;size&quot; and &quot;eSize&quot; that allowed you to make this bug.  
Name the variable what it represents, maybe something &quot;autosCapacity&quot; and &quot;capacityUsed&quot;.
If this is an assignment, make sure you add comments or you will be marked down.
</details>

huangapple
  • 本文由 发表于 2023年4月17日 10:03:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76031277.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定