C: Where should I free my pointers? - c

I'm a student and I'm trying to complete a task in C right now.
I've written an algorithm, which works fine so far. It gets a file to detect if the included logical expression is satisfiable (SAT-Solver). The problem is, that I get a Segementation Fault after a while, when I'm trying to use it with bigger files (about 60MB). I think it is, because I use malloc a couple times, but I don't free that memory yet, because I don't know where to put the free() expresseions.
There's one method, which calls itself twice everytime. The code looks like this:
int DPLL (int *pointer, int variablen, int anzahlklauseln)
{
int newliteral;
int neueklauseln;
int *neuphi;
int *neuphi2;
int *unitclauses;
int *pureliterals;
int offsetzaehler;
int rek1, rek2;
klauseln = anzahlklauseln;
unitclauses = (int *) malloc(klauseln * sizeof(int));
pureliterals = (int *) malloc(variablen * sizeof(int));
if (isEmpty())
{
return 1;
}
if (ContainsEmptyClause(pointer, variablen))
{
return 0;
}
unitClauses(pointer, variablen, unitclauses);
if (unsatisfiable)
{
unsatisfiable = 0;
return 0;
}
int iunitclauses = 0;
while (unitclauses[iunitclauses] != 0)
{
unitPropagate(pointer, variablen, unitclauses[iunitclauses++]);
}
if (quicksati(pointer, variablen))
{
return 1;
}
pureLiterals(pointer, variablen, pureliterals);
int ipureliterals = 0;
while (pureliterals[ipureliterals] != 0)
{
pureLiteralAssign(pointer, variablen, pureliterals[ipureliterals++]);
}
if (quicksati(pointer, variablen))
{
return 1;
}
newliteral = chooseliteral(pointer, variablen);
neuphi = (int*) malloc(variablen * (klauseln + 1) * sizeof(int));
neuphi2 = (int*) malloc(variablen * (klauseln + 1) * sizeof(int));
int *hilfspointer = pointer;
offsetzaehler = 0;
for (int i = 0; i < (klauseln +1); ++i)
{
for (int j = 0; j < variablen; ++j)
{
if (i == klauseln)
{
neuphi[offsetzaehler] = 0;
neuphi2[offsetzaehler] = 0;
}
else
{
neuphi[offsetzaehler] = *hilfspointer;
neuphi2[offsetzaehler++] = *hilfspointer++;
}
}
}
neueklauseln = klauseln + 1;
addClause(neuphi, variablen, newliteral);
addClause(neuphi2, variablen, (-newliteral));
if (DPLL(neuphi, variablen, neueklauseln))
{
return 1;
}
else
{
return DPLL(neuphi2, variablen, neueklauseln);
}
}
Now I thought I should edit the last lines like this:
rek1 = DPLL(neuphi, variablen, neueklauseln);
rek2 = DPLL(neuphi2, variablen, neueklauseln);
free(neuphi);
free(neuphi2);
free(unitclauses);
free(pureliterals);
return rek1 || rek2;
But then I'll get segmentation fault errors for files, which worked before.
Then I tried it like this:
if (DPLL(neuphi, variablen, neueklauseln))
{
return 1;
}
else
{
free(neuphi);
free(unitclauses);
free(pureliterals);
rek1 = DPLL(neuphi2, variablen, neueklauseln);
free(neuphi2);
return rek1;
}
But then I'd get even more Segmentation Faults.
So any C experts here, who'd like to help me? Thanks alot! :)

Your recursion doesn't have an exit condition, so the program will encounter segmentation fault when it hits stack overflow or when your malloc call returns null pointer as consequence of running out of heap memory, whatever happens first.

Related

Program crashes when using free() on an array of structure that was created by calloc

