Freeing memory in the caller that is reallocated by the callee? - c

Here is my situation:
main allocates memory based on string and calls function by passing an address. The function then appropriately resizes the passed memory to accommodate more data. After which when I try to release the memory I get heap error.
Here is the code:
typedef char * string;
typedef string * stringRef;
/**************************
main
**************************/
int main()
{
string input = "Mary had";
string decoded_output = (string)calloc(strlen(input), sizeof(char));
sprintf(decoded_output, "%s", input);
gen_binary_string(input, &decoded_output);
free(decoded_output); /*this causes issue*/
return 0;
}
void gen_binary_string(string input,stringRef output)
{
int i=0, t=0;
size_t max_chars = strlen(input);
/*
the array has to hold total_chars * 8bits/char.
e.g. if input is Mary => array size 4*8=32 + 1 (+1 for \0)
*/
string binary_string = (string)calloc((BINARY_MAX*max_chars) + 1, sizeof(char));
int offset = 0;
/* for each character in input string */
while (*(input+i))
{
/* do some binary stuff... */
}
/* null terminator */
binary_string[BINARY_MAX*max_chars] = '\0';
int newLen = strlen(binary_string);
string new_output = (string) realloc((*output), newLen);
if (new_output == NULL)
{
printf("FATAL: error in realloc!\n");
free(binary_string);
return;
}
strcpy(new_output, binary_string);
(*output) = new_output;
free(binary_string);
}

You may be misunderstanding the purpose of realloc. Calling realloc will not necessarily return a newly allocated object. If possible, it will return the same object, extended to hold more bytes. Also, it automatically copies the object's contents. Theferore: (1) you should not copy and (2) you should not free the old buffer.
The realloc() function changes the size of the memory block pointed
to by ptr to size bytes. The contents will be unchanged in the range
from the start of the region up to the minimum of the old and new
sizes... (snip) Unless ptr is NULL, it must have been returned by an
earlier call to malloc(), calloc() or realloc(). If the area
pointed to was moved, a free(ptr) is done.
After a better reading of your code, I don't understand why you're using realloc at all here, as you're not using the old contents of output. You'd get the same behaviour (and the same error) if you replaced realloc with malloc. I think your real problem is that you're not allocating enough bytes: you should have strlen(binary_string) + 1 to accommodate the '\0' at the end of the string.

A better option would be to pass in a char** from the caller, let the callee allocate the char* and then pass back the pointer at the end of the function.
This prevents the need for two allocations and one free (always a bad sign).

Related

Differences between allocating memory spaces for a string based on the size of its characters vs. the size of the entire string

