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.
Related
Say for example I have a function called from main that returns a pointer:
EDIT
: I was a little unclear, sorry! Let's say I used a scanf in the main() and then I passed this into the function, and I wanted to copy the argument into a new pointer then return that one.
main(void)
{
char *word = malloc(50);
scanf("%s", word);
printf("%s", function(word));
}
char *function(char *array)
{
char *a = malloc(50);
while (*array)
{
*a = *array;
a++;
array++;
}
return a;
}
In this case, if I tried to return the pointer array to main, the pointer would be pointing to the memory location 1 space past where my values are held.
How would I make so I can return the pointer to the first value again?
Thanks!
The best way is to not increment your pointers at all:
char *function(char *array)
{
const size_t maxLength = 49;
char * a = malloc(maxLength + 1);
if ( !a ) {
perror("couldn't allocate memory");
exit(EXIT_FAILURE);
}
size_t i;
for ( i = 0; array[i] && i < maxLength; ++i ) {
a[i] = array[i];
}
a[i] = '\0';
return a;
}
Your original code does not null-terminate a, yet you pass it to printf() as if it's a string. Also, you're leaking memory, since you don't store the pointer you're returning, so you can never free() it.
The basic approach is to use a temporary variable to hold the pointer value you want to keep.
Assuming the only one you care about in your example is a.
char *function(char *array)
{
char *a, *t;
t = a = malloc(50);
while (*array)
{
*t = *array;
++t;
++array;
}
*t = '\0'; /* since the caller passes returned pointer to printf() */
return a; /* a unchanged, so return it */
}
Note that the above will have undefined behaviour if strlen(array) >= 50.
In your example, array is passed by value, so changes to it (repeated incrementing) do not propagate to the caller - there is no need to reset array back to its original value.
The best way would be to not use the parameter to the function, but a copy of it inside the function.
char* pTmp = array;
Also it's better to do ++pTmp rather than array++ because for non-POD types it can be quicker.
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...
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.
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?
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;
}