Access struct member from pointer - c

I've some problems of segmentation fault with this code:
void init(int max, pile * p) {
p = (pile *)malloc(sizeof(pile));
if(p){
p->nbElemPresent = 0;
p->maxElem = max;
p->tete = (data *)malloc(max * sizeof(data));
}
}
short int vide(pile * p) {
if(p->maxElem == 0) {return 1;}
return 0;
}
my function vide return me segfault.. I don't know how to access to struct member from the p pointer.
The main program:
pile * p;
init(5, p);
printf("%d", vide(p));
ty.

as already said, p is a new variable in your init function. other than the other answers suggested, i'd rather suggest not taking p as an argument at all, but instead returning it:
pile* init(int max) {
pile *p = (pile *)malloc(sizeof(pile));
...
return p;
}
and in your main function:
pile * p = init(5);
printf("%d", vide(p));

C takes parameters by value, that means that pointer p is copied when you pass it to init().
p in the function is a completely new variable and if its value is changed that doesn't change the value of p passed to the function.
You should pass its address:
init(5, &p);
void init(int max, pile** p) {
*p = malloc(sizeof(pile));
if(*p){
(*p)->nbElemPresent = 0;
....
}
}
Note the unusual parenthesis (*p)->nbElemPresent, this is done because -> operator has a higher precedence, yet we want to dereference the p first.

As said by barak manos, your problem lies in init. C pass parameters by value so let's imagine :
you set a pointer to pile to NULL (pile *p = NULL;)
you pass it to init (init(p);)
in init you alloc a pile and affect is to the local copy of p
on return from init, p is still NULL and you have a memory leak since you have no longer any pointer to the allocated pile
That's the reason why you should write :
void init(int max, pile ** p) {
pile *lp = *p = (pile *)malloc(sizeof(pile));
if(*p){
lp->nbElemPresent = 0;
lp->maxElem = max;
lp->tete = (data *)malloc(max * sizeof(data));
}
}
Now you use :
pile *p;
init(&p);
and on return p points to the allocated pile.

Related

Segmentation Fault while malloc and sizeof

Sorry if I'm offending anyone but I started learning C this week and I got a segmentation fault while compiling this. Can I please have a second pair of eyes to help me with this error?
void Space(void *empty, size_p s)
{
empty = malloc(s);
}
int main()
{
int *p = NULL;
Space(p, sizeof(p));
*p = 7;
return;
}
empty is just a pointer variable - it contains "some" address, but it is still a local variable in the context of Space. If you want to update the value of int *p in Space, you'll need to pass a pointer to it:
int main()
{
int *p = NULL;
Space(&p, sizeof *p);
*p = 7;
return;
}
void Space(void **empty, size_p s)
{
*empty = malloc(s);
}
Also, you have a bug where you call Space: Space(p, sizeof(p));
sizeof(p) is the size of the int * variable but you want to allocate the size of an int as that's what you're storing in p. So that line should instead be:
Space(&p, sizeof *p);
void * Space(void *empty, size_t s)
{
empty = malloc(s);
return empty;
}
int main()
{
int *p = NULL;
p = Space(p, sizeof(int));
*p = 7;
return 0;
}
You can change the Space function to return a void * or an int *. The variable empty is a copy of the pointer in main. When you change the value in Space, because it is a copy, the change never makes it back to main.
I changed sizeof(p) to sizeof(int). This is more of personal preference but I try to only give types as the argument to sizeof. You can get surprising results when you apply sizeof to variables.
I really like #DIMMSum's answer but I know pointer-to-a-pointer can be confusing especially when starting out.

How can I allocate memory for array inside a function

