How to free a returned malloced string? - c

I have the following two functions. Function get_string_data(line) mallocs a string and returns it. Later I use it like this:
char *get_string_data(char *) {
char *sec_tok, *result;
Split *split;
split = split_string(line, ' ');
sec_tok = split -> tail;
if (starts_with_char(sec_tok, '\"') && ends_with_char(sec_tok, '\"')) {
result = (char *) malloc(strlen(sec_tok) + 1);
strcpy(result, sec_tok);
free(split);
result++;
*(result + (strlen(result) - 1)) = '\0';
return result;
}
free(split);
return NULL;
}
void handle_string_instr(char *line) {
char* data = get_string_data(line);
...a few lines later, after I used the data...
free(data);
... end of the world happens here...
}
Now on attempt to free the string everything crashes (Program received signal SIGABRT, Aborted.). Why does this happen, and what is the correct way to free the memory?

Here is the problem code
result = (char *) malloc(strlen(sec_tok) + 1);
...
result++;
...
return result;
At this point the get_string_data method is no longer returning a pointer to the memory that was allocated. It is instead returning a pointer into the memory that was allocated. You can only pass pointers to memory that was allocated to free. In this case you don't and this is why it is crashing
Also a simpler way of null terminating the string would be the following
size_t length = strlen(sec_tok);
result = (char*)malloc(length + 1);
...
result[length] = '\0';

free(line) get_string_data possibly moves the pointer to some location in "line" which is not the correct pointer to return to free().

Related

Removing print statement causes program to crash C

I have a c program where I copy one string to another but for some reason in my loop, if I remove a print statement I used for debugging once, the program crashes before I reach the print statement outside the while loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char * cats2 = malloc(sizeof(char));
cats2[0] = '\0';
char * cats = "this string is a cool cat";
getCopyFrom(cats, cats2);
free(cats2);
return 0;
}
void getCopyFrom(char* original, char* translation){
int index = 0;
char * current = malloc(sizeof(char));
current[0] = '\0';
while(index < (strlen(original))){
printf("%d\n", index);
current = realloc(current, sizeof(char) * 2);
current[index] = original[index];
current[index + 1] = '\0';
index++;
}
printf("%s\n", current);
free(current);
}
If I remove the printf("%d\n", index); from the while loop, the program will crash before the while loop ends. If I keep it, the program runs fine until the end where it returns a access violation error.
I'm not sure why either happens, am I missing something obvious or am I just not understanding malloc and realloc correctly?
edit:)
My previous question was answered, but I have a new problem. I added translation = realloc(translation, (strlen(current) + 1) * sizeof(char)); to the code to set the size of translation to the size of current but I get another access violation. Are you not able to realloc parameters or something?
current = realloc(current, sizeof(char) * 2);
but why is the second argument to realloc() in a loop a constant? It's like we want
current = realloc(current, sizeof(char) * (index + 1));
but once you do that you'll discover your code is really slow. The * 2 meant something. You really want to keep a separate array size and allocated size, and only call realloc when array size == allocated size and double allocated size.
if (index + 1 >= alloc) {
char *new = realloc(current, sizeof(char) * (alloc = (alloc == 0) ? 4 : (alloc << 1)));
if (!new) {
/* todo handle error */
}
}

If Realloc() fails, does the caller lose the data prom the previous malloc() call?

