Related
In my notes the following code is provided as an example of a programm to allocate and deallocate
memory that doesn't work because the vett variable in the allocate function is local. The function is fixed by using a double pointer and doing the changes in the commented code
void allocate(double *vett, int n) //void allocate(double **vett, int n);
{ printf("vett=%p\n",vett); // printf("vett=%p\n",*vett);
vett = (double*)calloc(n,sizeof(double)); //*vett = (double*)calloc(n,sizeof(double));
printf("vett=%p\n",vett); // printf("vett=%p\n",*vett);
}
void freeit(double *vett) { free(vett); }
int main(int argc,char **argv)
{
double *v=NULL;
int i, size=atoi(argv[1]);
allocate(v,size); // allocate(&v,size);
printf("v=%p\n",v); //printf("v=%p, &v=%p\n",v,&v);
for(i=0;i<size;i++)
v[i]=i;
for(i=0;i<size;i++)
printf("v[%d]=%f\n",i,v[i]);
freeit(v);
return 0;
}
My question is do we really need a double pointer to fix the code? I came up with the following solution:
void* allocate(double *vett, int n) // I changed here
{ printf("vett=%p\n",vett);
vett = (double*)calloc(n,sizeof(double));
printf("vett=%p\n",vett);
return vett; // I added this
}
void freeit(double *vett) { free(vett); }
int main(int argc,char **argv)
{
double *v=NULL;
int i, size=atoi(argv[1]);
v=allocate(v,size); // I changed here
printf("v=%p\n",v);
for(i=0;i<size;i++)
v[i]=i;
for(i=0;i<size;i++)
printf("v[%d]=%f\n",i,v[i]);
freeit(v);
return 0;
}
Is my solution ok? If it is, is any of the solutions preferable over the other?
Additionaly in the following site https://aticleworld.com/dangling-pointer-and-memory-leak/ I found the following functions, but I don't think the Memory_Allocate function is correct, since it returns a local variable ( pvHandle). Am I right?
static unsigned int Allocate_Counter = 0;
static unsigned int Deallocate_Counter = 0;
void *Memory_Allocate (size_t size)
{
void *pvHandle = NULL;
pvHandle = malloc(size);
if (NULL != pvHandle)
{
++Allocate_Counter;
}
else
{
//Log error
}
return (pvHandle);
}
void Memory_Deallocate (void *pvHandle)
{
if(pvHandle != NULL)
{
free(pvHandle);
++Deallocate_Counter;
}
}
int Check_Memory_Leak(void)
{
int iRet = 0;
if (Allocate_Counter != Deallocate_Counter)
{
//Log error
iRet = Memory_Leak_Exception;
}
else
{
iRet = OK;
}
return iRet;
}
Your second example is correct, in the case you return back a pointer, that pointer is the one received from calloc(). And in that case there's no need for the double pointer. In the first case, without returning the pointer with return, the problem is that the pointer you pass to the function is copied in, and the copy can be modified inside the function, but that copy is different than the value of the variable you got it from.
Now two hints:
I have told you this in a comment to the question but: NEVER cast the result of malloc() and friends. You hide several possible errors if you cast the value returned: if you forget to #include <stdlib.h> the compiler will assume the function returns an int (wrongly, a pointer and a int are not the same size in 64bit architectures, and getting a 32 bit value will truncate your data to 32 bits, to later extend it to 64) and will generate code for getting an int that will be converted to a pointer (because of the cast, wrong again) with no warning from the compiler (because you have said with the cast don't worry, I know what I'm doing)
You return a void * from your function, which returns the value of a variable that is of type double *, and do so without a cast, that illustrates how the void * can be automatically converted by the compiler, so making the cast from malloc() totally unnecessary. But why don't return instead a double *, as you have already made the effort to convert a void * into a double *, just to convert it back to void *. If you want a wrapper function to return arrays of doubles, then return a double * in the function, and then you'll avoid the type conversion you do in the return statement, just to convert it again back to double * (which I guess this is what you want).
This applied to your code results in these comments:
/* return void *? Why did you convert it to double *? */
void* allocate(double *vett, int n)
/* why pass a pointer if you are not using the value inside the function body? */
{ printf("vett=%p\n",vett); /* well you print it :$ */
/* don't cast the automatic conversion, let the compiler do its work */
vett = (double*)calloc(n,sizeof(double));
printf("vett=%p\n",vett);
return vett; /* the double * stored in vett is converted to a void * to return it */
}
void freeit(double *vett) { free(vett); }
int main(int argc,char **argv)
{
double *v=NULL;
int i, size=atoi(argv[1]);
v=allocate(v,size); /* and you convert it again to double * here */
printf("v=%p\n",v);
...
so you get a void *, cast it to double * to be stored in a pointer variable, convert it to void * again to return the value to main and convert it again automatically to store it in main's v variable. My conclusion from this sample is that you never cast the value of malloc, and you should use the type void * as low as possible. The standard library functions do it for reasons out of scope, and trying to emulate them is something you can try, but when you have a better understanding of pointers. Until then, better never use void * pointers. A general principle is that you should the proper types, you never had to cast them. Casting should not be necessary (and it's almost never done in well written code) so better avoid casting as much as you can. The 80% of the errors come from bad casts, and the other 20% come from improperly defined types. C is already a language too lazy in type management, don't make it more by overusing of casts.
In my opinion, your code should be:
double *allocate_doubles(int n)
{
/* automatic conversion is done here only */
double *vett = calloc(n, sizeof(double));
printf("vett=%p\n", vett);
/* no conversion as vett is already of the function return type */
return vett;
}
void freeit(double *vett)
{
free(vett);
}
int main(int argc, char **argv)
{
double *v = NULL; /* use spaces, for readability */
int i, /* this is more readable */
size = atoi(argv[1]);
/* and no conversion because both, allocate and v are the same type */
v = allocate(v, size);
printf("v=%p\n", v);
for(i = 0; i < size; i++)
v[i] = i;
for(i = 0; i < size; i++)
printf("v[%d]=%f\n", i, v[i]);
freeit(v);
return 0;
}
In the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char** tab;
int n;
}slist;
void print(slist* p);
void add(slist* p, const char* s);
void add(slist* p, const char* s)
{
if(p->n==0)
{
p->tab=(char**)malloc(sizeof(char**));
}
strcpy(p->tab[p->n],s);
p->n=p->n+1;
}
void print(slist* p)
{
int i;
printf("[");
for(i=0;i<p->n;i++)
printf(" %s",p->tab[i]);
printf(" ]");
}
int main()
{
char s1[25] = "Picsou";
char s2[25] = "Flairsou";
slist* p = (slist*)malloc(sizeof(slist));
p->n=0;
p->tab=NULL;
add(p,s1);
add(p,s2);
print(p);
return 0;
}
the function add() doesn't work, but if I change it to:
void add(slist* p, const char* s)
{
if(p->n==0)
{
p->tab=(char**)malloc(sizeof(char**));
}
p->tab[p->n]=s;
p->n=p->n+1;
}
it seems to work perfectly well. In the first case the output is only " [";
in the second case it is what is should be: " [ Picsou Flairsou ] ".
I cannot understand why.
I also tried this :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char** tab;
int n;
}slist;
void print(slist* p);
void add(slist* p, const char* s);
void print(slist* p)
{
int i;
printf("[");
for(i=0;i<p->n;i++)
printf(" %s",p->tab[i]);
printf(" ]");
}
void add(slist* p, const char* s)
{
slist* tmp = (slist*)malloc(sizeof(slist));
tmp->tab=(char**)malloc(sizeof(char*)*(p->n+1));
int i;
for(i=0;i<p->n;i++)
tmp->tab[i]=(char*)malloc(sizeof(char));
strcpy(tmp->tab[p->n],s);
tmp->n=p->n+1;
p = tmp;
}
int main()
{
char* s1 = "Picsou";
char* s2 = "Flairsou";
slist* p = (slist*)malloc(sizeof(slist));
p->n=0;
p->tab=NULL;
add(p,s1);
add(p,s2);
print(p);
return 0;
}
Lots of errors here, which is common with people who are new to dealing with pointers. Where to begin... I'll just go in the order things appear in code.
This is not a "list".
It's an array... sort of. If you say "list" to a C programmer, they will think you mean a linked-list.
Incorrect allocation of array.
if(p->n==0)
{
p->tab=(char**)malloc(sizeof(char**));
}
Here you have allocated enough to store a single pointer. The second time you call add, you're going to access memory off the end. You have also incorrectly cast the result (in C, you don't cast the return value from malloc). Additionally, you have given confusing information to the reader, because you intend to allocate an array that will hold elements of type char*, NOT char**.
You must either allow the array to expand dynamically when required (not appropriate for your abilities right now - maybe try that in a few days), or set a maximum size. Let's do that.
const int MAX_SIZE = 100;
if( p->n==0 )
{
p->tab = malloc( MAX_SIZE * sizeof(char*) );
}
else if( p->n == MAX_SIZE )
{
printf( "Maximum size exceeded!\n" );
return;
}
You could use calloc instead of malloc if you like. It will zero-initialise the block after allocating it: calloc( MAX_SIZE, sizeof(char*) )
Copying to an uninitialized pointer.
strcpy(p->tab[p->n],s);
You allocated memory for tab, but you did not allocate memory that is pointed to by its elements, and here you have undefined behaviour (most likely resulting in a segmentation fault, but could do anything).
Make sure you have a valid pointer, and the location it points has enough storage reserved for the data you are copying into it:
p->tab[p->n] = malloc( strlen(s) + 1 );
strcpy( p->tab[p->n], s );
Storing potentially invalid pointer.
Your alternative that "works perfectly well" uses:
p->tab[p->n]=s;
However, the only reason this works is because those pointers remain valid for the whole time that you use the "list" (but actually the program does not "work" because of reasons I highlighted in number 2.
Sometimes we desire this behaviour in a program, and design our data structures to index pointers that they do not own. But more often, and especially for a beginner, you are better off copying the data (instead of simply copying the pointer). And so you'll instead use the approach I've suggested in number 3 above.
No comment!!
There are so many things wrong with the following code, that I'm not going to pull it apart or explain them.
void add(slist* p, const char* s)
{
slist* tmp = (slist*)malloc(sizeof(slist));
tmp->tab=(char**)malloc(sizeof(char*)*(p->n+1));
int i;
for(i=0;i<p->n;i++)
tmp->tab[i]=(char*)malloc(sizeof(char));
strcpy(tmp->tab[p->n],s);
tmp->n=p->n+1;
p = tmp;
}
However, it appears like you were attempting to do something similar to realloc. This is the option I mentioned in number 2 that I said you're maybe not ready for. But read up on it anyway: realloc
I am relatively new to programming in general, and I'm trying to write some code to work with square matrices. Unfortunately, I'm stuck very early in the development, as the code
typedef struct Matrix_t{
float** content;
size_t size;
} Matrix_t;
int main(int argc, char** argv) {
Matrix_t* matr;
initMatrix(matr,s);
/*
...
...
...
*/
return 0;
}
void initMatrix(Matrix_t* m, size_t s) {
int i;
m = (Matrix_t*) malloc(sizeof(Matrix_t));
m->content = (float**) malloc(s*sizeof(float*));
for(i=0;i<s;i++){
m->content[i] = (float*) malloc(s*sizeof(float));
}
m->size = s;
}
would SIGSEGV immediately after initMatrix() is done.
Using the debugger, I found out that basically all matrix info is lost after initMatrix() is closed. Why is it? And how can I fix it?
Thanks in advance.
Make matr=NULL in main function and so, try:
main(){
Matrix_t *matr=NULL;
/*Declare and initialize "s" variable.... */
initMatrix(&matr,s); /* See below... */
/*
.....
*/
}
Use a pointer to pointer in Matrix_t *m in function initMatrix
void initMatrix(Matrix_t **m, size_t s)
{
Matrix_t *aux=(Matrix_t*)malloc(sizeof(Matrix_t));
/*check if matrix already allocated */
if(*m != NULL)
{
/*Make a free matrix function to free the matrix before use*/
free_my_matrix(m);
*m=NULL;
}
/***
Work with aux....
aux->content=...malloc....
***/
/* make your base pointer be aux */
*m=aux;
}
You're modifying only a local automatic variable m in your function. C is a pass-by-value language. If you want to pass by address, then an address is what you have to pass, declaring the formal parameter as a pointer-to-type, even when that type is already a pointer and what you're modifying is the the pointer itself.
When you're passing something as an in/out or out parameter, If you find yourself doing this:
void foo(Type *p)
{
p = malloc(...)
}
you're not modifying the data pointed to by p, you're modifying p itself, and the caller will be unaware of the change. The address stored in p upon entrance is lost. Where as this:
void foo(Type *p)
{
*p = ....
}
is modifying what p points to. That said, if Type is already a pointer-type, and what you want to modify it the pointer itself, you must do this:
void foo(Type **pp) // declare a pointer-to-pointer-to-type
{
*pp = malloc(....) // dereference to store the address returned from malloc
// in the pointer pointed to by pp
}
Therefore, the most immediate fix is to declare the formal parameter as a pointer-to-pointer-to-type, passing the address of matr from main()
void initMatrix(Matrix_t **pp, size_t s)
{
int i;
Matrix_t *m = malloc(sizeof(Matrix_t));
m->content = malloc(s*sizeof(float*));
for(i=0;i<s;i++)
m->content[i] = malloc(s*sizeof(float));
m->size = s;
*pp = m; // note: saving pointer to the output target
}
int main(int argc, char** argv)
{
Matrix_t* matr = NULL;
initMatrix(&matr,s); // note: passing address of pointer
/*
...
...
...
*/
return 0;
}
I left out the error checking (or I should say, I didn't add any, as there was none there to begin with) and removed the unneeded casts from malloc, which you can read more about here.
There are about a half-dozen ways to do this, but this is the most direct to what code you already have. I would advise either returning the allocation from the function itself as the ret-val, or not even dynamic-allocating the structure itself as there is no need to do so. Both of which I leave for you to think about.
Best of luck.
I would like to create a function that will reallocate 2D array of typedef struct
typedef struct hero_data{
char name[254];
char title[254];
int encoding;
int startstr;
double incstr;
int startdex;
double incdex;
int startintel;
double incintel;
int basemindmg,basemaxdmg;
double bat;
double basearmor;
struct hero_data *next;
struct hero_data *Class;
}hero;
typedef struct parameters{
int toughtotal;
int nimbletotal;
int smarttotal;
int skeptictotal;
int mystictotal;
int cursedtotal;
int brutetotal;
int shreddertotal;
int vanillatotal;
int typetotal;
int typenum;
hero **smart[];
hero **nimble[];
hero **tough[];
hero **type[][];
hero **skeptic[][];
hero **mystic[][];
hero **cursed[][];
hero **brute[][];
hero **shredder[][];
hero **vanilla[][];
}Parameters;
void reallocation(Parameters *p, int typenum,int typetotal)
{
int i;
p = realloc(p,sizeof(Parameters *) * typenum);
for ( i = 0; i < typenum; i++)
{
p[i] = realloc(p[i],sizeof(Parameters) * typetotal);
}
}
The function above shall be called like: void reallocation(p->type,p->typenum,p->typetotal);
So, by substituting the parameters of the function correctly, I expect the function to look like:
void reallocation(Parameters *p, int typenum,int typetotal)
{
int i;
p->type = realloc(p->type,sizeof(Parameters *) * p->typenum);
for ( i = 0; i < p->typenum; i++)
{
p->type[i] = realloc(p->type[i],sizeof(Parameters) * p->typetotal);
}
}
The typedef struct named Parameters contains int typenum, int typetotal, and the 2D arrays that shall be initialized through realloc().
When I try to compile, I am getting an error in Tiny C (Windows): *The file is in C.
Error: cannot cast 'struct parameters' to 'void *'
(This apeears in the 'p[i] = realloc(p[i],sizeof(Parameters) * typetotal')
Can anyone help me re-write this function so that I will be able to realloc the 2D arrays within the Parameter *p?
I tried changing void reallocation(Parameters *p, ...) into void reallocation(Parameters *p[], ...) and the Error # 2 becomes the same message as Error #1 and it appears in the = of p[i] = realloc (...);
A large problem with your code is that you are assigning inequal types to each other, and you are also not checking the result of realloc. If this call were to fail, you will leak the memory allocated initially.
Assuming that your struct looks like
typedef struct {
int typenum;
int typetotal;
} Parameters;
Parameters *p;
p = malloc(10 * sizeof(*p));
if (p == NULL)
printf("Allocatation of memory failed!\n");
To properly reallocate to say 20, you could do something like this
reallocate_p(&p, 20);
Where the function is defined as
void reallocate_p(Parameters **p, int new_size)
{
Parameters *temp;
temp = realloc(*p, sizeof(*temp) * new_size);
if (temp==NULL) {
printf("Reallocatation of memory failed!\n");
// Handle error
}
*p = temp;
return;
}
Also note that we don't cast the return value of malloc() and realloc().
As to why, see this reference
OP is coding in C, but using a using a C++ compiler.
Code in C++
// C
// p = realloc(p,sizeof(Parameters *) * typenum);
// C++
p = (Parameters *) realloc(p,sizeof(Parameters *) * typenum);
OR
VS2012: set properties for each C file to use C compiler
How to compile C in visual studio 2010?
OP code has a memory leak when scaling down the pointer array table. The pointers in the table that are about to be loss due to realloc() need to be freed first.
for (i=old_typenum; i<typenum; i++) free(p[i]);
p = realloc(p,sizeof(Parameters *) * typenum);
So I have implemented a generic stack in Plain C. It should copy different type of data, inclusive structures. And by structures I have the problem.
So here's the structure of the stack:
/*
* Definite genStack as a structure.
* Pointer elems points to the objects lying on the stack
* The variable elemSize spiecifies the size of an element
* The variable logLength specifies the number of actually
* lying on the stack objects
* The variable allocLenght specifies the allocated size
*/
typedef struct{
void* elems;
int elemSize;
int logLength;
int allocLength;
}genStack;
Push and pop functions:
void GenStackPush(genStack *s, const void *elemAddr)
{
/* if stack is full - allocates more memory */
if (GenStackFull(s))
{
GenStackAlloc(s, s->elemSize);
}
memcpy((char*) (s->elems)+(s->logLength), elemAddr, sizeof(*elemAddr));
s->logLength++;
}
void GenStackPop(genStack *s, void *elemAddr)
{
if(GenStackEmpty(s))
{
fprintf(stderr, "Can't pop element from stack: stack is empty.\n");
} else
{
s->logLength--;
memcpy((void*) elemAddr, (s->elems)+(s->logLength), sizeof(s->elems[s->logLength]));
}
}
Simple structures test:
gentest.h:
#ifndef GENTEST1_H
#define GENTEST1_H
typedef struct {
char* name;
int age;
char gender;
}person;
#endif
gentest.c:
#include <stdio.h>
#include <stdlib.h>
#include "gentest1.h"
#include "genstacklib.h"
int main(int argc, char* argv[])
{
genStack StructStack;
person testPerson[5];
person* newPerson;
person* test;
int i;
newPerson = (void*) malloc (sizeof(person));
testPerson[0].name = "Alex";
testPerson[0].age = 21;
testPerson[0].gender = 'm';
testPerson[1].name = "Vanja";
testPerson[1].age = 20;
testPerson[1].gender = 'm';
testPerson[2].name = "sjrgsde";
testPerson[2].age = 11;
testPerson[2].gender = 'w';
testPerson[3].name = "wergsggsd";
testPerson[3].age = 99;
testPerson[3].gender = 'y';
testPerson[4].name = "adaasxx";
testPerson[4].age = 13;
testPerson[4].gender = 'g';
GenStackNew(&StructStack, sizeof(person));
printf("sizeof(person) = %lu\n", sizeof(person));
for (i = 0; i < 5; i++) {
newPerson = &testPerson[i];
GenStackPush(&StructStack, newPerson);
printf("Pushed: %s, %d, %c\n", newPerson->name, newPerson->age, newPerson->gender);
}
test = (void*) malloc (sizeof(person));
test->name = "test";
test->age = 0;
test->gender = 't';
while(!GenStackEmpty(&StructStack))
{
GenStackPop(&StructStack, test);
printf("Popped: %s, %d, %c\n", test->name, test->age, test->gender);
}
GenStackDispose(&StructStack);
return 0;
}
And here's the output I get:
./gentest1
elemSize = 16 GenStackInitialAlocationSize = 4
sizeof(person) = 16
Pushed: Alex, 21, m
Pushed: Vanja, 20, m
Pushed: sjrgsde, 11, w
Pushed: wergsggsd, 99, y
New size of alloc = 8
Pushed: adaasxx, 13, g
Popped: adaasxx, 0, t
Popped: wergsggsd, 0, t
Popped: sjrgsde, 0, t
Popped: Vanja, 0, t
Popped: Alex, 0, t
As you can see, I can receive names, but no age or gender. I've tried a lot of options, but still getting Segmentation Fault or the output from above. For moment, the output above is the finest output I get, but still not what I want.
The question is - how can I get the output I need?
Thanks in advance.
To avoid some questions:
sizeof(person) = s->elemSize
It is defined by creating the stack:
genstacklib.c:
void GenStackNew(genStack *s, int elemSize)
{
void* newElems;
/* Allocate a new array to hold the contents. */
newElems = (void*) malloc(elemSize * GenStackInitialAlocationSize);
printf("elemSize = %d\tGenStackInitialAlocationSize = %d\n",
elemSize, GenStackInitialAlocationSize);
if (newElems == NULL)
{
fprintf(stderr, "Error with allocating the stack.\n");
exit(1); /* Exit, returning error code. */
}
s->elems = newElems;
s->elemSize = elemSize;
s->allocLength = GenStackInitialAlocationSize;
s->logLength = 0; /*is empty*/
}
gentest.c:
GenStackNew(&StructStack, sizeof(person));
printf("sizeof(person) = %lu\n", sizeof(person));
your push function is copying sizeof(*elemAddr) and that is a void *, so it has the size of a pointer not the inteded size of a person struct. So you are probably copying only the first 4 bytes
As stated above the push is copying the wrong size of data. It should be elemSize.
The memcpy is also overwriting its own data. Something like this should work.
memcpy((char*) (s->elems)+(s->logLength)*elemSize, elemAddr, elemSize);
s->logLength++;
You're not using elemSize in all the relevant places...
void GenStackPush(genStack *s, const void *elemAddr)
{
...
memcpy((char*) (s->elems)+(s->logLength), elemAddr, sizeof(*elemAddr));
^^^^^^^^^^^^^^^^^
This is very wrong; the type of the expression *elemAddr is void, which is a constraint violation (sizeof may not be called on an expression of incomplete type, and void is an incomplete type). You will want to turn up the warning level on your compiler. I wrote a test program to compute sizeof on expressions of type void * and void, and I get a warning with gcc -pedantic. If I drop the -pedantic I don't get a warning, but the result I get for sizeof (void) is 1, which I'm pretty certain is not the size of a person. Why aren't you using s->elemSize here?
Secondly, why are you casting s->elems to char *?
EDIT
If I may offer some advice, I've womped up a few generic containers in the past, and here are the lessons I've come away with:
First, delegate all type-aware operations (allocation, deallocation, copy, compare, display, etc.) to separate functions, which are called via function pointers passed as parameters to the generic container's functions; i.e., a push would be defined like
GenStackPush(genStack *stack, const void *data, void *(*copy)(const void *))
{
stack->elems[++stack->logLength] = copy(data);
}
...
void *myIntCopyFunc(const void *data)
{
const int *inputData = (const int *) data;
int *copy = malloc(sizeof *copy);
if (copy)
*copy = *inputData;
return copy;
}
...
GenStackPush(&myIntStack, &intVal, myIntCopyFunc);
One issue you have with your person type is that you're not doing a deep copy of the name member; you're just copying a pointer value to the stack. In this case it's not a big deal since you're working with string literals, but if you were using, say, a local char [], you'd have problems. By writing a separate copy function for each type, you can deal with those sorts of issues, instead of trying to do a one-size-fits-all allocation in the container function itself.
Secondly, don't call your generic container functions directly; put a type-aware interface between you and the container (basically, the poor man's version of function overloading):
void pushInt(GenStack *stack, int intVal)
{
GenStackPush(stack, &intVal, myIntCopyFunc);
}
...
genStack myIntStack;
...
pushInt(&myIntStack, 5);
This gives you two benefits; first, it allows you to pass literal values as parameters (which you can't do with parameters of type void *). Secondly, it gives you a way to enforce type safety on your container. You can't accidentally push a value of the wrong type this way.
Is this a lot of extra work? Oh my yes. There's a lot of magic that has to happen under the hood for generic container types to work properly. If you're trying to replicate the same kind of functionality that you get with the C++ std::stack container type, you're going to be writing a lot of code.