I have this function which is using calloc to create an array of structure proposition. Whenever I try to free the resulting array from another fuction, it crashes.
proposition* get_matching_propositions(char *pcde, proposition *propositions, int *match_count)
{
proposition *matches;
int count = get_count_from_stream(ptf_proposition, sizeof(proposition)),
cptr_match = 0;
for (int i = 0; i < count; i++)
{
if (strcmp(propositions[i].cde, pcde) == NULL)
{
cptr_match++;
}
}
matches = (proposition*) calloc (cptr_match, sizeof(propositions));
assert(matches != NULL);
cptr_match = 0;
for (int i = 0; i < count; i++)
{
if (strcmp(propositions[i].cde, pcde) == NULL)
{
matches[cptr_match] = propositions[i];
cptr_match++;
}
}
*match_count = cptr_match;
return matches;
}
Inside some other function I have:
proposition *matches =
get_matching_propositions(current_question.cde, propositions, &match_count);
free(matches);
Then the program crashes with this message :
Process returned -1073740940 (0xC0000374) execution time : 1.370 s.

Why does this introduce a memory leak?

I am implementing an Ant Colony Optimization for the Set Covering Problem in C. In my code, I have found a function that causes a memory leak. I am pretty sure this function is the cause of the memory leak, since I have ruled out other functions by testing. Only, I don't understand why this function introduces a memory leak.
To understand this function, I'll describe the Ant struct first. The Ant struct looks like this:
struct Ant {
int* x;
int* y;
int fx;
int** col_cover;
int* ncol_cover;
int un_rows;
double* pheromone;
}
typedef struct Ant ant_t;
The pointers in this struct (such as x, y, col_cover, etc.) are initialized using malloc and freed at the end of the program. Now, the function causing the memory leak is the following:
void localSearch(ant_t* ant) {
int improvement = 1;
ant_t* antcpy = (ant_t*) malloc(sizeof(ant_t));
initAnt(antcpy);
copyAnt(ant, antcpy);
while (improvement) {
improvement = 0;
for (int i = 0; i < inst->n; i++) {
if (antcpy->x[i]) {
removeSet(inst, antcpy, i);
while (!isSolution(antcpy)) {
constructSolution(antcpy);
}
if (antcpy->fx < ant->fx) {
copyAnt(antcpy, ant);
improvement = 1;
eliminate(ant);
} else {
copyAnt(ant, antcpy);
}
}
}
}
free((void*) antcpy);
}
First, I create another instance of the Ant struct (antcpy), using the initAnt function. The copyAnt function does a deep copy of one Ant struct to another Ant struct. My reason for doing a deep copy is the following; I am changing the antcpy and then comparing it to ant. If it turns out better (antcpy->fx < ant->fx), ant is replaced by antcpy. If it turns out worse, antcpy is restored to the values of ant.
These functions are given below:
void initAnt(ant_t* ant) {
ant->x = (int*) malloc(inst->n * sizeof(int));
ant->y = (int*) malloc(inst->m * sizeof(int));
ant->col_cover = (int**) malloc(inst->m * sizeof(int*));
ant->ncol_cover = (int*) malloc(inst->m * sizeof(int));
ant->pheromone = (double*) malloc(inst->n * sizeof(double));
for (int i = 0; i < inst->m; i++) {
ant->col_cover[i] = (int*) malloc(inst->ncol[i] * sizeof(int));
}
}
void copyAnt(ant_t* from, ant_t* to) {
to->fx = from->fx;
to->un_rows = from->un_rows;
for (int i = 0; i < inst->n; i++) {
to->x[i] = from->x[i];
to->pheromone[i] = from->pheromone[i];
}
for (int i = 0; i < inst->m; i++) {
to->y[i] = from->y[i];
to->ncol_cover[i] = from->ncol_cover[i];
for (int j = 0; j < inst->ncol[i]; j++) {
to->col_cover[i][j] = from->col_cover[i][j];
}
}
}
I don't really see why this code causes a memory leak, since I free antcpy at the end of the localSearch function. So, why does this code introduce a memory leak and how can I fix it?
You will have to implement a function freeAnt that before free((void*) antcpy); will release all memory that was allocated in initAnt.
void freeAnt(ant_t* ant) {
for (int i = 0; i < inst->m; i++) {
free(ant->col_cover[i]);
}
free(ant->pheromone);
free(ant->ncol_cover);
free(ant->col_cover);
free(ant->y);
free(ant->x);
}

Connect-N Board Game, crashing when Width is >> Height

