Copying and freeing malloc'ed pointer - c

I'm trying to hunt down memory leaks and have found one source. I am malloc'in the pointer in one function and freeing it in another, but I'm missing out on understanding how to copy the value the pointer points to while also being able to free the pointer.
Current implementation (with memory leak):
// This code has been greatly simplified
// and as such does not appear to have any purpose
int foo(){
int bestval = 0;
char *best;
char *match;
for (int i=0;i<3;i++) {
int returnValue = bar(&best);
if (returnValue > 10) {
(1)
match = best;
}
}
printf("%s", match);
(2)
return 0;
}
int bar(char ** best) {
char*s = "Hello!";
*best = malloc(strlen(s) + 1);
strcpy(*best,s);
return 0;
}
Two questions
If I had to free memory at (1) rather than (2), how would I do it so that match would still have what was contained in best?
Should I be doing strcpy to copy best to match? If so, do I have to do another malloc within foo?

A bit of a stab in the dark, assuming there's a loop in Foo...
int foo()
{
int bestval = 0;
char *best;
char *match = 0; // initialize to null
// start some loop
for (int i=0;i<3;i++) {
// fetch the next best value...
int returnValue = bar(&best);
// some check (if best is really best!)
if (returnValue > 10) {
// if match has previously been populated, free it
if(match) {
free(match);
}
// save the new best value
match = best;
}
else {
// not saving best in match, so free it!
free(best);
}
}
// end some loop
// only do this if match was successful?!?
if(match) {
printf("%s", match);
// clean up once the best of the best has been used...
free(match);
}
return 0;
}

In function bar the strcpy should read as
strcpy(*best,s);
In the main function you can copy the value best points to by
strcpy(match, best);
free(best);
match needs to point to a valid memory block before. If you do a
match = best;
free(best);
match will be invalid too because it points at the same freed memory best pointed.

You need to know the size of the string.
At (1) You would be assigning the address of a memory address that has already been freed, you have to do another malloc to match*=malloc(sizestr) and then copy it with memmove or strcpy if you want to free best.
If I understood properly, you want to copy the string into best, then free bests memory and assign ptr to match? if you free best memory before memmoving or strcpying to another location you lose its contents, and if you want to copy it to another location first you need to allocate the memory where you want to copy it to, so you need 2 mallocs on that code.

If I had to free memory at (1) rather than (2), how would I do it so that match would still have what was contained in best?
If you free at position (1), it is not possible to do it so that match would still have what was contained in best.
Should I be doing strcpy to copy best to match? If so, do I have to do another malloc within foo?
match = best;
With the above statement, both are pointing to the same location. So, there is no need to strcpy at all. To do that, allocate memory for match to point to whose length is best+1 and then do a strcpy.

Copying the value of a pointer does not copy the underlying memory. So either, don't free(best) until you are done with match, or you will need to malloc a new buffer, and e.g. memcpy() the contents from one buffer to the other.

Yes, you can malloc and strcpy:
match = malloc(strlen(best) + 1);
strcpy(match, best);
But, if your implementation provides it you can use the strdup() function which is much easier:
match = strdup(best);
If you don't already have strdup(), it's a good idea to create one yourself.

Your current assignment simply assigns the pointers to the same buffer. If you then free() this buffer, you've removed what is contained here (and thus dereferencing it is a bad idea).
You don't need to use strcpy() to copy best to match - you'll be better off freeing it after the printf() (or the last point that it is needed). There's no point over-complicating things with an extra function call or six, just remember to free() memory that you've allocated at the end of each function!

Related

How to change a function which returns local variable

