I'm trying to allocate some memory with realloc(). This works so far. But if I want to assign the allocated memory to a pointer in a struct variable, I get a segmentation fault:
// in header
typedef struct {
int a;
char test[20];
} MyContent;
typedef struct {
MyContent* values;
// simmilar to: MyContent values[]
// ... some other stuff
} MyData;
// in source
void myFunction(MyData* dataPtr) {
dataPtr->values = NULL;
MyData* tempPtr = NULL;
for (int i = 1; i < 10; i++) {
tempPtr = (MyContent*) realloc(dataPtr->values, i * sizeof(MyContent));
if (tempPtr == NULL) {
free(dataPtr->values);
break;
}
dataPtr->values = tempPtr; // Here I get the segmentation fault
dataPtr->values[(i-1)].a = 42;
// ...
}
}
I can't figure out what's going wrong here. Any suggestions? Thanks for your help.
Seems like you edited your code. The edited code works just fine.
#include<stdio.h>
#include<malloc.h>
#include<string.h>
// in header
typedef struct {
int a;
char test[20];
} MyContent;
typedef struct {
MyContent* values;
// simmilar to: MyContent values[]
// ... some other stuff
} MyData;
// in source
void myFunction(MyData* dataPtr) {
dataPtr->values = NULL;
MyData* tempPtr;
for (int i = 1; i < 10; i++) {
tempPtr = (MyData*) realloc(dataPtr->values, i * sizeof(MyContent));
if (tempPtr == NULL) {
if(dataPtr->values)
free(dataPtr->values);
printf("realloc() failed\n");
return ;
}
dataPtr->values = (MyContent*)tempPtr; // Here I get the segmentation fault
dataPtr->values[(i-1)].a = 42+i;
strcpy(dataPtr->values[(i-1)].test,"name");
}
}
void PrintData(MyData* dataPtr) {
for (int i = 1; i < 10; i++)
printf("We have %s at %d\n",dataPtr->values[(i-1)].test,dataPtr->values[(i-1)].a);
}
main() {
MyData Sample;
myFunction(&Sample);
PrintData(&Sample);
}
At first glance, I don't see a problem that could cause a crash there - that ones-based addressing is a bit odd, but not incorrect. There could be a problem in the code that you're not showing that results in heap or stack corruption that the realloc call makes worse. Or if you are compiling with optimizations, your debugger might be confused about where the crash is actually occurring. You're also confusing MyData and MyContent, but I'll assume that's just because you made an error while redacting the code.
Note also that if realloc fails, you will crash on the line after the one you indicated, as you'll be writing to a null pointer. You need to abort if tempPtr is NULL, not just free the old pointer. Again, though, this causes a fault on a different line than you indicated.
I'd recommend running your program under valgrind to see where it reports errors - the first such error to occur is likely to be the culprit.
Your condition is wrong for checking the newly allocated memory. It should be:
if (tempPtr == NULL) {
// handle error condition or continue with original 'dataPtr->values'
}
else {
dataPtr->values = tempPtr;
}
Remember that realloc() doesn't necessarily transfer one block to the another block. Sometimes it may allocate the memory in the same pointer region.
Related
I'm currently writing a function for an assignment, and when I attempt to increment a count variable, a segmentation fault occurs.
void createVar(char *varname, char *value) {
int val = vars->count;
if (val >= 1) {
int index = varIndex(varname);
if (index != -1) {
vars->varArray[index]->value = value;
return;
} else {
vars->varArray = (variables_ **) realloc(vars->varArray, sizeof(variables_ *) * (val + 1));
}
}
printf("count= %d\n", vars->count); //testing purposes
vars->varArray[val] = malloc(sizeof(variables_));
vars->varArray[val]->varname = varname;
vars->varArray[val]->value = value;
vars->count++; //incrementing count
}
I found that the line vars->count++; is causing the fault, however I am not sure how to fix this.
To include some context, these are the structs addressed in the above code:
typedef struct variables {
char *varname;
char *value;
} variables_;
typedef struct variableArray {
variables_ **varArray;
int count;
} variableArray_;
variableArray_ *vars;
Any help is greatly appreciated :-)
Restructure this code; something is very wrong.
You are using val and index somewhat incoherently and are probably trashing memory because they're both being used as indices into the array but the piece that uses val is not coherent with the piece that uses index.
It's almost like vars->varArray[val] is intended to be vars[val].varArray[index] but the whole of the code has to change for this to work.
I'm trying to use a "fixed memory scheme" and pre-allocate memory & reuse it via alloc, init, free fashion as many times as possible.
free() will called at shutdown only, but I want to test many iterations.
Although I call my alloc function bn_tree_alloc_node_space_heap() & init function bn_tree_init_node_heap(), I can only call free function bn_tree_free_node_space once.
Below is a complete reproducible snippet of my memory management, maint_test.c:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <float.h>
#define BN_TREE_HEAP_SIZE 100
/*variables internal*/
typedef struct bntree_internals;
/*bn_tree_node is single bntree_t leaf*/
typedef struct bn_tree_node {
struct bn_tree_node* left;
struct bn_tree_node* right;
float* dataset;
float distance_to_neighbor;
int visited;
int heap_index;
} bn_tree_node;
/*tree*/
typedef struct {
/*in order to keep track of the bn-tree root*/
bn_tree_node* _root;
/*pointer to internal variables struct*/
struct bntree_internals* _internals;
} bntree_t;
/*bn tree leaf nodes heap*/
bn_tree_node* node_processing_space = NULL;
/*leaf nodes*/
void bn_tree_alloc_node_space_heap(int max_dimensions);
bn_tree_node*
get_pre_allocated_bn_tree_node_heap();
void bn_tree_init_node_heap(bn_tree_node* nodes, int max_dimensions);
void bn_tree_free_node_space(bn_tree_node* nodes);
int main(int argc, char** argv) {
/*PROBLEM:called the alloc,init,free cycle several times, problem,
getting seg fault on 2nd call of free()*/
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
bn_tree_alloc_node_space_heap(3);
assert(get_pre_allocated_bn_tree_node_heap());
printf("alloc\n");
bn_tree_init_node_heap(node_processing_space, 3);
printf("init\n");
bn_tree_free_node_space(node_processing_space);
printf("free\n");
return (EXIT_SUCCESS);
}
void bn_tree_alloc_node_space_heap(int max_dimensions) {
if (NULL == node_processing_space) {
node_processing_space = (bn_tree_node*) calloc(BN_TREE_HEAP_SIZE, sizeof (bn_tree_node));
//TODO: bn_tree_set_k_dimensions (max_dimensions);
int i = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
node_processing_space[i].dataset = (float*) calloc(max_dimensions, sizeof (float));
}
//bn_heap_tail_index = bn_heap_head_index = 0;
}
}
bn_tree_node* get_pre_allocated_bn_tree_node_heap() {
return node_processing_space;
}
void bn_tree_init_node_heap(bn_tree_node* nodes, int max_dimensions) {
int i = 0;
int c = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
/*reset values */
if (NULL != nodes[i].dataset) {
c = 0;
for (; c < max_dimensions; c++) {
nodes[i].dataset[c] = FLT_MIN;
}
}
nodes[i].visited = 0;
nodes[i].distance_to_neighbor = FLT_MAX;
nodes[i].left = NULL;
nodes[i].right = NULL;
nodes[i].heap_index = -1;
}
}
/*PROBLEM is subsequent call to free(), but if I alloc again why cant I free again?*/
void bn_tree_free_node_space(bn_tree_node* nodes) {
int i = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
if (nodes[i].dataset) {
free(nodes[i].dataset);
}
}
free(nodes);
nodes = NULL;
}
Here is the output that I expect/want:
alloc
init
free
alloc
init
free
alloc
init
free
alloc
init
free
But Im getting this output/error:
alloc
init
free
alloc
init
double free or corruption (!prev)
Aborted (core dumped)
How can fix this?
Can't I do alloc,init,free as many times as I want (as long as I called alloc before free) OR I can do only alloc() once, then many init(), free() once?
Thanks a million & please be kind enough to provide concise answers with minimal changes.
The problem is that your bn_tree_free_node_space function takes, as its argument, a copy of the pointer variable - that is, you are passing the pointer by value - thus, the line nodes = NULL; at the end of that function only sets the local variable to NULL and does not change the value of the node_processing_space variable.
To fix this (with minimal changes to your code logic1), you need to pass that function a pointer to the pointer, and dereference that in the function. So, your function should look like this:
void bn_tree_free_node_space(bn_tree_node** nodes) // Argument is pointer-to-pointer
{
int i = 0;
for (; i < BN_TREE_HEAP_SIZE; i++) {
if ((*nodes)[i].dataset) { // Now we need to use (*nodes) to get the underlying pointer
free((*nodes)[i].dataset); // ... same here
}
}
free(*nodes); /// ... and here
*nodes = NULL;
}
You will, of course, also need to change the function prototype (just before your main) to match the new definition:
void bn_tree_free_node_space(bn_tree_node** nodes); // Must match definition!
Fruther, you will (clearly) need to change the calls to that function to pass the address of the node_processing_space pointer:
bn_tree_free_node_space(&node_processing_space); // Likewise for the other 3 calls!
Feel free to ask for further clarification and/or explanation.
1 EDIT: There are other ways (some may argue better ways) to implement your system, and also other 'minor' issues in your code. However, you did explicitly ask for "concise answers with minimal changes," so I have endeavoured to comply with that request!
The following code works fine without the statement d = *dummy; which is a double pointer dereference. However if this line is present, a segmentation fault occurs. Why so?
The code allocates and initializes memory for data structs dynamically. I was trying to simplify access to the returned pointer-to-pointer.
#include <stdlib.h>
#include <stdio.h>
typedef struct s_dummy {
char dummy_number;
} Dummy;
int mock_read_from_external_source() {
return 4;
}
int load_dummies(Dummy** dummies, int* num_of_dummies) {
*num_of_dummies = mock_read_from_external_source();
*dummies = (Dummy*) calloc(*num_of_dummies, sizeof(Dummy));
if (!dummies) {
return 1; // allocation unsuccessful
}
// Iterate dummies and assign their values...
for (int i = 0; i < *num_of_dummies; i++) {
(*dummies + i)->dummy_number = i;
}
return 0;
}
void main() {
Dummy** dummies;
Dummy* d;
int num_of_dummies = 0;
int *p_num_of_dummies = &num_of_dummies;
int err;
err = load_dummies(dummies, p_num_of_dummies);
// Segmentation fault occurs when dummies is dereferenced
d = *dummies;
if (err) {
exit(err);
}
for (int i = 0; i < num_of_dummies; i++) {
printf("Dummy number: %d\n", (*dummies + i)->dummy_number);
}
}
Thanks in advance.
You are getting the fault because of UB, in part caused by trying to use variable objects without memory. dummies, although created as a Dummies **, has never been provided memory. At the very least, your compiler should have warned you about dummies not being initialized in this call:
err = load_dummies(dummies, p_num_of_dummies);
This is easily addressed by simply initializing the variable when it is created:
Dummy** dummies = {0}; //this initialization eliminates compile time warnings
^^^^^
Then come the run-time errors. The first is called a fatal run-time on my system, which means the OS refused to continue because of a serious problem, in this case an attempt to dereference a null pointer in this line:
dummies = (Dummy) calloc(*num_of_dummies, sizeof(Dummy));
Because you created a Dummy ** called dummies, the first step is to create memory for the pointer to pointers dummies, then create memory for the several instances of dummies[i] that will result. Only then can the members of any of them be written to.
Here is one method illustrating how memory can be created for a Dummies pointer to pointers, ( d ) and several Dummies instances ( d[i] ):
Dummy ** loadDummies(int numPointers, int numDummiesPerPointer)
{
int i;
Dummy **d = {0};
d = malloc(numPointers * sizeof(Dummy *));//Create Dummies **
if(!d) return NULL;
for(i=0;i<numPointers;i++)
{ //Now create Dummies *
d[i] = malloc(numDummiesPerPointer*sizeof(Dummy)); //random size for illustration
if(!d[i]) return NULL;
}
return d;
}
In your main function, which by the way should really be prototyped at a minimum as: int main(void){...}, this version of loadDummies could be called like this:
...
Dummies **dummies = loadDummies(4, 80);
if(!dummies) return -1;//ensure allocation of memory worked before using `dummies`.
...
After using this collection of dummies, be sure to free all of them in the reverse order they were created. Free all instances of dummies[0]-dummies[numPointers-1] first, then free the pointer to pointers, dummies
void freeDummies(Dummy **d, int numPointers)
{
int i;
for(i=0;i<numPointers;i++)
{
if(d[i]) free(d[i]);
}
if(d) free(d);
}
Called like this:
freeDummies(dummies, 4);
dummies was never assigned a value, so de-referencing will attempt to reach some random memory which is almost certainly not going to be part of your program's allocated memory. You should have assigned it to &d.
But you don't even need to do that. Just use &d once when you call the function.
Also, if you return the number of dummies allocated instead of 1/0, you can simplify your code. Something like the below (not tested):
#include <stdio.h>
int mock_read_from_external_source() {
return 10;
}
typedef struct Dummy {
int dummy_number;
} Dummy;
int load_dummies(Dummy** dummies) {
int want, i = 0;
if((want = mock_read_from_external_source()) > 0) {
*dummies = (Dummy*) calloc(want, sizeof(Dummy));
if(*dummies) {
// Iterate dummies and assign their values...
for (i = 0; i < want; i++) {
(*dummies)[i].dummy_number = i;
}
}
}
return i;
}
int main() {
Dummy* d = NULL;
int num_of_dummies = load_dummies(&d); // when &d is de-referenced, changes are reflected in d
if(num_of_dummies > 0) {
for (int i = 0; i < num_of_dummies; i++) {
printf("Dummy number: %d\n", d[i].dummy_number);
}
}
if(d) { // clean up
free(d);
}
return 0;
}
Apologies for the really bad question - I wasn't really sure how to word it.
I'm executing a piece of code where I'm trying to use a dynamic array. It is segfault-ing at this line:
void myFunction(....) {
// other code up here
Stack *s = stack_new(); //segfault here
}
The relevant header file for my struct is:
typedef struct {
void **A;
int size;
int top; // the index of the current top of the stack
} Stack;
and the function stack_new() is:
Stack
*stack_new() {
Stack *s;
s->size = 1;
s->top = -1;
s->A = (void **)malloc(s->size);
return s;
}
I think I've included everything that is relevant, but please let me know if you need more code.
I think that the problem is with the way I'm using malloc, but have had a search online and have tried a few different options and am still getting the segfault. Is anyone able to offer some insight?
Thank you heaps
This is your problem:
Stack *s;
s->size = 1;
you're not actually allocating a Stack. s is uninitialized and points to an arbitrary location in the memory. s->size will obviously fail then.
Try:
Stack *s = malloc(sizeof(*s));
if (s == NULL)
{
fprintf(stderr, "Memory allocation error\n");
exit(1);
}
s->size = 1;
Note: you should also check if s->A is NULL. If so, return an error code (such as NULL) and before that remember to free the Stack you allocated, or alternatively print an error message and exit the program. If you exit the program, the operating system will reclaim all memory used so no need to do it explicitly then.
Another note: when doing
s->size = 1;
s->top = -1;
s->A = (void **)malloc(s->size);
...you allocate 1 byte of memory even though you should be allocating sizeof(void*) bytes of memory. Try doing
s->A = (void **)malloc(s->size*sizeof(void*));
instead.
Here's your first problem:
Stack *s;
s->size = 1;
What do you actually expect the value of s is at this point? It could be literally anything. You can't set a field of a struct if the struct itself isn't already allocated.
Try:
Stack *s = malloc(sizeof(*s));
if(!s){
//... error checking / exiting ..
}
and then everything else you were doing.
You are accessing a not initialized pointer!
Stack
*stack_new() {
Stack *s = std::nullptr; // initialize this pointer with nullptr
// and then you will see later (one line
// beyond) that you will try to access a
// null pointer
s->size = 1; // the problem occurs here!!
// you are accessing a pointer, for which has never
// been allocated any memory
s->top = -1;
s->A = (void **)malloc(s->size);
return s;
}
You will have to use "malloc" to allocate some memory for this pointer.
sth. like this is missing between those two lines, I commented:
Stack
*stack_new() {
Stack *s = (Stack*)malloc(sizeof(Stack));
s->size = 1;
s->top = -1;
s->A = (void **)malloc(s->size);
return s;
}
this might be a bit long so my apologies.
consider the following code (i've left some irrelevant parts from it). this code receives a pointer to a struct (BoardP theBoard), x & y coords and a value.
the goal is to place the value in a 2D array that is found in the struct.
if the coords are out of bounds, i have to increase the size of the table, copy old data to new data and place the value in its place.
well this code works the first call but in the second call it crashes and writes:
*** glibc detected *** ./b: double free or corruption (top): 0x092ae138 ***
i couldn't find an answer to it and i hope you will help.
These are the calls from main()
BoardP p = CreateNewBoard(10,10);
PutBoardSquare(p,10,5,'X');
PutBoardSquare(p,5,10,'O');
Boolean PutBoardSquare(BoardP theBoard, int X, int Y, char val) {
if (inBounds(X,Y,theBoard->_rows,theBoard->_cols)) {
theBoard->_board[X * theBoard->_cols + Y] = val;
return TRUE;
}
else {
int newRows = (X>=theBoard->_rows) ? (2*X) : theBoard->_rows;
int newCols = (Y>=theBoard->_cols) ? (2*Y) : theBoard->_cols;
BoardP newBoard = CreateNewBoard(newCols,newRows); //this creates a new Board with the new dimensions
if (newBoard == NULL) {
//ReportError(MEM_OUT);
return FALSE;
}
else {
copyData(theBoard,newBoard);
freeBoardArray(&theBoard->_board[0]); //free old array
theBoard->_board = newBoard->_board; //old array point to new array
FreeBoard(newBoard); //free the temp copy THIS CAUSES THE PROBLEM
PutBoardSquare(theBoard,X,Y,val);//recursion, will be in bounds now
return TRUE;
}
}
}
These are the Free functions:
void FreeBoard(BoardP board) {
if (board != NULL) {
printf("FREE 1\n");
//free the board array:
if (board->_board != NULL) {
printf("FREE 2\n");
freeBoardArray(&board->_board[0]);
printf("FREE 3\n");
}
free(board);
}
}
static void freeBoardArray(char * arrP) {
free(arrP); //**PROGRAM CRASH HERE**
}
This is how i create a new board:
BoardP CreateNewBoard(int width, int high) {
BoardP board = (BoardP) malloc(sizeof(Board));
if (board != NULL) {
board->_board = allocateBoardArray(high,width);
if ( board->_board == NULL) {
FreeBoard(board);
//TODO make file ReportError(MEM_OUT);
return NULL;
}
initializeBoard(board,high,width,X_SIGN,SPACE);
return board;
}
else {
FreeBoard(board);
//TODO make file ReportError(MEM_OUT);
return NULL;
}
}
static char* allocateBoardArray(int row, int col) {
char* newBoard = (char*) malloc(row * col * sizeof(char));
if (newBoard == NULL) {
return NULL;
}
return newBoard;
}
this is BoardP:
typedef struct Board* BoardP;
You have to free memory which you have allocated and no longer want to hold a reference too.
from your code i can see the following line.
theBoard->_board = newBoard->_board;
Now you maintain reference to a allocated pointer and then free that same pointer itself.
Example code:
char *foo()
{
char *ref1;
char *ref2;
ref1 = malloc(256);
ref2=ref1;// Holding reference to a pointer in another pointer
strcpy(ref1,"stackoverflow");
printf("%s %s",ref1,ref2); // This prints stackoverflow twice
free(ref1); // This is valid but you can access ref2 or ref1 after this point
return ref2; /// This will cause problems
}
Try this:
copyData(theBoard, newBoard);
/* swap the _board pointers */
char * b = theBoard->_board;
theBoard->_board = newBoard->_board;
newBoard->_board = b;
FreeBoard(newBoard); /* cleanup the temp struct and the old array */
This errors says that you are trying to free the memory which is already freed by you. What i am suspecting here is this block of code
if (board != NULL) {
printf("FREE 1\n");
//free the board array:
if (board->_board != NULL) {
printf("FREE 2\n");
freeBoardArray(&board->_board[0]);
printf("FREE 3\n");
}
free(board);
once you are freeing the part of structure freeBoardArray(&board->_board[0]); and then you are freeing the whole structure free(board);, and it looks to me causing the problem.Why you passing the address of the _board pointer?I wrote the code on the same line of code,which causing the problem.
struct a{
int * next;
};
int main(){
struct a *aptr = (struct a *)malloc(sizeof(struct a));
aptr->next=(int *)malloc(5*sizeof(int));
free(&aptr->next);
free(aptr);
return 0;
}
this code will cause the same issue as you shown. Now again try this code after removing '&' from free(&aptr->next);statement.It will work fine.
So i think you got a clue where you have to modify.
Running this code under valgrind will tell you exactly on which line you a.) first freed the memory and b.) when you tried to free it again.
It will also tell you if you try and access any addresses which are inside a block that you have freed.