The following is a quote from an exam (1% top university).
I failed, because my answer differed from the "approved" answer.
I have a hunch that his (professor, known expert in C) answer is not correct.
The following, is the question followed by the "approved" answer.
There is a potential bug in the following function. What is it and how would I fix it?
Hint: this has something to do with the use of the realloc() function. Please identify the line numbers you would change and what you would replace them with.
BOOLEAN lengthen_string(char* string, const char newcontents[])
{
int newlen = strlen(string) + strlen(newcontents) + 1;
string = realloc(string, newlen);
if (!string) {
perror("malloc");
return FALSE;
}
strcat(string, newcontents);
return TRUE;
}
The "correct" answer provided by the professor was:
line 4: realloc returns a NULL pointer when it fails to allocate. This means that on failure the original data is lost.
To fix this, assign the result of realloc to a temporary variable and test that first.
Ie: line 4:
char * temp=realloc(string, newlen);
if(!temp) ... (all remains the same)
after old line 9, string = temp;
Any thoughts?
BTW, my answer was that #string is a local variable, and the prototype of the function should be char **string, where the caller passes a pointer to its string pointer, and then the callee would assign any realloc() return value to *string
Any thoughts?
You are both correct.
The professor is correct, in that realloc() does not alter the passed-in memory on failure, thus leaving the input string pointer intact, but if the NULL return value on failure is assigned immediately to string then the original data is lost and leaked. So a check for failure first is needed before assigning the new pointer value to string.
You are correct, in that string needs to be passed by pointer so it can be re-assigned a new value if realloc() returns a different memory address.
The correct solution would look more like this:
BOOLEAN lengthen_string(char** string, const char newcontents[])
{
if (!string)
{
errno = EINVAL;
perror("bad input");
return FALSE;
}
size_t newsize = strlen(*string) + strlen(newcontents) + 1;
char *temp = realloc(*string, newsize);
if (!temp)
{
perror("realloc failed");
return FALSE;
}
strcat(temp, newcontents);
*string = temp;
return TRUE;
}
Alternatively, there is some room for optimization, eg:
BOOLEAN lengthen_string(char** string, const char newcontents[])
{
if (!string)
{
errno = EINVAL;
perror("bad input");
return FALSE;
}
char *temp;
if (!*string)
{
temp = strdup(newcontents);
if (!temp)
{
perror("strdup failed");
return FALSE;
}
}
else
{
size_t offset = strlen(*string);
size_t size = strlen(newcontents) + 1;
temp = realloc(*string, offset + size);
if (!temp)
{
perror("realloc failed");
return FALSE;
}
memcpy(temp + offset, newcontents, size);
}
*string = temp;
return TRUE;
}

C using malloc and realloc to dynamically increase string length

Currently learning memory management in C, and I am currently running into issues increasing string length as a loop iterates.
The method I am trying to figure out logically works like this:
// return string with "X" removed
char * notX(char * string){
result = "";
if(for int = 0; i < strlen(string); i++){
if (string[i] != 'X') {
result += string[i];
}
}
return result;
}
Simple enough to do in other languages, but managing the memory in C makes it a bit challenging. Difficulties I run into is when I use malloc and realloc to initialize and change size of my string. In my code I currently tried:
char * notX(char * string){
char* res = malloc(sizeof(char*)); // allocate memory for string of size 1;
res = ""; // attempted to initialize the string. Fairly certain this is incorrect
char tmp[2]; // temporary string to hold value to be concatenated
if(for int = 0; i < strlen(string); i++){
if (string[i] != 'X') {
res = realloc(res, sizeof(res) + sizeof(char*)); // reallocate res and increasing its size by 1 character
tmp[0] = string[i];
tmp[1] = '\0';
strcat(res, tmp);
}
}
return result;
}
Note, I have found success in initializing result to be some large array like:
char res[100];
However, I would like to learn how to address this issue with out initializing an array with a fixed size since that might potentially be wasted memory space, or not enough memory.
realloc needs the number of bytes to allocate. size is incremented for each character added to res. size + 2 is used to provide for the current character being added and the terminating zero.
Check the return of realloc. NULL means a failure. Using tmp allows the return of res if realloc fails.
char * notX(char * string){
char* res = NULL;//so realloc will work on first call
char* tmp = NULL;//temp pointer during realloc
size_t size = 0;
size_t index = 0;
while ( string[index]) {//not the terminating zero
if ( string[index] != 'X') {
if ( NULL == ( tmp = realloc(res, size + 2))) {//+ 2 for character and zero
fprintf ( stderr, "realloc problem\n");
if ( res) {//not NULL
res[size] = 0;//terminate
}
return res;
}
res = tmp;//assign realloc pointer back to res
res[size] = string[index];
++size;
}
++index;//next character
}
if ( res) {//not NULL
res[size] = 0;//terminate
}
return res;
}
2 main errors in this code:
the malloc and the realloc function with parameter that call sizeof(char*). In this case the result of sizeof(char*) is the size of a pointer, not of a char, so you have to substitute the char* with char in the sizeof function.
res = ""; is incorrect. You primarly have a memory leak because you lose the pointer to the just allocated memory in malloc function, secondary but not less important, you have an undefined behavior when call realloc function over res initialized as an empty string ( or better a constant string), after the above initialization the memory is no longer dinamically managed. To substitute this initialization i think a memset to 0 is the best solution.