How should I change the variable BinaryNumber, so the function will not give me a warning message.
I understand that I can't return a address of a local variable cause of the memory. Should I use malloc or what do you think how should I change the variable BinaryNumber so I can return it?
char *Functoin_chang_string_ToBinary(char *Line) {
char *space = " ", *point = ",";
char BinaryNumber[Array_Size] = { "000000000000000" };
char *word = strtok(Line,"\"");
int num = 0, flag = 2, j = 11;
for (int i = 0; i < strlen(Line) - 1; i++) {
if (word[i] == '"') {
flag--;
i++;
}
num = word[i];
j = 14;
while (num != 0) {
BinaryNumber[j--] += (num % 2);
num /= 2;
}
printf("%s\n", BinaryNumber);
Fill_Struct_Binary_Machine_Code("", BinaryNumber);
strcpy(BinaryNumber, "000000000000000");
}
printf("%s\n", BinaryNumber);
Fill_Struct_Binary_Machine_Code("", BinaryNumber);
return BinaryNumber;
}
Although you can use malloc() to allocate a buffer for the BinaryNumber string (which will, of course, need to be released by the caller using free()), a much simpler method would be to use the strdup() function.
This will allocate the exact amount of memory required to duplicate the string given as its argument (including the nul terminator) and copy the actual string data in one call.
Thus, you could just change your function's return statement to this:
return strdup(BinaryNumber);
Of course, the caller will still need to call free() on the returned data when it's done with it (strdup allocates the memory in a manner compatible with the malloc function).
Yes, you can return a pointer to memory allocated by malloc.
Alternatively, you could change the function prototype of Functoin_chang_string_ToBinary to the following:
void Functoin_chang_string_ToBinary(char *Line, char *BinaryNumber );
That way, the calling function can allocate the memory as a local array and pass a pointer to that array to the function Functoin_chang_string_ToBinary, for example like this:
BinaryNumber[Array_Size];
Functoin_chang_string_ToBinary( Line, BinaryNumber );
However, when passing pointers to memory buffers like this, it is also important to make sure that the called function does not write past the boundary of the buffer. For this reason, it would be better if the called function knew the size of the buffer it is being passed. Therefore, you may want to also pass the size of the buffer to the function, by changing the function prototype to the following:
void Functoin_chang_string_ToBinary(char *Line, char *BinaryNumber, int BinaryNumberSize )
The code of the calling function would then be changed to the following:
BinaryNumber[Array_Size];
Functoin_chang_string_ToBinary( Line, BinaryNumber, ArraySize );
That way, the called function can determine how large the memory buffer is, by accessing its third parameter.
Change your function signature to accept a target to save it to:
char *Function_chang_string_ToBinary_r(char *Line, char *out, size_t out_size )
Whenever you do this it is far safer to provide a maximum output size as not to overrun the target. You would also use size sensitive copies for copying to the target limiting copies to the smaller of the target area our your internal working area.
Look at the strtok() vs strtok_r() function for a model for a function that switched to this model to be thread safe.
Yes, malloc() would work but I tend to consider malloc() calls within a function a bad idea, expecialy for short strings. [1] it leaves callers open to memory leaks if they forget to free the memory you allocated and [2] if the function is called frequently malloc() can have a high overhead. Passing in a NULL pointer could make the function call malloc() anyway to return the new address. This way any memory leak or performance bugs would then be on the caller.

how to add a string at the end of pointer to pointer (**pointer) in C

I'm trying to add a string at the end of pointer to pointer in C, I'm using the below code the problem is I can't free what I have allocated as the pointer to pointer has values that were not all allocated memory, How can I add string at the end of a pointer to pointer properly?
int add_environ(char *str, char **envp)
{
char **r;
int i;
r = envp;
i = 0;
while (r[i])
{
i++;
}
//how can I add string without using malloc?
// my problem is I can't free this allocated memory
r[i] = malloc(strlen(str));
if (r[i])
{
r[i] = str;
r[++i] = 0;
return (1);
}
return (0);
}
If your question only targets environmental variables, then I would go with setenv. If not, Waxrat gave you one solution. Oh, btw: You're assuming in your code, that envp is arbitrarily long. That's not true either, so your code will crash sooner or later. Depending on your exact requirements, I would suggest to create a deep copy of envp in main and then only operate on that copy, because then everything is malloced and needs to be freed, so nothing special to track any longer.
You'd need to remember somehow which items in the *envp array came from the heap. For example, by storing them in another array of pointers. There's no real general way to do what you describe, you'd need to do something context specific.

Using realloc to resize a dynamic array

