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...
Related
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.
I'm actually learning C programming and my school actually doesn't allow us to use calloc / realloc without reprogramming them. That's why I'm asking for help.
Here is my problem :
I want to use void * to make my code reusable but I encounter the problem "dereferencing void * pointer" when I try to run through my array. I'm unable to pick up the type of the final pointer.
Here is my functions :
#include <stdlib.h>
void *my_calloc(size_t size, size_t n) //n = number of bytes your type : sizeof(<whatever>)
{
void *ptr = NULL;
if (size < 1 || n < 1)
return (NULL);
ptr = malloc(n * (size + 1));
if (ptr == NULL)
return (NULL);
for (int i = 0; i != (n * (size + 1)); i++) {
*ptr = NULL; //Here is my problem
ptr++;
}
return (ptr);
}
void *my_realloc(void *src, size_t size, size_t n)
{
void *dst = NULL;
int dst_len = 0;
if (src == NULL || size < 0 || n < 1)
return (NULL);
dst_len = my_strlen(src) + size;
if (dst_len == my_strlen(src))
return (src);
dst = my_calloc(dst_len, n);
if (dst == NULL)
return (NULL);
for (int i = 0; src[i] != NULL;i++)
dst[i] = src[i]; //Here is the same problem...
free(src);
return (dst);
}
I just find a problem while I was writing my post, my my_strlen function can only take a char *... so I would need a function my_strlen looking like :
int my_strlen(void *str)
{
int len = 0;
while (str[len] != NULL) { //same problem again...
len++;
}
return (len);
}
A typical function where i call calloc / malloc would be :
int main(void)
{
char *foo = NULL;
int size = 0;
int size_to_add = 0;
size = <any size>;
//free(foo); //only if foo has been malloc before
foo = my_calloc(size, typeof(*foo));
//something
size_to_add = <any size>;
foo = my_realloc(foo, size_to_add, sizeof(*foo))
//something
free(foo);
return (0);
}
Thank you for trying to help me.
my_calloc() has various troubles:
Attemptted pointer math on a void *
This is undefined behavior (UB).
Instead make ptr a character pointer.
// void *ptr = NULL;
unsigned char *ptr = NULL;
...
ptr++;
Attempt to de-reference a void *
This is also UB.
Instead make ptr a character pointer.
// void *ptr = NULL;
unsigned char *ptr = NULL;
...
// *ptr = NULL;
*ptr = '\0';
my_calloc() allocates more memory than calloc()
To do the same as calloc(), do not add one.
// ptr = malloc(n * (size + 1));
ptr = malloc(n * size);
No overflow protection
my_calloc() does not detect overflow with n * (size + 1). A test is
// Note: it is known n > 0 at this point
if (SIZE_MAX/n > size+1) return NULL;
// or if OP drop the + 1 idea,
if (SIZE_MAX/n > size) return NULL;
my_realloc() has various troubles:
Different signature
I'd expect the goal of "school actually doesn't allow us to use calloc / realloc without reprogramming them" was meant to create a realloc() substitute of which my_realloc() is not. If a different function is desired, consider a new name
void *my_realloc(void *src, size_t size, size_t n)
// does not match
void *realloc(void *ptr, size_t size);
Failure to handle a shrinking allocation
The copying of data does not take into account that the new allocation may be smaller than the prior one. This leads to UB.
Unneeded code
size < 0 is always false
Memory leak
The below code does not free src before returning. Further, it does not allocate anything when n>0. This differs from calloc(pit, 0) and calloc(NULL, 42).
// missing free, no allocation
if (src == NULL || size < 0 || n < 1) {
return (NULL);
}
Assumed string
my_strlen(src) assume src points to a valid string. calloc() does not assume that.
void is an incomplete type, so you can't dereference a void *. What you can do however is cast it to a char * or unsigned char * to access individual bytes.
So my_calloc can do this:
((char *)ptr)[i] = 0;
And my_realloc can do this:
((char *)dst)[i] = ((char *)src)[i];
I tested my software with "valgrind --leak-check=full", and it shows:
==90862== 7,627 bytes in 4 blocks are definitely lost in loss record 858 of 897
==90862== at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==90862== by 0xD64991C: concat(int, ...) (Client.cpp:150)
I can't understand why, because I use free() after calloc.
Here's my code:
char* p = concat(2, buffOld, buff);
char *x;
while(true) {
x = p;
p = strstr(p,"\\final\\");
if(p == NULL) { break; }
*p = 0;
p+=7;
parseIncoming((char *)x,strlen(x));
}
free(p);
And the "concat" function:
char* concat(int count, ...)
{
va_list ap;
int i;
// Find required length to store merged string
int len = 1; // room for NULL
va_start(ap, count);
for(i=0 ; i<count ; i++)
len += strlen(va_arg(ap, char*));
va_end(ap);
// Allocate memory to concat strings
char *merged = (char*)calloc(sizeof(char),len);
int null_pos = 0;
// Actually concatenate strings
va_start(ap, count);
for(i=0 ; i<count ; i++)
{
char *s = va_arg(ap, char*);
strcpy(merged+null_pos, s);
null_pos += strlen(s);
}
va_end(ap);
return merged;
}
What I do wrong?
I can't understand why, because I use free() after calloc
Yes, but (if I understand correctly) you free() the wrong pointer.
You should copy p in another pointer (before modifing it) and free() the save copy.
Look at your code
char* p = concat(2, buffOld, buff);
char *x;
while(true) {
x = p;
p = strstr(p,"\\final\\");
if(p == NULL) { break; }
*p = 0;
p+=7;
parseIncoming((char *)x,strlen(x));
}
free(p);
The pointer p is initialized with the calloc-ed pointer but the while cicle modify it and return only when p is NULL.
So, when you call
free(p)
you're calling
free(nullptr)
--- EDIT ---
I still don't understand it. I added free(x) at the end, and it crashes
My initial suggestion to free(x) was a mistake of mine because I didn't pointed the attention to the fact that x is initializes with the p value but is modified in the while loop. Thanks again to Johnny Mopp for pointing my attention to it.
I suggest the use of another variable to memorize the original value of p (the exact value returned by calloc()) and free this value.
Something like
char* p = concat(2, buffOld, buff);
char *x;
char * const forFree = p; /* <--- saving calloc() returned value */
while(true) {
x = p;
p = strstr(p,"\\final\\");
if(p == NULL) { break; }
*p = 0;
p+=7;
parseIncoming((char *)x,strlen(x));
}
free(forFree);
There is my C code, it is a leetcode problem, and I got "Runtime Error". So I recompile in VS2013, the problem is free(++tmp), why? I can't get it, I writen C code like that, just want to known more things about pointer.
#include <stdio.h>
#include <stdlib.h>
/* Add binary.
* a = "11", b = "1"
* result = "100"
*/
char *add_binary(char *a, char *b);
int main()
{
printf("%s\n", add_binary("10", "1"));
printf("%s\n", add_binary("1111", "1111"));
return 0;
}
char *add_binary(char *a, char *b)
{
int alen = 0, blen = 0, sum = 0;
int len;
char *tmp, *result;
while(*a++) alen++;
while(*b++) blen++;
a -= 2;
b -= 2;
len = alen > blen ? alen : blen;
tmp = (char *)malloc(len*sizeof(char));
printf("%p\n", tmp);
while(*a || *b){
if(*a){
sum += *a - '0' + 0;
a--;
}
if(*b){
sum += *b - '0' + 0;
b--;
}
if(sum > 1){
*tmp++ = 3 == sum ? '1' : '0';
sum = 1;
} else {
*tmp++ = 1 == sum ? '1' : '0';
sum = 0;
}
}
*tmp = '\0';
len += 1 == sum ? 1 : 0;
result = (char *)malloc(len*sizeof(char));
if(1 == sum){
*result++ = '1';
}
while(*(--tmp)){
*result++ = *tmp;
}
*result = '\0';
printf("%p\n", tmp);
free(++tmp);
tmp = NULL;
return (result-len);
}
You can only pass to free the resulting pointer value of malloc:
tmp = (char *)malloc(len*sizeof(char));
then
free(tmp);
is OK.
But free(++tmp) or free(tmp + 42) is not OK and invokes undefined behavior.
Stop modifying the mallocated pointer before freeing it. If you want to use pointer arithmetic, eg '*tmp++', then keep a copy of the original so that the space can be freed.
I have no clue why you would do 'free(++tmp);'. It makes no sense though, by that time, you've already totally shagged up tmp by incrementing it in the while loop:(
Edit: BTW, you've screwed 'result' as well. You are returning a malloced and bodged pointer that cannot be correctly freed by the caller.
Whatever 'clever' thing you are attempting with the pointer manipulations, stop it. It's too easy to get it wrong!
Here is a slightly more detailed response from the other answer.
The pointer is an address for which you allocate memory. When you pass in an address to free that has been previously malloc'd there is no problem. The problem is that you are not passing in the address of a malloc'd space. You are passing in the address of something that is potentially within a malloc'd space and as such cannot be freed.
free expects its argument to be the same pointer value that was returned from a previous malloc or realloc call. If you modify that pointer value before passing it to free, then the behavior is undefined and Bad Things can happen (this is why it appears to work for one platform and breaks on another; in truth, it's broken for both).
You'll need to preserve the pointer values returned from your malloc calls:
char *tmp, *tmpOrig;
...
tmp = tmpOrig = malloc(len * sizeof *tmpOrig); // note no cast, operand of sizeof
...
/**
* modify tmp to your heart's desire
*/
...
free( tmpOrig );
You'll need to do the same thing for result.
You should not cast the result of malloc, unless you are working with a pre-C89 compiler. It's unnecessary, and under C89/C90 compilers can mask a bug.
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.