When we allocating memory spaces for a string, do the following 2 ways give the same result?
char *s = "abc";
char *st1 = (char *)malloc(sizeof(char)*strlen(s));
char *st2 = (char *)malloc(sizeof(s));
In other words, does allocate the memory based on the size of its characters give the same result as allocating based on the size of the whole string?
If I do use the later method, is it still possible for me to add to that memory spaces character by character such as:
*st = 'a';
st++;
*st = 'b';
or do I have to add a whole string at once now?
Let's see if we can't get you straightened out on your question and on allocating (and reallocating) storage. To begin, when you declare:
char *s = "abc";
You have declared a pointer to char s and you have assigned the starting address for the String Literal "abc" to the pointer s. Whenever you attempt to use sizeof() on a_pointer, you get sizeof(a_pointer) which is typically 8-bytes on x86_64 (or 4-bytes on x86, etc..)
If you take sizeof("abc"); you are taking the size of a character array with size 4 (e.g. {'a', 'b', 'c', '\0'}), because a string literal is an array of char initialized to hold the string "abc" (including the nul-terminating character). Also note, that on virtually all systems, a string literal is created in read-only memory and cannot be modified, it is immutable.
If you want to allocate storage to hold a copy of the string "abc", you must allocate strlen("abc") + 1 characters (the +1 for the nul-terminating character '\0' -- which is simply ASCII 0, see ASCII Table & Description.
Whenever you allocate memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. So if you allocate for char *st = malloc (len + 1); characters, you do not want to iterate with the pointer st (e.g. no st++). Instead, declare a second pointer, char *p = st; and you are free to iterate with p.
Also, in C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?.
If you want to add to an allocation, you use realloc() which will create a new block of memory for you and copy your existing block to it. When using realloc(), you always reallocate using a temporary pointer (e.g. don't st = realloc (st, new_size);) because if when realloc() fails, it returns NULL and if you assign that to your pointer st, you have just lost the original pointer and created a memory leak. Instead, use a temporary pointer, e.g. void *tmp = realloc (st, new_size); then validate realloc() succeeds before assigning st = tmp;
Now, reading between the lines that is where you are going with your example, the following shows how that can be done, keeping track of the amount of memory allocated and the amount of memory used. Then when used == allocated, you reallocate more memory (and remembering to ensure you have +1 bytes available for the nul-terminating character.
A short example would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define THISMANY 23
int main (void) {
char *s = "abc", *st, *p; /* string literal and pointer st */
size_t len = strlen(s), /* length of s */
allocated = len + 1, /* number of bytes in new block allocated */
used = 0; /* number of bytes in new block used */
st = malloc (allocated); /* allocate storage for copy of s */
p = st; /* pointer to allocate, preserve st */
if (!st) { /* validate EVERY allocation */
perror ("malloc-st");
return 1;
}
for (int i = 0; s[i]; i++) { /* copy s to new block of memory */
*p++ = s[i]; /* (could use strcpy) */
used++; /* advance counter */
}
*p = 0; /* nul-terminate copy */
for (size_t i = 0; i < THISMANY; i++) { /* loop THISMANY times */
if (used + 1 == allocated) { /* check if realloc needed (remember '\0') */
/* always realloc using temporary pointer */
void *tmp = realloc (st, 2 * allocated); /* realloc 2X current */
if (!tmp) { /* validate EVERY reallocation */
perror ("realloc-st");
break; /* don't exit, original st stil valid */
}
st = tmp; /* assign reallocated block to st */
allocated *= 2; /* update allocated amount */
}
*p++ = 'a' + used++; /* assign new char, increment used */
}
*p = 0; /* nul-terminate */
printf ("result st : %s\n" /* output final string, length, allocated */
"length st : %zu bytes\n"
"final size : %zu bytes\n", st, strlen(st), allocated);
free (st); /* don't forget to free what you have allocated */
}
Example Use/Output
$ ./bin/sizeofs
result st : abcdefghijklmnopqrstuvwxyz
length st : 26 bytes
final size : 32 bytes
Look things over and let me know if this answered your questions, and if not, leave a comment and I'm happy to help further.
If you are still shaky on what a pointer is, and would like more information, here are a few links that provide basic discussions of pointers that may help. Difference between char pp and (char) p? and Pointer to pointer of structs indexing out of bounds(?)... (ignore the titles, the answers discuss pointer basics)

How to copy the values of an array of char pointers?

How do I copy the values in an array of char pointers into another array? I am really lost please help me out. This is what I have so far.
char **copy_values(char **values) {
char **val;
//do something
return val;
}
To fully copy the pointers and values (what they point to), you need to know three things:
How many pointers do I have?
Do I need to also copy the things they point to?; and if so
How many pointers do I have that point to something I need to copy.
When you declare a pointer to pointer to char, it is simply an uninitialized pointer. To provide the ability to address more than a single address, you then allocate some needed number of pointers (say MAXPTRS). For instance:
#define MAXPTRS 32
...
char **values = NULL;
values = malloc (MAXPTRS * sizeof *values); /* allocate MAXPTRS pointers */
if (values == NULL) { /* validate/handle error */
perror ("malloc-values");
/* handle error */
}
You now have MAXPTRS (32) pointers to work with. If you then allocate storage for say 8 of them, e.g.
size_t count = 0;
while (fgets (buf, sizeof buf, stdin)) {
size_t len = strlen (buf);
values[count] = malloc (len + 1);
if (!values[count]) {
perror ("malloc-values[count]");
break;
}
memcpy (values[count++], buf, len + 1);
}
So at this point in the example, you have 32 pointers allocated and 8 of those pointers pointing to blocks of memory holding strings read from stdin.
If you then want to copy the entire structure, you must not only copy the original 32 pointers, but also the 8 blocks of memory the initialized pointers point to. If you fail to copy the blocks of memory pointed to and simply assign pointers (e.g. val[i] = values[i]), then any changes to the original, e.g. values[2] will automatically be reflected in val[2] (this may, or may not, be what you want)
To fully copy your values pointer to pointer to char and return val containing the same number of pointers with a copy of each string allocated and contained in the original values array of pointers, you would need a "deep copy" where you copy not only the pointers, but duplicate the contents as well, e.g.
char **copystrings (const char **values, size_t nptrs, size_t filled)
{
char **val = NULL;
val = malloc (nptrs * sizeof *val); /* allocate nptrs pointers */
if (!val) { /* validate */
perror ("malloc-val");
return NULL;
}
for (size_t i = 0; i < filled; i++) { /* loop over each filled ptr */
size_t len = strlen (values[i]); /* get length of string */
val[i] = malloc (len + 1) /* allocate storare val[i] */
if (!val[i]) { /* validate */
perror ("malloc-val[i]");
break;
}
memcpy (val[i], values[i], len + 1); /* copy to val[i] */
}
return val; /* return val (may contain less than filled allocated) */
}
(note: not compiled, also it would be advisable to pass filled as a pointer and update filled with the value of i before returning to provide a means of validating that all blocks of memory for filled pointers were duplicated. Otherwise, a malloc failure of val[i] would result in less than filled being allocated and copied and no way to tell -- unless you used calloc to zero the new memory when you allocate for val)
A deep copy allows you to modify the copied values without altering the data at the addresses pointed to by the pointers in values. If you are not modifying the data (e.g. you simply want to sort the pointers with qsort, then there is no need for a "deep copy" and you need only allocate for the filled number of pointers and assign the address from values to val.
Understanding what you need and the differences in how you go about achieving it is key.
(thanks to #4386427 for catching a couple of omissions)
How do I copy the values in an array of char pointers into another array?
Something like:
char **copy_values(char **values, int size) {
char **val = malloc(size * sizeof *val);
if (val) memcpy(val, values, size * sizeof *val);
return val;
}
Remember to free the allocated memory when done with it

how to free the dynamically allocated memory for a local variable?

Sample program:
#include <stdio.h>
#include <malloc.h>
void f(int n) {
char *val = (char *) malloc(12*sizeof(char));
val = "feels....";
printf("%s", val);
// free val; // if enable, compile time error: expected ';' before 'val' free val;
}
int main()
{
f(1);
return 0;
}
Is it required to free the memory which is dynamically allocated ? if yes, how to.
Yes, you need to free the memory. But when you allocate memory for a string, the way to populate the string is not to assign a string to it as that replaces the memory you've allocated. Instead you're meant to use the function strcpy like this...
char *val = malloc(12*sizeof(char));
strcpy(val,"feels....");
printf("%s", val);
free(val);
Instead of this:
char *val = (char *) malloc(12*sizeof(char));
val = "feels...."; // val points now to the string literal ""feels...."
// discarding the value returned by malloc
...
free(val); // attempt to free the string literal which will
// result in undefined behaviour (most likely a crash)
you probably want this:
char *val = malloc(12*sizeof(char)); // in C you don't cast the return value of malloc
strcpy(val, "feels...."); // the string "feels...." will be copied into
// the allocated buffer
...
free(val); // free memory returned previously by malloc
The compilation problem is because free is a function, you need to put its argument in parentheses.
free(val);
The other problem is a memory leak.
Strings in C are really just pointers to (hopefully) blocks of memory containing char data. The end of the string is denoted by a char with value 0. The thing to remember is that your variable is simply a pointer like any other pointer. So...
char *val = (char *) malloc(12*sizeof(char));
The above line dynamically allocates a block of memory and assigns a pointer to it to val.
val = "feels....";
The above line assigns a pointer to a string literal to val overwriting the previous pointer that was in val. It has not touched, in any way, the block of memory that was malloced in the first line. Furthermore, you have lost any reference you had to the malloced block so it has leaked. There's no way to free it.
String literals are usually created at compile time and the memory they occupy will be part of the program. This means they haven't come from the heap (where malloc gets its memory from. This means, in turn, when you try to free a string literal, bad things happen. On modern architectures, the program text is protected from writes at the OS level so trying to free part of it will almost certainly crash your program.
As long as you do not want to change the content of the string, you do not need to malloc space to it. You can omit the malloc line (and the corresponding free) and your program will still work.
f you do want to change the string, the easiest way to get a mutable copy of a string literal is to use strdup:
char *val = strdup("feels....");
// Do stuff with the string
free(val); // strdup strings need to be freed
strdup is a Posix function but not a C standard function so your platform might not have it. It's pretty simple to implement your own, though.
char* myStrDup(const char* thingToDup)
{
char* ret = malloc(strlen(thingToDup) + 1); // strlen returns the length without the terminating nul. Hence add 1 to it to allocate
strcpy(ret, thingToDup); // Copies the entire string including the terminating nul.
return ret;
}

Add zeros to String in C

I want to add zeroes in front of a string with this method:
void addFrontzeros(char *str,int zeros)
{
if(zeros==0)
{
return;
}
char *temp=malloc((strlen(str)+1+zeros)*sizeof(char));
int i=0;
for(;i<zeros;i++)
{
temp[i]='0';
}
int j=0;
for(;j<strlen(str);j++)
{
temp[j+zeros]=str[j];
}
temp[strlen(str)+zeros]=0;
str=realloc(str,(strlen(temp)+1)*sizeof(char));
strcpy(str,temp);
free(temp);
}
But when i call it from another Method the string is empty after the invocation.
The caller string is allocated like this in another method:
char *mul = malloc(sizeof(char)*2);
mul[0]='0';
mul[1]=0;
With valgrind i got this error:
Address 0x5201b00 is 0 bytes inside a block of size 2 free'd
I think the problem is with realloc , but i don't have an idea why it wont work here
By calling realloc you're (possibly) modifying str inside the function, but the caller of addFrontzeros doesn't see the new value of str. It still has the old version of str which no longer points to valid data after the realloc.
Your function should either return str (so that it can be called as x = addFrontzeros(x, n)) or accept a char ** so that it can modify the pointer in place.
As pointed out by StoryTeller, str = realloc(str, ...) is unsafe in the case where realloc fails. First, because you're not testing whether realloc returned NULL, and second, because if it does return NULL, you have a memory leak because the old str is still allocated but you've lost your pointer to it. A minimal way to handle it would be
char *new_str = realloc(str, strlen(temp)+1);
if (!new_str) {
perror("addFrontzeros: realloc");
} else {
str = new_str;
}
although if you want to handle the failure in some other way, you can, and the original str will still be valid and unmodified.
Another problem is that you only copy strlen(str) bytes, which doesn't include the terminating zero byte, so your string is not correctly terminated. Either add the terminating zero yourself, or simply copy one more byte (since you can assume str is correctly terminated to start with).
Finally, as a side note, sizeof(char) is 1 by definition, so multiplying by it is unnecessary.

What does memcpy do exactly in this program?

I am writing a program where the input will be taken from stdin. The first input will be an integer which says the number of strings to be read from stdin.
I just read the string character-by-character into a dynamically allocated memory and displays it once the string ends.
But when the string is larger than allocated size, I am reallocating the memory using realloc. But even if I use memcpy, the program works. Is it undefined behavior to not use memcpy? But the example Using Realloc in C does not use memcpy. So which one is the correct way to do it? And is my program shown below correct?
/* ss.c
* Gets number of input strings to be read from the stdin and displays them.
* Realloc dynamically allocated memory to get strings from stdin depending on
* the string length.
*/
#include <stdio.h>
#include <stdlib.h>
int display_mem_alloc_error();
enum {
CHUNK_SIZE = 31,
};
int display_mem_alloc_error() {
fprintf(stderr, "\nError allocating memory");
exit(1);
}
int main(int argc, char **argv) {
int numStr; //number of input strings
int curSize = CHUNK_SIZE; //currently allocated chunk size
int i = 0; //counter
int len = 0; //length of the current string
int c; //will contain a character
char *str = NULL; //will contain the input string
char *str_cp = NULL; //will point to str
char *str_tmp = NULL; //used for realloc
str = malloc(sizeof(*str) * CHUNK_SIZE);
if (str == NULL) {
display_mem_alloc_error();
}
str_cp = str; //store the reference to the allocated memory
scanf("%d\n", &numStr); //get the number of input strings
while (i != numStr) {
if (i >= 1) { //reset
str = str_cp;
len = 0;
}
c = getchar();
while (c != '\n' && c != '\r') {
*str = (char *) c;
printf("\nlen: %d -> *str: %c", len, *str);
str = str + 1;
len = len + 1;
*str = '\0';
c = getchar();
if (curSize/len == 1) {
curSize = curSize + CHUNK_SIZE;
str_tmp = realloc(str_cp, sizeof(*str_cp) * curSize);
if (str_tmp == NULL) {
display_mem_alloc_error();
}
memcpy(str_tmp, str_cp, curSize); // NB: seems to work without memcpy
printf("\nstr_tmp: %d", str_tmp);
printf("\nstr: %d", str);
printf("\nstr_cp: %d\n", str_cp);
}
}
i = i + 1;
printf("\nEntered string: %s\n", str_cp);
}
return 0;
}
/* -----------------
//input-output
gcc -o ss ss.c
./ss < in.txt
// in.txt
1
abcdefghijklmnopqrstuvwxyzabcdefghij
// output
// [..snip..]
Entered string:
abcdefghijklmnopqrstuvwxyzabcdefghij
-------------------- */
Thanks.
Your program is not quite correct. You need to remove the call to memcpy to avoid an occasional, hard to diagnose bug.
From the realloc man page
The realloc() function changes the size of the memory block pointed to
by ptr to size bytes. The contents will be unchanged in the range
from the start of the region up to the minimum of the old and new
sizes
So, you don't need to call memcpy after realloc. In fact, doing so is wrong because your previous heap cell may have been freed inside the realloc call. If it was freed, it now points to memory with unpredictable content.
C11 standard (PDF), section 7.22.3.4 paragraph 2:
The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size. The contents of the new object shall be the same as that of the old object prior to deallocation, up to the lesser of the new and old sizes. Any bytes in the new object beyond the size of the old object have indeterminate values.
So in short, the memcpy is unnecessary and indeed wrong. Wrong for two reasons:
If realloc has freed your previous memory, then you are accessing memory that is not yours.
If realloc has just enlarged your previous memory, you are giving memcpy two pointers that point to the same area. memcpy has a restrict qualifier on both its input pointers which means it is undefined behavior if they point to the same object. (Side note: memmove doesn't have this restriction)
Realloc enlarge the memory size where reserved for your string. If it is possible to enlarge it without moving the datas, those will stay in place. If it cannot, it malloc a lager memory plage, and memcpy itself the data contained in the previous memory plage.
In short, it is normal that you dont have to call memcpy after realloc.
From the man page:
The realloc() function tries to change the size of the allocation pointed
to by ptr to size, and returns ptr. If there is not enough room to
enlarge the memory allocation pointed to by ptr, realloc() creates a new
allocation, copies as much of the old data pointed to by ptr as will fit
to the new allocation, frees the old allocation, and returns a pointer to
the allocated memory. If ptr is NULL, realloc() is identical to a call
to malloc() for size bytes. If size is zero and ptr is not NULL, a new,
minimum sized object is allocated and the original object is freed. When
extending a region allocated with calloc(3), realloc(3) does not guaran-
tee that the additional memory is also zero-filled.

Resources