I tried to extend my ful list of players.
When I use the realloc function, it save my player except the last.
I mean that if I had 4 players in my array and I tried to extend my array to 7 I got a new array in size 7 and just 3 players.
This is part of the function:
void initializeListForTree(Player** players, int listSize)
{
int formulaSize = bla bla bla.....
players = (Player **)realloc(players, sizeof(Player *)*formulaSize);
if (!players)
{
printf("memory allocation failed\n");
}
}
More something like:
void initializeListForTree(Player*** players, int listSize)
{
int formulaSize = bla bla bla.....
void *p = realloc(*players, sizeof(Player *)*formulaSize);
if (!p) {
printf("memory allocation failed\n");
}
else {
*players = p;
}
}
and at the call site
Player **playerslist = NULL;
initializeListForTree(&playerslist, 1);
...
initializeListForTree(&playerslist, 2);
etc..
This, of course, only if your type is a pointer to a list of pointers.
No, you cannot change players itself () from initializeListForTree() function. C uses pass by value for function argument passing. Any changes made to player inside initializeListForTree() function won't be reflected to the actual argument used.
If you have to get that done, you'll need to pass a pointer to players.
If you don't mind having an alternate approach, if choose to return the newly
allocated pointer from initializeListForTree() and collect the same into the actual argument passed, then you'll not be needing to pass a pointer-to-pointer-to-pointer.
That said,
Please do not cast the return value of malloc() and family in C.
Please do not store the return value of realloc() directly into the targeted pointer. In case realloc() fails, it will overwrite the valid entry.
Where realloc() find the extend memory:
If there are enough free space after the original memory, then it will use that, and the original address don't change.
If orignal memory is at end of heap/.. , it extend the memory, so the original address don't change.
If original memory is in middle of heap/.., and there is not enough space, then it will allocate a new memory block, and copy your original memory into the new ones, so the address change.
The last case happens with big chance, so you always need to update your address after call realloc().
And the old address might be put into the free memory list, you should not touch it any more. It might be allocated by another malloc()/.. call in future.
And you can see that, realloc() could be heavy, because it might need to copy memory, so improve code to avoid to use it, if possible.
Here is a possible use case (from TLPI):
// nptr is new pointer, ptr is your original pointer,
nptr = realloc(ptr, newsize);
if (nptr == NULL) {
/* Handle error */
} else {
/* realloc() succeeded */
ptr = nptr;
}
Basicly, first check return value to see whether it succeed:
If failed, then original memory remain unchange.
If succeed, assign new address to original pointer.
And, you need to make sure you don't have another pointer that point to middle of original memory, because that would change too, use offset to start address could make things easier.
If your array size change frequently, then you might allocate a bigger memory, remember its size, and reallocate it only when the size is reached, when resize you also give a bigger value than the new value.
You can choose a factor when resize, e.g factor = 1.5, means: new_size = old_size * factor.

Error trying to change contents of string pointer in C

I'm working on a program in C and one of my key functions is defined as follows:
void changeIndex(char* current_index)
{
char temp_index[41]; // note: same size as current_index
// do stuff with temp_index (inserting characters and such)
current_index = temp_index;
}
However, this function has no effect on current_index. I thought I found a fix and tried changing the last line to
strcpy(current_index, temp_index)
but this gave me yet another error. Can anyone spot what I'm doing wrong here? I basically just want to set the contents of current_index equal to that of temp_index at each call of changeIndex.
If more information is needed, please let me know.
strcpy should work if current_index points to allocated memory of sufficient size. Consider the following example, where changeIndex require additional parameter - size of distination string:
void changeIndex(char* current_index, int max_length)
{
// check the destination memory
if(current_index == NULL)
{
return; // do nothing
}
char temp_index[41];
// do stuff with temp_index (inserting characters and such)
// copy to external memory, that should be allocated
strncpy(current_index, temp_index, max_length-1);
current_index[max_length-1] = '\0';
}
Note: strncpy is better for the case when temp_index is longer then current_index.
Examples of usage:
// example with automatic memory
char str[20];
changeIndex(str, 20);
// example with dinamic memory
char * ptr = (char *) malloc(50);
changeIndex(ptr, 50);
Obviously defining a local char array on the stack and returning a pointer to it is wrong. You should never do that as the memory is not defined after the function ends.
In addition to the previous answers: The strncpy char pointer (which seems unsafe for my opinion), and the malloc which is safer but you need to remember to free it outside of the function (and its inconsistent with the hierarchy of the program) you can do the following:
char* changeIndex()
{
static char temp_index[41]; // note: same size as current_index
// do stuff with temp_index (inserting characters and such)
return temp_index;
}
As the char array is static it will not be undefined at the end of the function and you do not need to remember to free the pointer at the end of the use.
Caveat: If you are using multiple thread you cannot use this option as the static memory could be changed by different threads entering the function at the same time
Your array temp_index is local for function, then *current_index don't take what u want.
U can use also function strdup . Function return begin memory location of copied string , or NULL if error occurred, lets say ( char *strdup(char *) )
char temp[] = "fruit";
char *line = strdup(temp );