Unexpected behavior of string reallocation

I have encountered a strange behavior of memory allocation with string-functions.
Note: right now i am told to ignore failure of the allocation operation.
My code is:
void string_reallocation(char *result, int result_length) {
char *temp_result = malloc((strlen(result) + 1) * sizeof(char));
strcpy(temp_result, result);
realloc(result, (result_length + 1) * sizeof(char));
strcpy(result, temp_result);
free(temp_result);
}
this function is called with iterations within a while loop:
while (current_node != NULL) {
current_value_to_string = current_node->toStringFunc(current_node->value);
current_value_length = (int) strlen(current_value_to_string);
current_length += current_value_length + arrow_length;
string_reallocation(result, current_length);
strcat(result, current_value_to_string);
strcat(result, arrow);
current_node = current_node->next;
}
current_node is of type Node as follows:
typedef struct t_node {
Element value;
struct t_node *next;
elementDestroy destroyFunc;
elementCopy copyFunc;
elementToString toStringFunc;
} *Node;
The thing is, for some reason, specifically on the third iteration the free(temp_result); fails with a segmentation fault.
I'm don't think that the while loop has anything to do with the segmentation fault but i put it here in case it does.
This is a biphasic solution, since you got to understand how to use realloc(), by checking on its prototype. Let's do just that first.
Change this:
realloc(result, (result_length + 1) * sizeof(char));
to this:
result = realloc(result, (result_length + 1) * sizeof(char));
since from the reference, we got for the prototype of this method:
Return value: A pointer to the reallocated memory block, which may be
either the same as ptr or a new location.
Now, think about the scope of your variables (pointers). As #whozCraig commented, result = (in the corrected realloc()) assigns a value to an automatic variable. The original result passed in caller-side is unchanged, and now dangling. This has to be handled with an in/out arg or a function return result.
So what you could do, is to simply return that pointer, by changing this:
void string_reallocation(char *result, int result_length) {
to that:
char* string_reallocation(char *result, int result_length) {
// ...
return result;
}
and then change the call to this function, to this:
result = string_reallocation(result, current_length);

Returning a String from function in C

char* clean_string (char *input_string){
/*Ensure that input string isn't null and only do heavy lifting if it's not null*/
if (input_string){
char *stripped;
stripped = (char*)malloc(strlen(input_string)*sizeof(char));
while (*input_string != '\0'){
if isalpha(*input_string){
*stripped = toupper(*input_string);
input_string++;
stripped++;
} else {
input_string++;
}
}
/* *stripped++ += '\0';*/
return stripped;
}
/*default return val*/
return NULL;
}
Can anybody tell me where I'm going wrong with this? Tried to do a test run and it doesn't output anything when I try to call it.
You are returning a pointer to the last character in the string (stripped++ ?).
You are allocating one byte too few (should be strlen(...) + 1).
stripped = (char*)malloc(strlen(input_string)*sizeof(char)); /* Wrong. */
stripped = (char*)malloc(strlen(input_string) + 1);
/* .. */
stripped++;
/* .. */
return stripped;
Try to keep a copy, something like original_stripped = stripped before starting to change stripped, and return the copied value (not the incremented one).
The problem is with calling stripped++. You are modifying the pointer you get by malloc. Make an extra pointer char *result_char = stripped; and use that for iteration over resulting string.
The problem ís that you increment your stripped variable before returning it.
Try:
char *stripped;
char *result;
stripped = (char*)malloc(strlen(input_string)*sizeof(char));
result = stripped;
...
return result;
How about just:
char* clean_string (char *input_string)
{
/*Ensure that input string isn't null and only do heavy lifting if it's not null*/
if (input_string)
{
char *stripped;
int i;
stripped = (char*)malloc(strlen(input_string)*sizeof(char) + 1);
for(i=0; i < strlen(input_string); i++)
stripped[i] = (isalpha(input_string[i]) ? toupper(input_string[i]) : input_string[i]);
return stripped;
}
/*default return val*/
return NULL;
}

Resources