I'm in the process of coding a Connect-N board game, and I'm almost finished and have gone through troubleshooting. My problem is now after changing some stuff my game crashes when the computer plays its move if the Width is too much greater than the height. There are two functions involved here, so I will paste them both.
Board
*AllocateBoard(int columns, int rows)
{
int **array= malloc(sizeof(int *) *columns);
int r = 0;
for ( r = 0; r < columns; ++r)
{
array[r] = malloc(sizeof(int) * rows);
}
int j = columns - 1;
int k = rows - 1;
int m = 0;
int n = 0;
for ( m = 0; m < j; ++m)
{
for ( n = 0; n < k; ++n)
{
array[m][n] = 0;
}
}
Board *board = malloc(sizeof(Board));
board->columns = columns;
board->rows = rows;
board->spaces = array;
return board;
}
This first function allocates the board to be a matrix Width * Height that the user passes in via the command line. It then initializes every space on the board to be zero, and then stores the columns, rows, and spaces into a Board structure that I've created. It then returns the board.
int
computerMakeMove(Board *board)
{ int RandIndex = 0;
int **spaces = board->spaces;
int columns = board->columns;
int *arrayoflegalmoves = malloc(sizeof(int) * (columns));
int columncheck = 0;
int legalmoveindex = 0;
while (columncheck <= columns - 1)
{
if (spaces[columncheck][0] == 0)
{
arrayoflegalmoves[legalmoveindex] = columncheck;
++legalmoveindex;
++columncheck;
}
else
{
++columncheck;
}
arrayoflegalmoves = realloc(arrayoflegalmoves, (legalmoveindex) * sizeof(int));
}
if (legalmoveindex == 1)
{
return arrayoflegalmoves[0];
}
else
{
RandIndex = rand() % (legalmoveindex);
return arrayoflegalmoves[RandIndex];
}
}
This second function is designed to make the computer randomly pick a column on the board. It does this by checking the value of the top row in each column. If there is a zero there, it will store this value in an array of legal moves, and then it increments the legalmoveindex. If there isn't, it skips the column and checks the next. It ends when it gets finished checking the final column. If there is only one legal move, it will play it. If there are more, it will select a random index from the array of legal moves (I run srand in the main) and then return that value. It will only ever attempt to play on a legal board, so that's not the problem. I am pretty confident the problem occurs in this function, however, as I call the functions as follows
printf("Taking the computers move.\n");
{printf("Taking computer's move.");
computermove = computerMakeMove(playerboard);
printf("Computer's move successfully taken.\n");
playerboard = MakeMove(playerboard, computermove, player);
printf("Computer's board piece successfully played.\n");
system("clear");
displayBoard(playerboard);
...;
}
and it prints
Aborted (core dumped)
immediately after it prints
"Taking computer's move."
Once again, my question is: why is my program crashing if the width is larger than the height when the computer plays?
Thanks.
Edit: I found the solution and I am stupid.
I realloc'd during the while loop.
The realloc should be the first thing outside of the while loop.
The answer for any future programmers who may have this problem:
Notice the
while (columncheck <= columns - 1)
{
if (spaces[columncheck][0] == 0)
{
arrayoflegalmoves[legalmoveindex] = columncheck;
++legalmoveindex;
++columncheck;
}
else
{
++columncheck;
}
arrayoflegalmoves = realloc(arrayoflegalmoves, (legalmoveindex) * sizeof(int));
}
has a realloc inside of it. The realloc should be moved to immediately outside of it, like so
while (columncheck <= columns - 1)
{
if (spaces[columncheck][0] == 0)
{
arrayoflegalmoves[legalmoveindex] = columncheck;
++legalmoveindex;
++columncheck;
}
else
{
++columncheck;
}
}
arrayoflegalmoves = realloc(arrayoflegalmoves, (legalmoveindex) * sizeof(int));
it is unusual to have the columns be the first index in an array.
having the first index of an array be columns leads to confusion
// suggest using camel case for all variable names, for readability
Board *AllocateBoard(int columns, int rows)
{
int **array= malloc(sizeof(int *) *columns); // add check that malloc successful
int r = 0;
for ( r = 0; r < columns; ++r)
{
array[r] = malloc(sizeof(int) * rows); // <-- add: check that malloc successful
}
int j = columns - 1; // this results in last column not initialized
int k = rows - 1; // this results in last row of each column not initialized
int m = 0; // column loop counter
int n = 0; // row loop counter
for ( m = 0; m < j; ++m)
{
for ( n = 0; n < k; ++n)
{
array[m][n] = 0;
}
}
Board *board = malloc(sizeof(Board)); // <-- add: check if malloc successful
board->columns = columns;
board->rows = rows;
board->spaces = array;
return board;
} // end function: AllocateBoard
// why is this only looking at the first row of each column?
int computerMakeMove(Board *board)
{
int RandIndex = 0;
int **spaces = board->spaces;
int columns = board->columns;
int *arrayoflegalmoves = malloc(sizeof(int) * (columns)); // <-- add check that malloc successful
int columncheck = 0;
int legalmoveindex = 0;
while (columncheck <= columns - 1)// should be: for(; columncheck < columns; columncheck++ )
{
if (spaces[columncheck][0] == 0)
{ // then first row of column is zero
arrayoflegalmoves[legalmoveindex] = columncheck;
++legalmoveindex;
++columncheck; // <-- remove this line
}
else // remove this 'else' code block
{
++columncheck;
} // end if
arrayoflegalmoves = realloc(arrayoflegalmoves, (legalmoveindex) * sizeof(int));
// <-- 1) use temp int*, in case realloc fails
// <-- 2) if realloc successful, update arrayoflegalmoves
// <-- 3) the code is not checking each row of each column,
// so the original malloc is more than plenty
// so why bother to realloc
// <-- 4) if legalmoveindex is 0 then realloc returns NULL
} // end while
// in following, what about when zero moves found? probably should return NULL
if (legalmoveindex == 1)
{ // only one column[row0] found to contain 0
return arrayoflegalmoves[0];
}
else
{
RandIndex = rand() % (legalmoveindex);
return arrayoflegalmoves[RandIndex]; // if zero moves found, this returns a
// de-reference to address 0
// which would result in a seg fault event
} // end if
} // end function: computerMakeMove