free memory used to return value in C

I have a function that calls another function which creates a unique ID and returns it as a string by malloc().
my question is how do I free the memory once outside the function? or what is the better way to do what I would like to do.
my function that asks for the ID:
void addCustomer(TennisStoreType* ts){
CustomerNodePtr newcustdata;
int datapos = 0;
newcustdata = malloc(sizeof(CustomerNodeType));
while (datapos <= CUSTDATA_POSITIONS) {
char userinput[BUFFER_SIZE];
switch (datapos) {
case 0:
strcpy(newcustdata->custID, createCustID(ts));
break;
}
}
the function that returns uniqueID:
char* createCustID(TennisStoreType* ts) {
char *custID;
custID = (char *)malloc(CUSTID_LEN + 1 * sizeof(char));
if (ts->customerCount + 1 >= FOURDIGITS) {
sprintf(custID, "C%i\n", ts->customerCount + 1);
} else if (ts->customerCount + 1 >= THREEDIGITS){
sprintf(custID, "C0%i\n", ts->customerCount + 1);
} else if (ts->customerCount + 1 >= TWODIGITS) {
sprintf(custID, "C00%i\n", ts->customerCount + 1);
} else {
sprintf(custID, "C000%i\n", ts->customerCount + 1);
}
return custID;
}
so how would I go about freeing the string that has been copied to newcustdata->custID? do I even need to? or is there a better way to go about doing this?
thanks in advance.
You can eliminate that function entirely. The line
strcpy(newcustdata->custID, createCustID(ts));
can simply be written as
sprintf( newcustdata->custID, "C%04d", ts->customerCount + 1 );
provided, of course that custID is an array of at least 6 characters, e.g.
char custID[8];
Notes:
I typically round char array sizes up to multiples of 8, since structure
padding will waste the bytes anyways.
I removed the \n since it doesn't seem right to have a newline
character in a unique ID, but of course you can add it back in.
If you really like that function, and want to keep it, then replace
switch (datapos) {
case 0:
strcpy(newcustdata->custID, createCustID(ts));
break;
}
with this
char *temp;
switch (datapos) {
case 0:
temp = createCustID(ts);
strcpy(newcustdata->custID, temp);
free( temp );
break;
}
That will free up the memory after the copy.
Your createCustID() function is going to allocate some memory, then return it to the caller, by returning the pointer it got from malloc().
The calling routine, when it is done with the structure, can (and must) free the memory by passing that same pointer to free().
In your example, you need to expand the logic in addCustomer() to retain the pointer it received from createCustID() long enough to (1) test that it is not null, (2) copy the contents locally if needed, and (3) free the received block.
As others have pointed out, you might find it more efficient to just build the received block into the data structure you are assembling, rather than making a copy of it. However, you would still need to free the block as part of your logic for disposing the larger data structure.
You need to plan your code paths carefully with this type of code, so that you always know who "owns" the allocated block, and is responsible for freeing it when it is no longer needed.
Also, you must always check the return value of malloc() against null. If malloc fails to give you the memory you asked for, you need to handle the error appropriately; not just forge ahead writing data into the null pointer.

Resources