I am trying to receive a number from the user.
And create an array with that number, but, inside a function.
Here are my few attempts, I get into run time errors.
Help is very much appreciated.
#include <stdio.h>
#include <stdlib.h>
int* Init(int* p, int num);
int main() {
int *p;
int num, i;
puts("Enter num of grades:");
scanf("%d", &num);
Init(&p, num);
//for (i = 0; i < num; i++)
//{
// scanf("%d", &p[i]);
//}
free(p);
}
int* Init(int* p, int num)
{
int *pp;
p = (int *)malloc(num*sizeof(int));
if (!pp)
{
printf("Cannot allocate memory\n");
return;
}
p = pp;
free(pp);
}
You have done well upto the point you understood you need to pass a pointer to pointer. But your function signature doesn't take an int **. Either you pass a pointer to pointer and store the allocated memory in it:
void Init(int **pp, int num)
{
int *p;
p = malloc(num*sizeof(int));
if (!p)
{
printf("Cannot allocate memory\n");
}
*pp = p;
}
And check if the Init() returns a proper pointer:
Init(&p, num);
if(p == NULL) {
/*Memory allocation failed */
}
Or allocate memory and return the pointer:
int* Init(int num)
{
int *p;
p = malloc(num*sizeof(int));
if (!p)
{
printf("Cannot allocate memory\n");
}
return p;
}
and from main() call as:
int * p = Init(num);
if(p == NULL) {
/*Memory allocation failed */
}
Change the prototype of Init() accordingly.
In any case, you must not free() the pointer in Init(). That just de-allocates memory immediately and you'll be left with a dangling pointer.
And you need to free() in the main() after you are done with it.
int *pp;
p = (int *)malloc(num*sizeof(int));
if (!pp) /* pp is used uninitialized at this point */
int *p;
int num, i;
puts("Enter num of grades:");
scanf("%d", &num);
Init(&p, num);
free(p); /* p is used uninitialized at this point */
If you want to allocate space for a pointer to int inside another function, you need to pass a pointer to pointer:
...
Init(&p, num);
...
int Init(int **pp, int num)
{
*pp = malloc(num * sizeof(int));
...
First you need to fix the prototype of your function. It should be
int* Init(int** p, int num);
Then fix the function definition
int* Init(int** p, int num)
{
//int *pp; // You don not need this variable
*p = malloc(num*sizeof(int)); // Allocate memory
if (!*p)
{
printf("Cannot allocate memory\n");
return NULL; // Return a NULL pointer
}
return *p;
}
Some typos in your code,
p = (int *)malloc(num * sizeof(int));
should be
pp = (int *)...
Your free(pp); is what is causing it to not work chiefly, you do not want to call that or the memory you allocated will not be saved. Also the memory of pp is essentially "lost" at the end of the function call as method parameter to Init p is a value copy not exact reference to main's version of p, thus when Init returns, the changes to p are 'lost'.
simply do: p = Init(); and in init return pp;
Exp:
This line p = pp, sets variable p to point to the memory allocated by pp, thus a free of pp is a free to p as well.
I am not sure if returning an address to memory is always considered good practice, as you have to ensure it is freed, but for your program it would work.
It's very important to know that your function doesn't modify your pointer (*p),The **p is lost And *p doesn't have a valid and known memory address in the Main function.
To allocate the memory safely I suggest these two functions.
void init(int **p,int number){
*p = malloc(number*sizeof(int));
}
If you want that your function returns the pointer allocated you can do this:
int* init(int number){
int* p = malloc(number*sizeof(int));
return p;
}

Converting old C code

I have this code snippet in project source code which I work on
void func(void **p,size_t s)
{
*p = malloc(s+sizeof(size_t));
*(((size_t *)(*p))++) = s;
}
and gcc-4.7 does not compile it. gcc returns
lvalue required as increment operand
error message. I changed it into
stp = ((size_t *)(*p));
*(stp ++) = s;
and
stp = ((size_t *)(*p));
*stp = *stp + 1;
*stp = s;
gcc compiles both of them. But application does not work expected.
Is conversion true? And is there any tool for conversion?
The idea seems to be to allocate a certain amount of memory (s) and an additional amount to store this size allocated in the same area as a leading block and then return a pointer to just behind the stored size.
So try this:
void func(void ** p, size_t s)
{
size_t * sp = malloc(s + sizeof s);
if (NULL != sp)
{
*sp = s;
++sp;
}
*p = sp;
}
Btw, freeing the allocated memory, is not straight forward.
A typicall sequence of calls, also freeing what this function returns, would look like this then:
void * pv = NULL;
func(&pv, 42);
if (NULL != pv)
{
/* Use 42 bytes of memory pointed to by pv here. */
free(((char *) pv) - sizeof (size_t));
}
*(((size_t *)(*p))++) = s;
Breakdown:
*(
(
(size_t *) (*p)
) ++
) = s
Means : Take *p as a pointer to size_t (let's call that ptr for after), dereference it (= take the size_t typed value at the address *p), assign that value to s and finally increment ptr (which is to say increment the address in *p by the sizeof(size_t).
You can translate that to:
size_t *ptr = (size_t*)(*p); //second pair of paren is optionnal
s = *ptr;
ptr = ptr + 1; //Warning: This will only modify the variable ptr and not
//the data at its original place *p, if the remainder of
//the program is based on that (which I highly suspect)
//you should do instead :
(size_t*)*p = (size_t*)(*p) + 1; //This also ensures "+1" is treated as
//"add the sizeof(size_t)" because *p
//points to a size_t typed variable
You could also retype a variable and have it point at the same location as p and be done with the casts:
void func(void **p,size_t s)
{
size_t **ptr = p;
*ptr = malloc(s+sizeof(size_t));
if (*ptr == NULL) etc...
*((*ptr)++) = s;
}
func2() : Adding a variable can increase readability, IMHO. (and inlining will get rid of it, afterwards)
The second function func3() demonstrates that using the return value instead of passing a (opaque) pointer by reference can avoid complexity and casts
#include <stdio.h>
#include <stdlib.h>
void func2(void **p,size_t s)
{
size_t **pp;
pp = (size_t **) p; // only one cast
*pp = malloc(s+sizeof(size_t));
if (!*pp) return;
fprintf(stderr,"[mallocd %p]", *pp);
*pp[0] = s;
*pp += 1;
}
void *func3(size_t s)
{
size_t *p;
p = malloc(s+sizeof *p);
if (!p) return NULL;
fprintf(stderr,"[mallocd %p]", p);
p[0] = s;
return p+1;
}
int main(void)
{
char *p = NULL , *p2 = NULL;
func2( (void**) &p, 666); // yet another cast
fprintf(stderr,"returned p := %p\n", p);
p2 = func3( 666); // No cast!!!
fprintf(stderr,"returned p2 := %p\n", p2);
return 0;
}
try
void func(void **p,size_t s)
{
*p = malloc(s+sizeof(size_t));
*(*(size_t **)p)++ = s;
}
This is allocating s bytes of memory, plus enough extra to hold s, storing s at the start of that space and modifying *p to point just after that.
More sensible and clearer (and avoiding casts!) would be:
void *func(size_t s)
{
size_t *p = malloc(s + sizeof(size_t));
if (p) *p++ = s;
return p;
}
but that requires changing the code that calls this function to take the return value and store it wherever desired, rather than passing an extra pointer as an argument:
some_ptr = func(needed_size);
rather than
func((void **)&some_ptr, needed_size);
also avoiding casts...

Returning a pointer from a function

This is in reference to this question: Why is a pointer to pointer needed to allocate memory in this function?
The answer to the question explained why this didn't work:
void three(int * p)
{
p = (int *) malloc(sizeof(int));
*p = 3;
}
void main()
{
int *p = 0;
three(p);
printf("%d", *p);
}
... but this works:
void three(int ** p)
{
*p = (int *) malloc(sizeof(int));
**p = 3;
}
void main()
{
int *p = 0;
three(&p);
printf("%d", *p);
}
This also works, by returning a pointer from the function. Why is that?
int* three(int * p)
{
p = (int *) malloc(sizeof(int));
*p = 3;
return p;
}
void main()
{
int *p = 0;
p = three(p);
printf("%d", *p);
}
int* three(int * p)
{
p = (int *) malloc(sizeof(int));
*p=3;
return p;
}
Because here you're returning a copy of the pointer p and this pointer now points to valid memory, which contains the value 3.
You originally passed in a copy of your p as an argument, so you're not changing the one you passed in, but a copy. Then you return that copy, and assign it.
From the comment, which is a very valid point, this will also work just as well:
int* three()
{
//no need to pass anything in. Just return it.
int * p = (int *) malloc(sizeof(int));
*p=3;
return p;
}
They're completely different (and if you truly understand why the first works, you'd see there's no connection).
By returning, you're not attempting to modify the already existing pointer from inside the function. You're just returning a new pointer, and assigning its value outside.
Look at it as a question of scope.
In main() you have a pointer p.
int *p = 0;
p in main is set to NULL. When you make a call to the three function passing it p:
three(p);
You are passing a pointer to NULL. What happens to it is outside the scope of main(). main() does not know, nor does it care what happens. main() only cares about its copy of p, which at this point is still set to NULL.
Unless I reassign p within the scope of main() (including handing off the address of p), p is still just a pointer pointing to NULL.
If I give you this code:
void main()
{
int *p = 0;
funcX(p);
printf("%d",*p);
}
You can tell me definitively what is going to happen (Segmentation fault) without ever knowing what funcX() does because we're passing a copy of the pointer to this function, but a copy doesn't affect the original.
But if I give you this code:
void main()
{
int *p = 0;
funcX(&p);
printf("%d",*p);
}
You can't tell me what will happen unless you know what funcX() is doing.
That make sense?

Why I've allocated a pointer memory in a function, but it's also NULL?

The code confused me.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void create_int(int *p)
{
p = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
create_int(p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
You are not passing the pointer value back from the function. Try:
void create_int(int **p) {
*p = (int *) malloc(sizeof(int));
}
int main() {
int *p = NULL;
create_int(&p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
The variable p in the function create_int is a copy of the variable p in main. So any changes made to p in the called function does not get reflected in main.
To make the change get reflected in main you need to either:
Return the changed value:
int* create_int(int *p) {
p = malloc(sizeof(int));
// err checking
return p:
}
...
// in main:
p = create_int(p);
Or pass the address of p as:
void create_int(int **p) {
*p = malloc(sizeof(int));
// err checking
}
...
// in main:
create_int(&p);
You need a pointer to a pointer like this:
void create_int(int **p)
{
*p = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
create_int(&p);
assert(p != NULL); /* failed. why? I've allocated memory for it. */
return 0;
}
As folks have pointed out, it's failing since you're not actually changing the pointer that the caller has.
A different way to think about the code might be to notice that it's basically wrapping malloc(), i.e. it's doing a memory allocation but with intelligence added. In that case, why not make it have the same prototype (=call signature) as malloc()? That makes it clearer in the caller's context what's going on, and easier to use:
int * create_int(void)
{
return malloc(sizeof (int));
}
int main(void)
{
int *p = create_int();
assert(p != NULL);
return 0;
}
Also, in C you should never cast the return value of malloc() (see Do I cast the result of malloc?).
You need to send a pointer to a pointer to be able to assign a memory to it via a function
void create_int(int **p)
{
*p = (int*)malloc(sizeof_int));
}
int main()
{
int* p = NULL;
create_int(&p);
assert(p != NULL);
return 0;
}
Your code contains two pointers: one in the create_int function and another one in main. When you call create_int, a copy of the pointer in main is made and used, then eliminated when the create_int function returns.
So, any changes you did to the copy within create_int remain there and are not propagated back to main.
The only way to propagate changes between functions in C (aside from, obviously, returning new values) is to pass a pointer to the changed values. This way, while the pointer being passed will be copied, the value that it points to will be the same, so changes will apply.
Since you're trying to change a pointer, you need a pointer-to-pointer.
void create_int(int **pp)
{
// this changes the pointer that `p` points to.
*pp = (int *) malloc(sizeof(int));
}
int main()
{
int *p = NULL;
// this sends a pointer to the pointer p in main
create_int(&p);
assert(p != NULL);
return 0;
}

Resources