Initializing Strings in an Array of Sturts within a Struct

I have a struct gradebook with(among other things) an array of student structs that has two string fields
#define MAX_NAME_LEN 50
#define MAX_EMAIL_LEN 80
#define MAX_NUMBER_OF_STUDENTS 200
#define MAX_NUMBER_OF_ASSIGNMENTS 100
typedef struct students {
char *name;
char *email;
} Students;
typedef struct gradebook {
int number_of_students;
Students students[MAX_NUMBER_OF_STUDENTS];
int number_of_assignments;
char assignments[MAX_NUMBER_OF_ASSIGNMENTS][(MAX_NAME_LEN + 1)];
int scores[MAX_NUMBER_OF_STUDENTS][MAX_NUMBER_OF_ASSIGNMENTS];
} Gradebook;
I have an initialization function
int init_gradebook(Gradebook *book) {
int row, col, ndx, count;
book->number_of_students = 0;
count += book->number_of_students;
for(ndx = 0; ndx < MAX_NUMBER_OF_STUDENTS; ndx++) {
book->students[ndx].name = 0;
book->students[ndx].email = 0;
}
book->number_of_assignments = 0;
count += book->number_of_assignments;
for(row = 0; row < MAX_NUMBER_OF_ASSIGNMENTS; row++) {
for(col = 0; col < (MAX_NAME_LEN + 1); col++) {
book->assignments[row][col] = 0;
count += book->assignments[row][col];
}
}
for(row = 0; row < MAX_NUMBER_OF_STUDENTS; row++) {
for(col = 0; col < MAX_NUMBER_OF_ASSIGNMENTS; col++) {
book->scores[row][col] = 0;
count += book->scores[row][col];
}
}
if (count == 0) {
return 1;
} else {
return 0;
}
}
and I need to then insert, into those two string fields, the passed in strings, with my add_student function.
int add_student(Gradebook *book, char *nom, char *mail) {
int ndx, count;
if (book->number_of_students == 0) {
book->students[(book->number_of_students)].name = malloc(sizeof(51));
book->students[(book->number_of_students)].email = malloc(sizeof(81));
strcpy(book->students[(book->number_of_students)].name, nom);
strcpy(book->students[(book->number_of_students)].email, mail);
book->number_of_students++;
} else {
for (ndx = 0; ndx < book->number_of_students; ndx++) {
book->students[(book->number_of_students)].name = malloc(sizeof(51));
book->students[(book->number_of_students)].email = malloc(sizeof(81));
strcpy(book->students[(book->number_of_students)].name, nom);
strcpy(book->students[(book->number_of_students)].email, mail);
book->number_of_students++;
}
}
return 1;
}
My code compiles, but when I run it with the main function, I get a seg fault. The add_student function is what I am ultimately trying to do (copy the given string into book->student[ndx].name) If you need to see the main file or the gradebook.h file, let me know.
Edit: Thanks to all of you, this issue has been solved. The main problem, as abginfo pointed out, was my If Else + the For loop inside of it. But now I have other problems further along in my program. Haha, Thank You.
From what portion of your code I can see, I'm going to make the assumption that the init_gradebook function takes a non allocated reference to gradebook and attempts to initialize it.
In this case the gradebook reference you have has no memory allocated to it just yet. Try using the malloc() function to assign the required memory to your gradebook reference before attempting to initialize the rest of its variables.
gb = (Gradebook*)malloc(sizeof(*Gradebook));
I've changed the variable name to avoid any confusion.
To supplement varevarao's answer, you should allocate everything explicitly as a matter of habit instead of relying on segfaults to tell you something's not allocated. (Not that you necessarily do!) Messing with unallocated memory is undefined behavior, so in some cases this code does not trigger an error -
int main (void) {
Gradebook mybook;
init_gradebook(&mybook);
printf("there are %i students\n", mybook.number_of_students);
add_student(&mybook, "blerf", "blerf#gmail.com");
printf("now there are %i students\n", mybook.number_of_students);
printf("%s has an email address of %s\n", mybook.students[0].name, mybook.students[0].email);
return 0;
}
returned (on my machine)
there are 0 students
now there are 1 students
blerf has an email address of blerf#gmail.com

