Problems concerning pointers and malloc in C90 - c

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

Related

Realloc does not work (following the instruction in cs50 lecture 5)

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

creating own malloc function in c

I have create my own malloc function and it works properly. but I want to create another malloc using only array without struct. Is that possible to create without struct? This is my code.
#include <stdio.h>
char memory[20000];
int freeMem=20000;
typedef struct{
int start;
int end;
}chunk;
void *MyMalloc(int size){
printf("\nMemory Size= %d ",size);
if(size==0){
printf("0 means no memory\n");
return 0;
}
int memsize=20000;
chunk *p=(chunk *)&memory[0];
if(freeMem >= size+sizeof(chunk)){
while(p<(chunk *)&memory[19999]){
if(p->start==0){
if(p->end !=0){
if(size+sizeof(chunk)< (p->end - (int)p)){
p->start=(int)p+8;
p->end=(int)p+8+size;
freeMem = freeMem-(size+8);
printf("free Mem : %d\n",freeMem);
return (int *)p->start;
}
else{
p=(chunk *)p->end;
continue;
}
}
else{
p->start=(int)p+8;
p->end=(int)p+8+size;
freeMem = freeMem-(size+8);
printf("free Mem : %d\n",freeMem);
return (int *)p->start;
}
}
p = (chunk *)p->end;
}
}
else{
printf("no space...!\n");
return 0;
}
}
void MyFree(void * p){
chunk *ptr = (chunk *)p;
ptr--;
freeMem=freeMem+(ptr->end - ptr->start)+sizeof(chunk);
if(ptr->start != 0){
printf("\nfreed Memory : %d\t",ptr->end - ptr->start);
ptr->start = 0;
}
else{
printf("\nno Such memory allocated!!!!!\n");
}
}
Roughly speaking, the basic mechanism to use would be the same. In MyMalloc, allocate 2*sizeof(int) space more, store the content of a chunk there and return the address behind the 2*sizeof(int). On deallocation, do the same process in reverse - subtract 2*sizeof(int) from the argument to access the content of which was stored in chunk before.

realloc() on array of structs gives invalid next size

I have this function. As you can see, everything is being done in the function, I'm not allocating in the main and then passing anything to it (I'll only return the pointer to the array once the function is done). The function in itself (with a fixed size for the array) works, but the realloc fails.
struct database *parse() {
int i = 0;
int n = 1;
FILE *dbase = (fopen(PATH, "r"));
if (dbase == NULL) {
fprintf(stderr, ERRORE_APERTURA);
exit(EXIT_FAILURE);
}
struct database *database_array = calloc(20*n, sizeof(struct database));
if (database_array == NULL) {
fprintf(stderr, "Impossibile allocare memoria\n");
exit(EXIT_FAILURE);
}
while (feof(dbase) == 0) {
fscanf(dbase, "%[^:]:%[^:]:\n", database_array[i].user, database_array[i].password);
database_array[i].iswritten = 1;
i++;
if (i > 20*n) {
n++;
struct database *new_database_array = realloc(database_array, sizeof(struct database)*(20*n));
database_array = new_database_array;
}
}
database_array[++i].iswritten = 0;
fclose(dbase);
return database_array;
}
I tried reading other explanations, but I can't understand what's wrong here.
The array I allocated with calloc is initially 20. then, when it's filled, I want it to double in size, so I use n, which will be 2, by 20, so 40.
The frustrating thing is that I tried reallocating an array of struct with a simpler program, and doing THE SAME THING works without any problem:
#include <stdio.h>
#include <stdlib.h>
struct prova {
int a;
int b[10];
};
int main() {
struct prova* array_struct = calloc(10, sizeof(struct prova));
array_struct[0].a = 2;
struct prova* tmp = realloc(array_struct, sizeof(struct prova) * 20);
free(array_struct);
array_struct = tmp;
array_struct[1].b[1] = 3;
printf("a = %d", array_struct[0].a);
printf("b = %d\n", array_struct[1].b[1]);
return 0;
}
What am I not seeing? (Please nevermind the fact that I'm not checking if realloc returns NULL, I'll add that later)
struct database *new_database_array = realloc(database_array, sizeof(struct database)*(20*n));
free(database_array);
You can't both reallocate something and deallocate it. You can do either, but once you've done either, the previous allocation no longer exists, so you can't do the other.
After the first line of code above, the value of database_array should not be used anymore because it may not be valid.

