Ive tried creating a dynamic database in which the user inputs the size of the database they want to create however im getting a memory leak after a certain amount of size inputs and im unsure what im doing incorrectly as im freeing everything as it should.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct _product_t
{
char *product;
float price;
} product_t;
product_t *newDatabase(product_t *database, int *dbSize, int newSize)
{
product_t *newdatabase = (product_t *)malloc(sizeof(*newdatabase) * newSize);
if (newSize < *dbSize)
{
for (int i = 0; i <= newSize; i++)
{
if (database[i].product != NULL)
{
free(database[i].product);
}
}
}
else
{
for (int i = 0; i <= *dbSize; i++)
{
if (database[i].product != NULL)
{
free(database[i].product);
}
}
}
for (int i = *dbSize; i < newSize; i++)
{
// newdatabase[i].product = (char*)malloc(sizeof(char)*100);
newdatabase[i].product = NULL;
newdatabase[i].price = -1;
}
*dbSize = newSize;
free(database);
return newdatabase;
}
int main(void)
{
product_t *database = NULL;
int dbSize = 0;
char cmd;
do
{
printf("Command?");
scanf(" %c", &cmd);
switch (cmd)
{
case 'q':
printf("Bye!");
break;
case 'n':
printf("Size? ");
int newSize2 = 0;
scanf("%d", &newSize2);
if (newSize2 < 0)
{
printf("Must be larger than 0");
break;
}
else
{
database = newDatabase(database, &dbSize, newSize2);
break;
}
default:
printf("Unkown command '%c'\n", cmd);
}
} while (cmd != 'q');
return 0;
}
#edit number 3
Ive opted on removing the malloc for the product pointer and decided to free all non NULL values with if and else statements
With the first malloc you allocate newSize pointers to product_t but you want to allocate an array of them instead:
product_t *newdatabase = malloc(newSize * sizeof *newdatabase);
You cannot deference the database pointer after you free it.
Why do you only free database[i].product for i >= newSize? Presumably you want to free all of them (but see realloc and code sample below).
Consider using realloc() to resize an array. If it was successful your old will be retained.
It's clumsy having client remember the previous database size, so consider creating a struct to old both the data and the size.
As you allocate fixed length string, it's easier to encode that in the type. Use constants (PRODUCT_LEN) instead of hard-coding magic values.
malloc() / realloc() of 0 bytes is implementation defined. My implementation returns a NULL so handling it as a special case.
malloc() does not guarantee initialized memory so either initialize it after or use calloc.
We don't cast void * (result from malloc) in C.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define PRODUCT_LEN 100
typedef struct {
size_t size;
char (*products)[PRODUCT_LEN];
float *prices;
} database;
database *newDatabase() {
return calloc(1, sizeof(database));
}
database *resizeDatabase(database *db, size_t newSize) {
if(!db) return NULL;
database tmp;
tmp.products = realloc(db->products, newSize * sizeof *db->products);
if(newSize && !tmp.products) {
printf("realloc of products failed\n");
// handle error
return NULL;
}
db->products = tmp.products;
tmp.prices = realloc(db->prices, newSize * sizeof *db->prices);
if(newSize && !tmp.prices) {
printf("realloc of prices failed\n");
// handle error; we successfully resize products but failed
// to resize price. So we may need to shrink products but
// what if that now fails?
return NULL;
}
db->prices = tmp.prices;
for(size_t i = db->size; i < newSize; i++) {
db->products[i][0] = '\0';
db->prices[i] = -1;
}
db->size = newSize;
return db;
}
void freeDatabase(database *db) {
if(!db) return;
free(db->products);
free(db->prices);
free(db);
}
int main(void) {
database *db = newDatabase();
size_t tests[] = { 0, 1, 2, 1, 0 };
size_t tests_len = sizeof tests / sizeof *tests;
for(size_t i = 0; i < tests_len; i++) {
database *newDb = resizeDatabase(db, tests[i]);
if(!newDb) {
printf("resizefailed %zu\n", tests[i]);
return 1;
}
db = newDb;
}
freeDatabase(db);
}
and here is the valgrind run:
==533946== HEAP SUMMARY:
==533946== in use at exit: 0 bytes in 0 blocks
==533946== total heap usage: 9 allocs, 9 frees, 440 bytes allocated
==533946==
==533946== All heap blocks were freed -- no leaks are possible
Newer version to compare to
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct _product_t {
char *product;
float price;
} product_t;
product_t *newDatabase(product_t *database, int *dbSize, int newSize) {
for (int i = 0; i < *dbSize; i++) {
if (database[i].product != NULL) {
free(database[i].product);
}
}
// Free the previous memory allocated for the database
// Free the previous memory allocated for the database
free(database);
// Allocate new space for newSize products on the heap
database = (product_t*) malloc(newSize * sizeof(product_t));
// Initialize all products in the database with NULL and -1
for (int i = 0; i < newSize; i++) {
database[i].product = NULL;
database[i].price = -1;
}
// Update the database size
*dbSize = newSize;
// Return the pointer to the new database
return database;
}
int main(void) {
product_t *database = NULL;
int dbSize = 0;
char cmd;
do{
printf("Command?");
scanf(" %c", &cmd);
switch (cmd) {
case 'q':
printf("Bye!");
break;
case 'n':
printf("Size? ");
int newSize2 = 0;
scanf("%d", &newSize2);
if(newSize2 < 0) {
printf("Must be larger than 0");
break;
}
else{
database = newDatabase(database, &dbSize, newSize2);
break;
}
default:
printf("Unkown command '%c'\n",cmd);
}
}while(cmd != 'q');
return 0;
}
Related
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.
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).
I am currently taking a procedural programming course at my school. We are using C with C99 standard. I discussed this with my instructor and I cannot understand why realloc() is working for his machine, but it is not working for mine.
The goal of this program is to parse a text file students.txt that has students' name and their GPA formatted like this:
Mary 4.0
Jack 2.45
John 3.9
Jane 3.8
Mike 3.125
I have a function that resizes my dynamically allocated array, and when I use realloc the debugger in my CLion IDE, it gave me SIGABRT.
I tried using an online compiler and I get realloc(): invalid next size.
I have been trying to debug this all weekend and I can't find the answer and I need help.
My code is currently looking like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INITIAL_SIZE 4
#define BUFFER_SIZE 512
#define GRADE_CUTOFF 3.9
// ERROR CODES
#define FILE_OPEN_ERROR 1
#define MEMORY_ALLOCATION_ERROR 2
struct student {
double gpa;
char *name;
};
struct student *resizeAllocationIfNeeded(struct student *listOfStudents,
unsigned int studentCount, size_t *currentSize) {
if (studentCount <= *currentSize) {
return listOfStudents;
}
*currentSize *= 2;
struct student *resizedList = (struct student *) realloc(listOfStudents, *currentSize * sizeof(struct student));
if (resizedList == NULL) {
perror("Failed to allocate memory");
exit(MEMORY_ALLOCATION_ERROR);
}
return resizedList;
}
size_t getNamesAndGrades(FILE *file, struct student *listOfStudents, size_t size) {
unsigned int studentCount = 0;
char buffer[BUFFER_SIZE];
while(fscanf(file, "%s %lf", buffer, &listOfStudents[studentCount].gpa) > 0) {
listOfStudents[studentCount].name = strdup(buffer);
studentCount++;
listOfStudents = resizeAllocationIfNeeded(listOfStudents, studentCount, &size);
}
return studentCount;
}
void swapStudents(struct student *listOfStudents, int x, int y) {
struct student temp = listOfStudents[x];
listOfStudents[x] = listOfStudents[y];
listOfStudents[y] = temp;
}
void sortStudentsByGPA(struct student *listOfStudents, unsigned int studentCount) {
for (int i = 0; i < studentCount; i++) {
for (int j = 0; j < studentCount - i - 1; j++) {
if (listOfStudents[j].gpa < listOfStudents[j + 1].gpa) {
swapStudents(listOfStudents, j, j + 1);
}
}
}
}
void printStudentAndGPA(struct student *listOfStudents, unsigned int studentCount) {
for (int i = 0; i < studentCount; i++) {
if (listOfStudents[i].gpa > GRADE_CUTOFF) {
printf("%s %lf\n", listOfStudents[i].name, listOfStudents[i].gpa);
}
free(listOfStudents[i].name);
}
}
void topStudents(char *fileName) {
FILE *file = fopen(fileName, "r");
if (!file) {
perror("Could not open file for reading");
exit(FILE_OPEN_ERROR);
}
struct student *listOfStudents = (struct student *) malloc(INITIAL_SIZE * sizeof(struct student));
if (listOfStudents == NULL) {
perror("Failed to allocate memory");
exit(MEMORY_ALLOCATION_ERROR);
}
unsigned int studentCount = getNamesAndGrades(file, listOfStudents, INITIAL_SIZE);
sortStudentsByGPA(listOfStudents, studentCount);
printStudentAndGPA(listOfStudents, studentCount);
free(listOfStudents);
}
int main() {
topStudents("students.txt");
return 0;
}
You have a fencepost error when checking whether you need to resize the array.
Your initial allocation size is 4, which means that the highest valid index is 3.
In the loop in getNamesAndGrades(), after you read into listOfStudents[3] you increment studentCount to 4. Then you call resizeAllocationIfNeeded(listOfStudents, studentCount, &size);
Inside resizeAllocationIfNeeded(), studentCount == 4 and *currentSize == 4. So the test
if (studentCount <= *currentSize) {
return listOfStudents;
}
succeeds and you return without calling realloc().
Then the next iteration of the loop assigns to listOfStudents[4], which causes a buffer overflow.
You need to change that condition to studentCount < *currentSize.
There are two errors in your code: one is just a typo, the other is a more serious logical error.
First, you are reallocating too late, because of the condition in resizeAllocationIfNeeded(). When studentCount == currentSize, this doesn't resize (even though it should), which makes you overflow the array of students and causes problems.
You can change the condition to fix this:
if (studentCount < *currentSize) {
return listOfStudents;
}
Apart from the above, your main error is in getNamesAndGrades(), where you are reallocating memory and assigning the new pointers to a local variable. You then use that variable in topStudents() as if it was updated. This will of course not work, as the initial pointer passed by topStudents() becomes invalid after the first realloc() and memory is irrevocably lost when getNamesAndGrades() returns.
You should either pass a pointer to the student array, or better just make the function create the array for you.
Here's a solution, renaming getNamesAndGrades to getStudents:
struct student *getStudents(FILE *file, unsigned int *studentCount) {
char buffer[BUFFER_SIZE];
struct student *listOfStudents;
size_t size = INITIAL_SIZE;
*studentCount = 0;
listOfStudents = malloc(size * sizeof(struct student));
if (listOfStudents == NULL) {
perror("Failed to allocate memory");
exit(MEMORY_ALLOCATION_ERROR);
}
while(fscanf(file, "%511s %lf", buffer, &listOfStudents[*studentCount].gpa) == 2) {
listOfStudents[*studentCount].name = strdup(buffer);
(*studentCount)++;
listOfStudents = resizeAllocationIfNeeded(listOfStudents, *studentCount, &size);
}
return listOfStudents;
}
// ...
void topStudents(char *fileName) {
FILE *file = fopen(fileName, "r");
if (!file) {
perror("Could not open file for reading");
exit(FILE_OPEN_ERROR);
}
unsigned int studentCount;
struct student *listOfStudents = getStudents(file, &studentCount);
sortStudentsByGPA(listOfStudents, studentCount);
printStudentAndGPA(listOfStudents, studentCount);
free(listOfStudents);
}
int main() {
topStudents("students.txt");
return 0;
}
Additional notes:
When scanning on a fixed size buffer (in this case 512 bytes), use %511s, not just %s, that's a buffer overflow waiting to happen.
You are scanning two fields, so check if fscanf's return value is == 2, not > 0, you don't want for example one field initialized and one not.
Don't cast the result of malloc() or realloc()
For the future, if you are on Linux, compiling with gcc -g -fsanitize=address will give you detailed error reports when something goes bad in the heap, telling you exactly where memory was allocated, freed and used.
So, I have an array of a structures called vitorias (in English, "victories"), an array of structures and an array of that structure and an array of strings.
Structure and arrays:
char **sistema_eq;
typedef struct
{
int id;
char nome[MAX_CHARS];
int vit;
} vitorias;
The problem is that when I use cppcheck it gives an error saying:
(error) Common realloc mistake: 'conj_vit' nulled but not freed upon failure
(error) Common realloc mistake: 'sistema_eq' nulled but not freed upon failure
(error) Common realloc mistake: 'conj_jogos' nulled but not freed upon failure
And, if I use Valgrind, it says that I did 10 allocs and 2 free, but I don't understand what's wrong, because I freed everything in the end I think.
Program:
#include<stdlib.h>
#include<stdio.h>
#include <string.h>
#define MAX_CHARS 1024 /* max characters of a word */
#define MAX_SIZE 5
static int size_until = 0; /*conts the size of sistema_eq and conj_vit*/
static int line = 1; /* counts the number of lines of the stdin */
int ident = 0; /*conts the id of jogos*/
static int size_until = 0; /*counts the size of sistema_eq*/
static int size_until2 = 0;/*counts the size of conj_jogos*/
void a(char nome_jg[],char team1[],char team2[],int score1,int score2);
void A(char nome[]);
char **sistema_eq;
jogo *conj_jogos;
vitorias *conj_vit;
int main()
{
char c;
char nome_jg[MAX_CHARS], team1[MAX_CHARS], team2[MAX_CHARS];
int score1;
int score2;
int i;
conj_jogos = (jogo*)calloc(MAX_SIZE,sizeof(jogo));
memset(conj_jogos,0, MAX_SIZE*sizeof(jogo));
conj_vit = (vitorias*)calloc(MAX_SIZE,sizeof(vitorias));
memset(conj_vit,0, MAX_SIZE*sizeof(vitorias));
sistema_eq = (char**)calloc(MAX_SIZE,sizeof(*sistema_eq));
memset(sistema_eq,0, MAX_SIZE*sizeof(*sistema_eq));
for(i=0;i<MAX_SIZE;i++)
{
sistema_eq[i] = (char*)calloc(1024,sizeof(char));
memset(sistema_eq[i],0, sizeof(char)*1024);
}
while ((c = getchar())!= 'x') {
switch (c)
{
case 'A':
{
scanf("%1023[^:\n]",nome_jg);
remove_esp(nome_jg);
A(nome_jg);
break;
}
case 'a':
{
scanf("%1023[^:\n]:%1023[^:\n]:%1023[^:\n]:%d:%d",nome_jg,team1,team2,&score1,&score2);
remove_esp(nome_jg);
a(nome_jg,team1,team2,score1,score2);
line++;
break;
}
}
}
free(conj_vit);
free(conj_jogos);
free(sistema_eq);
return 0;
}
/*This functions adds a victory and a equipa (team in english) into the corresponding arrays and updates the vitories of each team*/
//Example in El Classico Barcelona vs Real Madrid 1:0, which means Barcelona won
void A(char nome[])
{
if (nome_in_sis(nome) == 1)
{
printf("%d Equipa existente.\n",line);
line++;
}
else
{
if (size_until < MAX_SIZE)
{
strcpy(sistema_eq[size_until],nome);
strcpy(conj_vit[size_until].nome,nome);
conj_vit[size_until].id = size_until;
size_until++;
line++;
}
else
{
conj_vit = realloc(conj_vit,sizeof(vitorias)*(size_until+1));
sistema_eq = realloc(sistema_eq,sizeof(char*)*(size_until+1));
sistema_eq[size_until] = calloc(1024,sizeof(char*));
strcpy(sistema_eq[size_until],nome);
strcpy(conj_vit[size_until].nome,nome);
conj_vit[size_until].id = size_until;
size_until++;
line++;
}
}
}
/*This functions adds a jogo (game in english) and a equipa (team in english) into the array conj_jogos (the array of jogos)*/
void a(char nome_jg[],char team1[],char team2[],int score1,int score2)
{
int vit;
if (jogo_in(nome_jg) == 1)
{
printf("%d Jogo existente.\n",line);
line++;
}
else if ((nome_in_sis(team1) == 0) || (nome_in_sis(team2) == 0))
{
printf("%d Equipa inexistente.\n",line);
line++;
}
else
{
if (size_until2 < MAX_SIZE)
{
conj_jogos[size_until2] = cria_jogo(nome_jg,team1,team2,score1,score2);
if (score1 > score2)
{
vit = procura_vit(team1);
conj_vit[vit].vit++;
}
else
{
vit = procura_vit(team2);
conj_vit[vit].vit++;
}
size_until2++;
}
else
{
size_until2++;
conj_jogos = realloc(conj_jogos,sizeof(jogo)*(size_until2+1));
conj_jogos[size_until2] = cria_jogo(nome_jg,team1,team2,score1,score2);
if (score1 > score2)
{
vit = procura_vit(team1);
conj_vit[vit].vit++;
}
else
{
vit = procura_vit(team2);
conj_vit[vit].vit++;
}
size_until2++;
}
}
}
Sorry if the code looks messy and thanks for the help.
As pointed out in the comments, you never free the data you allocated with calloc in the for loop. Add this loop (or something very similar) near the end of your main:
//...
for(i=0;i<MAX_SIZE;i++) free(sistema_eq[i]); // MUST be before the next line!
free(sistema_eq);
//...
Also, as you use calloc, you don't need any of the memset calls! From the linked documentation for void* calloc( size_t num, size_t size ):
Allocates memory for an array of num objects of size and initializes
all bytes in the allocated storage to zero.
For the 'errors' reported concerning realloc: in cases where a call to realloc fails, the code you use will prevent subsequent freeing of the original data (the address of which was in the pointer), as its address will be replaced with NULL on such a failure! To prevent this, use a temporary pointer, like this:
jogo* temp_jogo = realloc(conj_jogos,sizeof(jogo)*(size_until2+1));
if (temp_jogo != NULL) conj_jogos = temp_jogo;
else {
// In case of failure, we now still have the original conj_jogos
// pointer, which we can then pass to "free" at some point, presumably
// after we've signalled and/or handled the allocation error.
}
Finally (I think), you may like to read this: Do I cast the result of malloc? - which is equally valid for calls to calloc and realloc.
I created hash table to insert my values . But when I insert more than one value I got same values inside all fields . my code is here :
create a structure for both user and hashtable
struct UserNode
{
char *username;
char *password;
};
struct HashTable
{
int size;
struct UserNode *table;
};
// initialize the hash table as NULL
struct HashTable* initializeTable(int size)
{
struct HashTable *htable;
int i = 0;
if (size < MIN_TABLE_SIZE)
{
printf("Table Size Too Small\n");
return NULL;
}
htable = malloc(sizeof(struct HashTable));
if (htable == NULL)
{
printf("Out of Space\n");
return NULL;
}
htable->size = size;
htable->table = malloc(size * sizeof(struct UserNode));
if (htable->table == NULL)
{
printf("Table Size Too Small\n");
return NULL;
}
for (i = 0; i < htable->size; i++)
{
htable->table[i].username= malloc(20 * sizeof(char));
htable->table[i].password = malloc(20 * sizeof(char));
htable->table[i].username=NULL;
htable->table[i].password=NULL;
}
printf("Hsh table sucessfully created\n");
return htable;
}
insert each user name to hash table
int Insert(char *key,char *password,struct HashTable *htable)
{
int pos = 0;
pos = Find(key,htable);
printf("the value of key : %d\n",pos);
if ((htable)->table[pos].username == NULL)
{
(htable)->table[pos].username,key ;
(htable)->table[pos].password = password;
}
else
{
printf("Duplicate element ..\n");
}
return 0;
}
This function to display the hash table
void Retrieve(struct HashTable *htable)
{
int i=0;
for (i = 0; i < htable->size; i++)
{
if (htable->table[i].username == NULL)
printf("Position: %d \tusername : NULL\tpassword: NULL\n",i + 1);
else
printf("Position: %d \t username: %s\tpassword: %s\n",i + 1,htable->table[i].username,htable->table[i].password);
}
}
and I am calling these function from main function as :
............main codes............
...............................
case 1:
printf("Enter size of the Hash Table:\n");
scanf("%d",&size);
htable = initializeTable(size);
break;
case 2:
if (i > htable->size)
{
printf("Table is Full, Rehash the table\n");
continue;
}
printf("Enter the username:\n");
scanf("%s",&username);
printf("Ebter the password:\n");
scanf("%s",&password);
Insert(username,password,htable);
i++;
break;
case 3:
printf("Display\n");
Retrieve(htable);
break;
But when I insert more username and password inside structures via insert function , I got same values in both fields . that is the new one is overwrite the previous one and display both value as new username . why ? an problem on my code ?
Two things:
You have the code:
htable->table[i].username= malloc(20 * sizeof(char));
htable->table[i].password = malloc(20 * sizeof(char));
htable->table[i].username=NULL;
htable->table[i].password=NULL;
First you allocate memory, then you immediately overwrite the pointers with NULL making you loose the memory you just allocated, leading to a leak and possible undefined behavior (and probable crashes) if you use the pointers without checking for NULL.
If you are going to allocate fixed sizes for the username and password members of the UserNode structure, why not make them arrays? Like
struct UserNode
{
char username[20];
char password[20];
};
This will, incidentally, also solve the first problem since you no longer need to allocate memory. It will also lessen memory fragmentation.
In Insert(),
if ((htable)->table[pos].username == NULL)
{
(htable)->table[pos].username,key ;
(htable)->table[pos].password = password;
The (htable)->table[pos].username,key; line just did nothing. Also, strings should be copied through strcpy() or strncpy(), not through pointer assignment.
So it should be:
if (htable->table[pos].username == NULL)
{
htable->table[pos].username = malloc(strlen(key) + 1);
strcpy(htable->table[pos].username, key);
htable->table[pos].password = malloc(strlen(password) + 1);
strcpy(htable->table[pos].password, password);
}
I'm creating a double pointer and sending in the address to allocate memory, which requires a triple pointer. Also, i am creating single pointers (goals and assists) and sending their addresses to allocate memory, which requires double pointers. I think the problem lies in allocation of memory, but i cant figure it out. I keep seg faulting whenever i run the readLinesFromFile function. It does not segfault when I try running allocateMemory function by itself. The problem could also be in the readLinesFromFile function
int main (int argc, char **argv)
{
int numPlayers = 0;
if (argc != 3)
{
printf("Missing text file");
return 0;
}
char **playerNames;
int *goals, *assists;
FILE *filePtr = fopen(argv[1],"r");
if(filePtr == NULL)
{
printf("\nFile is empty");
return 0;
}
numPlayers = countLinesInFile(filePtr);
allocateMemory(&goals,&assists,&playerNames,numPlayers);
readLinesFromFile(filePtr,goals,assists,playerNames,numPlayers);
}
void allocateMemory(int **goals, int **assists, char *** names, int size)
{
int i = 0;
*goals = malloc(MAX_NAME * sizeof(int));
*assists = malloc(MAX_NAME * sizeof(int));
*names = malloc(MAX_NAME * sizeof(char*));
for (i = 0; i < size; i++)
{
(names[i]) = malloc(MAX_NAME * sizeof(char*));
}
}
void readLinesFromFile(FILE *fptr, int *goals, int *assists, char **names, int numLines)
{
int i = 0, j = 0, x = 0;
char players[MAX_LINE];
char *tokenPtr;
fptr = fopen(INPUT,"r");
for(i = 0; i < numLines; i++)
{
fgets(players,MAX_LINE, fptr);
tokenPtr = strtok(players," ");
strcpy((*(names+i)), tokenPtr);
while (tokenPtr != NULL)
{
tokenPtr = strtok(NULL," ");
if (x = 0)
{
goals[i] = atoi(tokenPtr);
x = 1;
}
else
{
assists[i] = atoi(tokenPtr);
x = 0;
}
}
}
}
Assuming MAX_NAME is the maximum length of a player's name, this should work:
void AllocateMemory(char *** pppNames, int ** ppGoals, int ** ppAssists, size_t sizePlayersMax)
{
*pppNames = malloc(sizePlayersMax * sizeof **pppNames);
*ppGoals = malloc(sizePlayersMax * sizeof **ppGoals);9
*ppAssists = malloc(sizePlayersMax * sizeof **ppAssists);
{
size_t sizePlayersCount = 0;0
for (; sizePlayersCount < sizePlayersMax; ++sizePlayersCount)
{
(*pppNames)[sizePlayersCount] = calloc(MAX_NAME + 1, sizeof *((*pppNames)[sizePlayersCount]));
}
}
}
To prevent the app from overwriting memory in case of really long player names you might like to change this line:
strcpy((*(names+i)), tokenPtr);
to become:
if (tokenPtr)
strncpy((*(names+i)), tokenPtr, MAX_NAME);
This would truncate the player names stored to a maximum of MAX_NAME characters. The latter is the size AllocateMemory() use minus 1. This one spare character is needed for the 0/NUL to terminate the character-array so it could be used as a "string".
Finally also this is dangerous:
while (tokenPtr != NULL)
{
tokenPtr = strtok(NULL," ");
if (x = 0)
{
Better do like this:
while (NULL != (tokenPtr = strtok(NULL," ")))
{
if (x = 0)
{