C -- Trouble with initializing dynamic list

I'm having trouble with the deal function in a blackjack program I am writing. Can anyone see what is going on? When I try to print in main(), I get a segmentation fault.
Cheers.
MAIN FUNCTION
int main(void)
{
int i, j, k, purse;
card deck[52];
card *head_d, *temp_d, *current_d = NULL, *last_d, *head_p, *temp_p, *current_p = NULL, *last_p;
make(deck); //CREATES THE DECK
shuffle(deck); //SHUFFLES THE DECK
deal(deck, head_d, current_d, head_p, current_p)
for(i = 0; i < DECK_SIZE; i++)
{
printf("%d: %d %c\n", i + 1, deck[i].face, deck[i].suit);
}
temp_p = head_p;
while(temp_p != NULL)
{
printf("%d %c\n", temp_p->face, temp_p->suit);
temp_p = temp_p->listp;
}
return(0);
}
FUNCTION deal()
void deal(card x[DECK_SIZE], card *head_d, card *current_d, card *head_p, card *current_p)
{
int i;
card *temp_p, *temp_d;
for(i = 0; i < 4; i++)
{
if( i % 2 == 0)
{
temp_p = (card *)malloc(sizeof(card));
temp_p->face = x[i].face;
temp_p->suit = x[i].suit;
if (current_p==NULL)
{
head_p=temp_p;
}
else
{
current_p->listp=temp_p;
}
current_p = temp_p;
temp_p->listp = NULL;
}
else
{
temp_d=(card *)malloc(sizeof(card));
temp_d->face = x[i].face;
temp_d->suit = x[i].suit;
if (current_d==NULL)
{
head_d=temp_d;
}
else
{
current_d->listp=temp_d;
}
current_d = temp_d;
temp_d->listp = NULL;
}
}
}
The problem is that the arguments to the deal function is local, meaning when you change their value in the function, the variables used when calling the function will not be changed. You need to pass those arguments by reference:
void deal(card x[DECK_SIZE], card **head_d, card **current_d, card **head_p, card **current_p);
The do e.g.
*head_p=temp_p;
in the function to set the variables.
Call as
deal(deck, &head_d, &current_d, &head_p, &current_p);
You have uninitialized pointer variable head_p in your main function. Yet you are attempting to read data supposedly pointed by head_p. Of course, you will get segfault.

Resources