glibc detected - double free or corruption

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.

C Linked List Memory Usage (Possible memory leak)

I'm having trouble with what should be a simple program.
I've written a single linked list implementation in C using void* pointers. However, I have a problem, as there is a possible memory leak somewhere, however I checked the code using valgrind and it detected no such errors.
But when all the memory is free'd there is still some memory un-freed (see comments)... I tried passing everything to the add function by reference too, but this didn't fix the issue either.
I just wondered if anyone here had any comments from looking at the code. (This should be simple!, right?)
/*
Wrapping up singley linked list inside a struct
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* Needed for: memcpy */
void waitKey(){
printf("Press any key to continue...");
getchar();
}
/* Define a structure for a list entry */
struct ListEntry {
void* data;
struct ListEntry* pNext;
};
/* Struct for list properties */
struct ListProperties {
struct ListEntry* g_pLast;
struct ListEntry* g_pHead;
struct ListEntry* pCurrent;
unsigned int size;
int getHead;
};
/* Add:
args: list, data, dyn (0 if not, else size of dynamic data)
*/
void add(struct ListProperties* l, void* d, unsigned long dyn) {
struct ListEntry* pNew = malloc(sizeof(struct ListEntry));
/* Set the data */
if (dyn > 0){
/* Allocate and copy array */
pNew->data = malloc(dyn);
pNew->data = memcpy(pNew->data,d,dyn);
} else {
pNew->data = d;
}
/* Set last element to point to new element */
if (l->g_pLast != NULL){
l->g_pLast->pNext = pNew;
/* Get head of list */
if (l->g_pHead == NULL && l->getHead == 0){
l->g_pHead = l->g_pLast;
l->getHead = 1;
}
} else {
/* 1 elem case */
l->g_pHead = pNew;
l->pCurrent = pNew;
}
/* New element points to NULL */
pNew->pNext = NULL;
/* Save last element for setting
pointer to next element */
l->g_pLast = pNew;
/* Inc size */
l->size++;
}
/* Create new list and return a pointer to it */
struct ListProperties* newList(){
struct ListProperties* nList = malloc (sizeof(struct ListProperties));
nList->g_pHead = NULL;
nList->g_pLast = NULL;
nList->getHead = 0;
nList->size = 0;
return nList;
}
/* Reset pointer */
int reset(struct ListProperties *l){
if (l->g_pHead != NULL){
l->pCurrent = l->g_pHead;
return 0;
}
return -1;
}
/* Get element at pointer */
void* get(struct ListProperties *l) {
if (l->size > 0){
if (l->pCurrent != NULL){
return l->pCurrent->data;
}
}
return NULL;
}
/* Increment pointer */
int next(struct ListProperties *l){
if (l->pCurrent->pNext != NULL){
l->pCurrent = l->pCurrent->pNext;
return 1;
}
return 0;
}
/* Get element at n */
void* getatn(struct ListProperties *l, int n) {
if (l->size > 0){
int count = 0;
reset(l);
while (count <= n){
if (count == n){
return l->pCurrent->data;
break;
}
next(l);
count++;
}
}
return NULL;
}
/* Free list contents */
void freeList(struct ListProperties *l){
struct ListEntry* tmp;
/* Reset pointer */
if (l->size > 0){
if (reset(l) == 0){
/* Free list if elements remain */
while (l->pCurrent != NULL){
if (l->pCurrent->data != NULL)
free(l->pCurrent->data);
tmp = l->pCurrent->pNext;
free(l->pCurrent);
l->pCurrent = tmp;
}
}
}
l->g_pHead = NULL;
l->g_pLast = NULL;
l->size = 0;
l->getHead = 0;
free(l);
}
void deleteElem(struct ListProperties *l, int index){
struct ListEntry* tmp;
int count = 0;
if (index != 0)
index--;
reset(l);
while (count <= index){
if (count == index){ // Prev element
if (l->pCurrent != NULL){
if (l->pCurrent->pNext != NULL){
free(l->pCurrent->pNext->data); // Free payload
tmp = l->pCurrent->pNext;
l->pCurrent->pNext = l->pCurrent->pNext->pNext;
free(tmp);
if (l->size > 0)
l->size--;
} else {
// Last element
free(l->pCurrent->data);
free(l->pCurrent);
l->g_pHead = NULL;
l->g_pLast = NULL;
l->getHead = 0;
l->size = 0;
}
}
break;
}
if (next(l) != 1)
break;
count++;
}
}
int size(struct ListProperties *l){
return l->size;
}
int main( int argc, char* argv )
{
int j = 0;
unsigned long sz = 0;
/*=====| Test 1: Dynamic strings |=====*/
/* Create new list */
struct ListProperties* list = newList();
if (list == NULL)
return 1;
char *str;
str = malloc(2);
str = strncat(str,"A",1);
sz = 2;
printf("Dynamic Strings\n===============\n");
/* Check memory usage here (pre-allocation) */
waitKey();
/* Add to list */
for (j = 0; j < 10000; j++){
add(list,(char*)str, sz);
str = realloc(str, sz+2);
if (str != NULL){
str = strncat(str,"a",1);
sz++;
}
}
/* Allocated strings */
waitKey();
/* TESTING */
freeList(list);
free(str);
/* Check memory usage here (Not original size!?) */
waitKey();
return 0;
}
Thanks!
You don't say how you are checking memory usage, but I'm going to guess that you are using ps or something similar to see how much memory the OS has given the process.
Depending on your memory allocator, calling free may or may not return the memory to the OS. So even though you are calling free, you will not see the memory footprint decrease from the OS's point of view.
The allocator may keep a cache of memory that is given to it by the OS. A call to malloc will first look in this cache to see if it can find a big enough block and if so, malloc can return without asking the OS for more memory. If it can't find a big enough block, malloc will ask the OS for more memory and add it to it's cache.
But free may simply add the memory back to the cache and never return it to the OS.
So, what you may be doing is seeing the allocators cache and not any memory leak.
As was mentioned, I would not trust the memory usage reported by the task manager as there are other factors beyond your control that impact it (how malloc/free are implemented, etc).
One way you can test for memory leaks is by writing your own wrapper functions around the existing malloc and free functions similar to:
void* my_malloc(size_t len) {
void* ptr = malloc(len);
printf("Allocated %u bytes at %p\n", len, ptr);
return ptr;
}
void my_free(void* ptr) {
printf("Freeing memory at %p\n", ptr);
free(ptr);
}
Now, you will get a log of all memory that is dynamically allocated or freed. From here, it should be fairly obvious if you leak a block of memory (the more complex your program is, the longer your log will be and the more difficult this task will be).
Your program contains incorrect argv in main, incorrect usage of strncat, and strange memory allocation. Some of these should of shown up as warnings. The argv is a non-issue, but if the others showed up as warning, you needed to heed them. Don't ignore warnings.
These changes clean it up. The biggest thing was that you don't seem to have a good grasp on the NUL ('\0') character (different than NULL pointer) used to terminate C strings, and how that effects str(n)cat.
The mixed usage of str* functions with memory functions (*alloc/free) was likely part of the confusion. Be careful.
#include <assert.h>
...
int main( int argc, char* argv[] ) /* or int main(void) */
...
sz = 2;
str = (char*) malloc(sz); /* allocate 2 bytes, shortest non-trivial C string */
assert(str != NULL);
strncpy(str, "A", sz); /* copy 'A' and '\0' into the memory that str points to */
...
/* Add to list */
for (j = 0; j < 10000; j++){
add(list, str, sz);
str = realloc(str, ++sz); /* realloc str to be one (1) byte larger */
assert(str != NULL);
strncat(str, "a", sz - strlen(str)); /* now insert an 'a' between last 'A' or 'a' and '\0' */
assert(str != NULL);
}

Resources