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.
Related
I'm going to add a new value 4 to the list array.
The original values in list array are 1,2,3.
But when i run the following code, i didn't get 1,2,3,4 but several random numbers.
Each time I run I get different output.
Can someone help me figure out what's going wrong here?
Thanks a lot.
#include <stdio.h>
#include <stdlib.h>
int main(void){
int *list = malloc(3 * sizeof(int));
//如果直接写int list[3] 就没有办法修改大小了
if (list == NULL)
{
free(list);
return 1;
}
list[0] = 1;
list[1] = 2;
list[2] = 3;
//resize the old array to be of size 4
//用realloc指定下old array,无需再做copy的工作
int *tmp = realloc(list, 4 * sizeof(int));
if (list == NULL)
{
free(list);
//a safety check, free the original list
return 1;
}
tmp[3] = 4;
//free old array
free(list); //这里就可以free之前的list了
//remember new array
list = tmp;
//所以不需要在free(tmp), free(list)相当于free(tmp)
//print new array
for (int i = 0; i < 4; i++)
{
printf("%i\n", list[i]);
}
//free new array
free(list);
return 0; //最后记得加上这个
}
the output is like this:
1609039888
25764
2043
4
try this code
#include <stdio.h>
#include <stdlib.h>
int main(void){
int *list = malloc(3 * sizeof(int));
//如果直接写int list[3] 就没有办法修改大小了
if (list == NULL)
{
free(list);
return 1;
}
list[0] = 1;
list[1] = 2;
list[2] = 3;
//resize the old array to be of size 4
//用realloc指定下old array,无需再做copy的工作
int *tmp = realloc(list, 4 * sizeof(int));
if (list == NULL)
{
free(list);
//a safety check, free the original list
return 1;
}
tmp[3] = 4;
//free old array
//free(list); //这里就可以free之前的list了 // this free the last memory location which empty the array.
//remember new array
list = tmp;
//所以不需要在free(tmp), free(list)相当于free(tmp)
//print new array
for (int i = 0; i < 4; i++)
{
printf("%i\n", list[i]);
}
//free new array
free(list);
return 0; //最后记得加上这个
}
There's a fundamental misunderstanding on how dynamic memory management actually works...
At first, if an allocation fails (malloc returning a null pointer), then there's nothing to free anyway, so you simply don't need to (even though it's legal – then effectively a no-op...).
int* list = malloc(...);
if(!list) // shorter for list == NULL
{
return -1;
}
Then realloc replaces the old array for you already! You can imagine it to work like this:
void* realloc(void* oldData, size_t desired)
{
// retain currently allocated memory size from pointer
// that's OS/compiler specific knowledge, usually stored somewhere
// in front of the memory the pointer points to, but not (legally)
// accessible by you...
size_t old = ...;
if(desired <= old)
{
return oldData;
}
void* newData = malloc(desired);
if(newData)
{
memcpy(newData, oldData, oldSize);
free(oldData); // !!!
}
return newData;
}
Note how the old data remains intact if re-allocation fails, but gets deleted on success!
Correct usage of realloc thus looks as follows:
int* tmp = realloc(list, desiredSize);
if(!tmp)
{
// appropriate error handling
// usually you cannot meaningfully go on anyway, so let's just exit
// but HERE list still points to valid memory, so clean up first:
free(list);
return -1;
}
// we can safely use the temporary as the list now; note that the old
// memory already HAS been deleted!
list = tmp;
// and now we simply use it:
list[3] = 4;
free(list); // when done
Data structure vehicle_array_t sometimes segfaults when a new vehicle_t is added to it.
I've tried inserting and removing things in different orders, but it may be an edge case that I am unaware of how to replicate.
Definition of the struct vehicle_array_t:
typedef struct {
int size;
int used;
vehicle_t *vehicles;
} vehicle_array_t;
Code used for adding to the array:
void add_vehicle(vehicle_array_t *array, vehicle_t vehicle)
{
if (array->used == array->size)
{
array->size *= 2;
array->vehicles = (vehicle_t*)realloc(array->vehicles, array->size * sizeof(vehicle_t));
}
array->vehicles[array->used] = vehicle;
array->used++;
}
The code should resize the array appropriately when a new vehicle_t is added, but, strangely, it segfaults sometimes. I can't see any issue with the code just from looking at it.
There is one way the posted code can segfault and that is if realloc fails (and therefore returns NULL). You should not realloc directly into the data pointer - always use a temp variable.
Your code should be:
void add_vehicle(vehicle_array_t *array, vehicle_t vehicle)
{
if (array->used == array->size)
{
array->size *= 2;
vehicle_t *tmp = (vehicle_t*)realloc(array->vehicles, array->size * sizeof(vehicle_t));
if (tmp == NULL)
{
//realloc error
// add error handling here... or just exit
exit(1);
}
array->vehicles = tmp;
}
array->vehicles[array->used] = vehicle;
array->used++;
}
First of all I want to say that I did search around, but I didn't understand the solutions proposed to the existing questions.
Here is my question.
Array *create()
{
static Array *arr1;
void *arraypointer;
if ((arraypointer = (Array *) malloc(sizeof(Array))) == NULL) {
printf("Array not created because no memory is available. \n");
} else {
arraypointer = arr1;
printf("Array created successfully. \n");
}
return arr1;
}
I am assuming that that is good. Now, I want to add something to the array, so obviously I need to increase the size in memory. At the moment, I have this.
void add(Array S[], Item x)
{
static Array *arr1;
void *arraypointer;
arraypointer = (Array *) malloc(sizeof(Array) + 1);
if (is_element_of(x, S) == true) {
printf
("Item already exists in array and therefore it can't be added. \n");
} else {
strcpy(S->arr1[S->s].sinput, x.sinput);
S->arr1[S->s].iinput = x.iinput;
S->s++;
printf("Item added successfully. \n");
}
}
I feel this is not good, although I am not sure how I have to do it. The warning I get is that arr1 and arraypointer are not used in the Add method.
What should I do?
Thanks
P.S. I would appreciate if you keep it simple, as I am still trying to wrap my head around this malloc thing.
this is different from yours but It feel like the following
typedef int Item;
typedef struct da {
size_t s;//now size of array
Item *arr;//dynamic array
} Array;
Array *create(void){
Array *ap;
if((ap = malloc(sizeof(Array)))== NULL){
fprintf(stderr, "Array not created because no memory is available. \n");
} else {
fprintf(stderr, "Array created successfully. \n");
ap->s = 0;
ap->arr = NULL;
}
return ap;
}
bool is_equal(Item x, Item y){
return x == y;
}
bool is_element_of(Item x, Array *S){
size_t i;
for(i = 0; i < S->s ; ++i){
if(is_equal(x, S->arr[i]))
return true;
}
return false;
}
void add(Array *S, Item x){
if (is_element_of(x, S) == true){
fprintf(stderr, "Item already exists in array and therefore it can't be added. \n");
} else {
S->arr = realloc(S->arr, (S->s + 1) * sizeof(Item));
if(S->arr == NULL){
fprintf(stderr, "Memmory could not allocate.\n");
} else {
S->arr[S->s++] = x;
fprintf(stderr, "Item added successfully. \n");
}
}
}
Once you allocated memory with malloc and resize it afterwards, you'll have to use realloc. Otherwise, if you use malloc again you'll get a whole new array. Furthermore, if you forget to call free, you'll get a memory leak, b/c the "old" array is not freed. With realloc the content of your current array is preserved.
Also have a look at this related question: Differences between using realloc vs. free -> malloc functions
I am assuming that that is good.
No, it's not, sorry. Look at your code carefully: assuming malloc is successfull, first, it assigns a newly allocated memory region to arraypointer (which doesn't really have a reason to be void *, you should make it Array *), and then it assigns arr1 to arraypointer. After that, you just lost reference to the previously allocated block. Thus, your program contains a memory leak.
I don't see the point of using arr1, and I can't understand why you made it static. Why not something like this?
Array * create()
{
Array *arraypointer;
if ((arraypointer = malloc(sizeof(*arraypointer))) == NULL) {
printf("Array not created because no memory is available. \n");
} else {
printf("Array created successfully. \n");
}
return arraypointer;
}
The warning that you get inside add() is because you're not really using arr1 nor arraypointer: you're just using S. Nowhere in the function's code you use these variables. I'm guessing you will want to use realloc here, but it is hard to tell, since you didn't show us the structure definition for Array.
I am quite a newbie when it comes to C, and seem to be having a few issues when it comes to memory allocation and pointers. For my assignment, we have to create the ADT of dynamic sets using arrays, and to do this we require heavy use of pointers which I find a bit difficult to grasp.
I created a structure to act as the sets
struct Set{
int arrelement; //the 'size' of the array
int * arrvalue;; //the array
}
typedef struct Set *SetArray;
The issue arises when I come to applying functions such as Add(where I add a unique element to the set) or Cardinality (where the programs shows me the total number of elements in the set). Adding seems to crash my program after more than 2 additions and trying to retrieve the stored data supplies junk variables.
Here is the code for the relevant functions
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Array.h"
int size = 1; // similar to arrelement, to be used for realloc
SetArray Create(){ // to allocate memory for the set
SetArray sptr;
sptr = malloc(sizeof(struct Set));
sptr->arrvalue = malloc(sizeof(struct Set));
sptr->arrelement = 1;
return sptr;
}
SetArray Add(SetArray sptr, int x){
if(Is_Element_Of(x, sptr)){ //function to keep elements in set unique.
//Function works, which brings me to
//believe values are being stored
puts("Value already exists, enter a unique value");
}
else{
if(sptr == NULL){
puts("Memory Allocation Failed. Shutting down.");
exit(EXIT_FAILURE);
}
}
sptr = realloc(sptr, size*sizeof(struct Set)); //reallocate memory
//for the
//new element
sptr->arrvalue[sptr->arrelement] = x;
sptr->arrelement++;
size++;
return sptr;
}
SetArray Remove(SetArray sptr, int x){
if(sptr == NULL){
puts("Memory Allocation Failed. Shutting down.");
exit(EXIT_FAILURE);
}
else if(!Is_Element_Of(x, sptr)){
puts("Value is not in set");
}
else if(sptr->arrvalue == NULL){
puts("Set is empty. Cannot remove that which does not exist");
}
else{
sptr = realloc(sptr, size*sizeof(struct Set));
sptr->arrvalue[sptr->arrelement] = '\0';
sptr->arrelement--;
size--;
}
return sptr;
}
SetArray Clear(SetArray sptr){
if(sptr == NULL){
puts("Memory Allocation Failed. Shutting down.");
exit(EXIT_FAILURE);
}
int i;
for(i = 0; i < sptr->arrelement; i++){
sptr->arrvalue[i] = '\0';
}
return sptr;
}
Also, not sure if relevant, but just in case, here is the Function Is_Element_Of
int Is_Element_Of(int x, SetArray sptr){
if(sptr == NULL){
puts("Memory Allocation Failed. Shutting down.");
exit(EXIT_FAILURE);
}
int flag = 0;
int i;
for(i = 0; i < sptr->arrelement; i++){
if(sptr->arrvalue[i] == x){
flag = 1;
}
}
return flag;
}
Pardon me for any mistakes, but this is my first time asking and I tried my best to keep everything organized and structured properly.
Thank you for reading.
You are reallocating the wrong pointer you realloc the pointer to your parent Set when you want to realloc the array it contains.
sptr = realloc(sptr, size*sizeof(struct Set));
should be
sptr->arrvalue = realloc(sptr->arrvalue, (sptr->arrelement+1)*sizeof(int));
I guess your main problem is this :
sptr->arrvalue = malloc(sizeof(struct Set));
since arravlue is int*, try this :
sptr->arrvalue = malloc(sizeof(int));
edit: same for realloc
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.