Trouble freeing memory in C with other functions - c

I'm creating a program where a struct is created through this process:
TokenizerT *TKCreate(char *separators, char *ts) {
TokenizerT * inu = malloc(sizeof(*inu));
char * sts = malloc(strlen(ts)*sizeof(char));
char * by = malloc(lim*sizeof(char));
strcpy(by, yr);
strcpy(sts, ts);
inu->sep = by;
inu->toks = sts;
return inu;
}
I need to free the struct inu through another function, but my function below only seems to free up the memory associated with TokenizerT.sep
void TKDestroy(TokenizerT *tk) {
free(tk->sep);
free(tk->toks);
}
How do I free up tk.sep and tk.toks?
EDIT: free(tk) results in this error: "malloc: * error for object 0x7fff55662bd8: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug"
EDIT2: Struct definition
struct TokenizerT_ {
char * sep;
char * toks;
};
And
void TKDestroy(TokenizerT *tk) {
free(tk->sep);
free(tk->toks);
free(tk);
}
results in the same error specified in EDIT 1
EDIT 3: I've also added my main method:
int main(int argc, char **argv) {
char * arr = argv[1];
char * y = argv[2];
TokenizerT jer = *TKCreate(arr, y);
TKDestroy(&jer);
return 0;
}

First of all, the malloc of "inu" seems not correct
TokenizerT * inu = malloc(sizeof(inu));
I believe it only get memory with 4 bytes (in 32-bit system)
It should be:
TokenizerT * inu = malloc(sizeof(TokenizerT ));
And as you mentioned -- "I need to free the struct inu"
I think the allocated "inu" is passed into "TKDestroy(TokenizerT *tk)"
then:
void TKDestroy(TokenizerT *tk) {
free(tk->sep);
free(tk->toks);
free(tk) // this free is what you want to free "inu"

You just need to reverse the operations you did for allocation:
void TKDestroy(TokenizerT *tk) {
free(tk->sep); // for the 3rd malloc()
free(tk->toks); // for the 2nd malloc()
free(tk); // for the 1st malloc()
}
BTW: you know that sizeof(char) is always 1 - per definition?
The error you get results from your wrong allocation of tk - you just allocated enough memory for a pointer, not for the whole struct. That will mess things up.

Concerning your main, replace:
TokenizerT jer = *TKCreate(arr, y);
TKDestroy(&jer);
With:
TokenizerT *jer = TKCreate(arr, y);
TKDestroy(jer);
The reason being that your create-function returns a pointer, which you then pass to your destroy-function...

The reason that your code fails with that error is that &jer is the address of a local variable. It is the not address returned by the call to malloc.
TokenizerT jer = *TKCreate(arr, y);
TKDestroy(&jer);
So, jer is a local variable. The address returned by TKCreate is immediately de-referenced, and a copy of the struct is made. You simply fail to retain the address returned by TKCreate and it is leaked. Then when you attempt to call free on &jer, the address of a local variable, your environment correctly reports that you are passing to free an address that was not created by a call to malloc.
As I said in your previous question, it makes a lot more sense to return the struct by value than using dynamic allocation. On top of that, your string allocations are incorrectly performed. You must always allocate sufficient room for the null-terminator.
I would write your program like this:
#include <stdlib.h>
#include <string.h>
typedef struct {
char *sep;
char *toks;
} TokenizerT;
TokenizerT TKCreate(const char *seps, const char *toks)
{
TokenizerT inu;
inu.sep = malloc(strlen(seps)+1);
strcpy(inu.sep, seps);
inu.toks = malloc(strlen(toks)+1);
strcpy(inu.toks, toks);
return inu;
}
void TKDestroy(TokenizerT *tk)
{
free(tk->sep);
free(tk->toks);
}
int main(int argc, char **argv)
{
TokenizerT jer = TKCreate(argv[1], argv[2]);
TKDestroy(&jer);
return 0;
}
Notes:
By definition, sizeof(char) is 1 so idiom dictates that it is omitted as a multiplicative factor in calls to malloc().
I've given the parameters to TKCreate the same names as the fields of the struct. This makes it easier to understand what is going on. What's more, your code looked plain wrong since it was ignoring one of the parameters.
As stated above, the struct is returned by value. This is conceptually easier to handle.
You might prefer to write a helper function to duplicate strings. If your compiler's runtime already has a function named strdup you might use that. Otherwise you can use this trivial implementation:
char *strdup(const char *str)
{
char *result = malloc(strlen(str)+1);
strcpy(result, str);
return result;
}
If you only want to search for the null-terminator once you write it like this:
char *strdup(const char *str)
{
size_t len = strlen(str)+1;
char *result = malloc(len);
memcpy(result, str, len);
return result;
}
Then the code becomes:
#include <stdlib.h>
#include <string.h>
char *strdup(const char *str)
{
size_t len = strlen(str)+1;
char *result = malloc(len);
memcpy(result, str, len);
return result;
}
typedef struct {
char *sep;
char *toks;
} TokenizerT;
TokenizerT TKCreate(const char *seps, const char *toks)
{
TokenizerT inu;
inu.sep = strdup(seps);
inu.toks = strdup(toks);
return inu;
}
void TKDestroy(TokenizerT *tk)
{
free(tk->sep);
free(tk->toks);
}
int main(int argc, char **argv)
{
TokenizerT jer = TKCreate(argv[1], argv[2]);
TKDestroy(&jer);
return 0;
}
If you are desperate to return a pointer to the struct, do it like this:
#include <stdlib.h>
#include <string.h>
char *strdup(const char *str)
{
size_t len = strlen(str)+1;
char *result = malloc(len);
memcpy(result, str, len);
return result;
}
typedef struct {
char *sep;
char *toks;
} TokenizerT;
TokenizerT *TKCreate(const char *seps, const char *toks)
{
TokenizerT *inu = malloc(sizeof *inu);
inu->sep = strdup(seps);
inu->toks = strdup(toks);
return inu;
}
void TKDestroy(TokenizerT *tk)
{
free(tk->sep);
free(tk->toks);
free(tk);
}
int main(int argc, char **argv)
{
TokenizerT *jer = TKCreate(argv[1], argv[2]);
TKDestroy(jer);
return 0;
}
Note particularly the difference in the way I call TKCreate and TKDestroy.
Finally, I have ignored all error checking on the calls to malloc(). In real production code you would not do that, but for the sake of clarity of exposition it is much better to omit it here.

Related

How to properly replace day in a dynamically allocated C array

I am working on a basic framework to dynamically allocate array with the C language. I have created a function to create an array of strings titled init_string_vector. Data can be appended to the array with the append_string_vector function and data can be de-allocated from the heap with the free_string_array function. I am currently working on a function titled replace_string_vector_index that allows a user to pass an array index to the function as well as a pointer to the string array. If the array is typed as a STRING array and the index is not out of bounds, the function should replace the existing data with the string that a user passes to the function.
The replace_string_vector_index function appears to work properly and does replace the string at the index with the other string the user passed to the function. However, the free_string_array function no longer works once I have used to replace_string_vector_index function to act on the array. This makes me think that the process within the function is causing an issue, but I cannot see how. An example is shown below. When the free_string_array function fails, I get the following error, free(): invalid pointer.
vector.h
#ifndef ARRAY_H
#define ARRAY_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef enum
{
FLOAT,
DOUBLE,
CHAR,
INT,
STRING
} dat_type;
// --------------------------------------------------------------------------------
typedef struct
{
char **array;
size_t len;
int elem;
dat_type dat;
} StringVector;
// --------------------------------------------------------------------------------
int string_vector_mem_alloc(StringVector *array, size_t num_indices);
// --------------------------------------------------------------------------------
StringVector init_string_vector();
// --------------------------------------------------------------------------------
int append_string_vector(StringVector *s, char *value);
// --------------------------------------------------------------------------------
void free_string_array(StringVector *array);
// --------------------------------------------------------------------------------
int replace_string_vector_index(StringVector *array, int index, char string[]);
// --------------------------------------------------------------------------------
vector.c
#include "vector.h"
int string_vector_mem_alloc(StringVector *array, size_t num_indices) {
// Determine the total memory allocation and assign to pointer
void *pointer;
pointer = malloc(num_indices * array->elem);
// If memory is full fail gracefully
if (pointer == NULL) {
printf("Unable to allocate memory, exiting.\n");
free(pointer);
return 0;
}
// Allocate resources and instantiate Array
else {
array->array = pointer;
array->len = 0;
return 1;
}
}
// --------------------------------------------------------------------------------
StringVector init_string_vector() {
StringVector array;
array.dat = STRING;
array.elem = sizeof(char *);
string_vector_mem_alloc(&array, array.elem);
return array;
}
// --------------------------------------------------------------------------------
int append_string_vector(StringVector *array, char *value) {
value = strdup(value);
if (!value) {
return -1;
}
array->len++;
char **resized = realloc(array->array, sizeof(char *)*array->len + 1);
if (!resized) {
free(value);
return -1;
}
resized[array->len-1] = value;
array->array = resized;
return 0;
}
// --------------------------------------------------------------------------------
void free_string_array(StringVector *array) {
if (array != NULL) {
for (int i = 0; i < array->len; i++) {
free(array->array[i]);
}
}
free(array->array);
// Reset all variables in the struct
array->array = NULL;
array->len = 0;
array->elem = 0;
}
// --------------------------------------------------------------------------------
int replace_string_vector_index(StringVector *array, int index, char string[]) {
if (array->dat != STRING) {
printf("Array data type must be a STRING");
return 0;
}
if (index > array->len) {
printf("Index is greater than array length");
return 0;
}
* (char **) ((char *) array->array + index * array->elem) = string;
return 1;
}
// --------------------------------------------------------------------------------
main.c
#include <stdio.h>
#include "vector.h"
int main(int argc, const char * argv[]) {
StringVector arr_test = init_string_vector();
char one[] = "Hello";
char two[] = "World";
char three[] = "Hello";
char four[] = "Goodbye";
append_string_vector(&arr_test, one);
append_string_vector(&arr_test, two);
append_string_vector(&arr_test, three);
append_string_vector(&arr_test, four);
// I can free the array at this point
free_string_array(&arr_test)
StringVector arr_test = init_string_vector();
append_string_vector(&arr_test, one);
append_string_vector(&arr_test, two);
append_string_vector(&arr_test, three);
append_string_vector(&arr_test, four);
replace_string_vector_index(&arr_test, 1, one);
// - Once I envoke replace_string_vector_index, free_string_array
// no longer works, and I get an invalid pointer error.
free_string_array(&arr_test);
}
If I understand the requirements for your replace_string_vector_index function, you should first free the memory of array->array[index], then assign the result of strdup(string) to that element.
No casting needed, no complex pointer arithmetic. Just simply:
free(array->array[index]);
array->array[index] = strdup(string);
What happens now (I think) is that you make array->array[index] point to the array that contains the string (i.e. you forget the strdup step). An array that wasn't allocated by malloc, and which can't be passed to free.
Since you will pass it to free as part of free_string_array you will have undefined behavior.

c program doesn't give me errors

Consider the following program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct my_string{
int len;
char *buf;
} my_string_t;
my_string_t *init_my_string(char *);
my_string_t *call_init_my_string();
int main(int argc, char *argv[])
{
my_string_t *st1 = call_init_my_string();
printf("%d\n", st1->len);
printf("%s\n", st1->buf);
free(st1);
return 0;
}
my_string_t *call_init_my_string()
{
my_string_t *st1 = init_my_string("Foo");
return st1;
}
my_string_t *init_my_string(char *s)
{
my_string_t *st = (my_string_t *) malloc(sizeof(*st));
st->len = strlen(s);
st->buf = s;
return st;
}
The question is,
does this program suppose to result in undefined behaviour or some kind of error?
since the string "Foo" inside function call_init_my_string is locally declared
and get passed to init_my_string function. In init_my_string function, I allocate
a space to hold the size of of the string and the string itself, but as i know, this
allocation
my_string_t *st = (my_string_t *) malloc(sizeof(*st)); only allocate enough space for st->len
and st->buf pointer and not for string "Foo" since I only assign the string
to st->buf instead of allocating it first and then do like the following:
st->buf = (char *) malloc(strlen(s) + 1);
memcpy(st->buf, s, strlen(s));
st->buf[strlen(s)] ='\0';
But after I compile it and run, it gives me no errors and the program runs fine.
why this program works fine and gives me no errors?
this is the result printed on the screen:
$ gcc struct_ptr_string1.c -o struct_ptr_string1
$ ./struct_ptr_string1
3
Foo
There's no undefined behaviour in your code.
The string literal "Foo" has static storage duration. You are passing its address to init_my_string and simply store that address (essentially a pointer to "Foo").
Your code is equivalent to (except we have one more copy of "Foo"):
my_string_t *call_init_my_string()
{
static char s[] = "Foo";
my_string_t *st1 = init_my_string(&s[0]);
return st1;
}
my_string_t *init_my_string(char *s)
{
my_string_t *st = malloc(sizeof(*st));
st->len = strlen(s);
st->buf = s;
return st;
}
The "Foo" string is a constant string probably stored somewhere statically. What happens in init_my_string is that you indeed allocate a new memory chunk, but you will assing st->buf to s which is the pointer which points to this "Foo" string. So you dont copy "Foo", but rather just set st->buf to the location where it is stored.
my_string_t *init_my_string(char *s)
{
my_string_t *st = (my_string_t *) malloc(sizeof(*st));
printf("st address=%d\n", st);
printf("s address=%d\n", s);
st->len = strlen(s);
st->buf = s;
printf("st->buf address=%d\n", st->buf);
return st;
}
Output:
st address=19779600
s address=4196344
st->buf address=4196344
3
Foo
As you see st->buf actually points to the constant string thats why no error.

Give Pointer from Library

Ii've a big Problem. I write a static Library, what I would like to use in a Software. My Problem is: if you give a pointer from a function out of the library back to the main program the pointer have not the value from the pointer in the Library. Is there an issue, if you give pointer from an Libay.a back to the main.c
Main.c:
#include <stdio.h>
int main(int argc, const char * argv[]) {
char *ptr;
Prallow_its(ptr, 122);
printf("%s", ptr);
return 0;
}
Prallow.c from Prallow.a
[...]
char *Prallow_its(char *ptr, int i){
static char buffer[255];
sprintf(buffer, "%u", i);
ptr = buffer;
return ptr;
}
[...]
It's fine to return the pointer to your static buffer from the library. It lives in the same address space as the rest of your program. Of course, it's not thread-safe but that's a separate issue.
The real problem is the way you are calling it:
char *ptr; // <-- ptr uninitialised
Prallow_its(ptr, 122); // <-- return value ignored
printf("%c", ptr); // <-- ptr still uninitialised
You should instead do this:
ptr = Prallow_its( ptr, 122 );
Alternatively, you could allow ptr to be modified by Prallow_its. In that case, it must be defined like this:
char *Prallow_its( char **ptr, int i )
{
static char buffer[255];
sprintf(buffer, "%u", i);
*ptr = buffer;
return *ptr;
}
And called like this:
Prallow_its( &ptr, 122 );
C passes by value, so the line ptr = buffer in the library function does not change the value of ptr in main.
Also, the library function doesn't do anything with the pointer that's passed in, so there's no reason to pass the pointer. The code in Main.c should be
int main(int argc, const char * argv[])
{
char *ptr = Prallow_its(122);
printf("%s", ptr);
return 0;
}
and the code in Prallow.c should be
char *Prallow_its(int i)
{
static char buffer[255];
sprintf(buffer, "%u", i);
return buffer;
}

strcpy with destination pointer and return value

My plain C is a bit rusty, and I currently try to figure out why the first works and the second doesn't.
char *returnSomething(void) {
char *s = (char *) malloc(5 + 1);
strcpy(s, "Hello");
return s;
}
void dontReturnSomething(char *dest) {
char *s = (char *) malloc (5 + 1);
strcpy(s, "Hello");
dest = malloc(strlen(s) + 1);
strcpy(dest, s);
free(s);
}
int main(int argc, char *argv[]) {
char *first = returnSomething();
char *second = NULL;
dontReturnSomething(second);
printf("first: %s | second: %s", first, second);
}
Isn't it basically doing the same thing?
To return a pointer through a parameter you need a pointer to a pointer. Declare dest as char **dest.
void dontReturnSomething(char **dest) {
char *str = "Hello";
*dest = malloc(strlen(str) + 1);
strcpy(*dest, str);
}
Call the function like this:
dontReturnSomething(&second); // pass in address of second
To be more accurate, pointers to pointers are only necessary so long as, just as in the examples above, the memory is not allocated until after you enter the function. Just wanted to say this for anyone having pointer problems and thinks any passing of pointers always requires pointers to pointers to be passed.
For example, the below example works just fine.
void dontReturnSomething(int* testint)
{
int test = 33;
*testint = test;
}
int main(int argc, char *argv[])
{
int *first = calloc(1,sizeof(int));
printf("Before: %d\n", *first);
dontReturnSomething(first);
printf("After: %d\n", *first);
return(1);
}
If you run it, you'll get 0 and 33 as expected. Of course the caveat to this is that you absolutely have to have memory allocated to the pointer being used. If you allocated memory for the pointer inside the function, then you will be assigning it a new address that would then have to be returned so that the address can persist. The below example also works just fine.
void dontReturnSomething(char* testchar)
{
char* test = "Hello World!";
strcpy(testchar,test);
}
int main(int argc, char *argv[])
{
char *hello = NULL;
hello = calloc(13, sizeof(char));
printf("Before: %s\n", hello);
dontReturnSomething(hello);
printf("After: %s\n", hello);
return(1);
}
Of course you will pretty much never know the size of a string, or more usually a buffer, ahead of time. I just think it's important to understand the subtleties of pointers.

C - Not getting the right value with an argument pointer

The get_current_path function gets a pointer to a char string of the current working directory. printf("%s\n", buf); in the function itself prints exactly what I want, but then outside of the function, printf("%s", thisbuf); gives me a lot of garbage. I assume I've made some silly mistake here, but I can't figure out what it is.
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
int get_current_path(char *buf) {
long cwd_size;
char *ptr;
cwd_size = pathconf(".", _PC_PATH_MAX);
if ((buf = (char *) malloc((size_t) cwd_size)) != NULL)
ptr = getcwd(buf, (size_t)cwd_size);
else cwd_size == -1;
printf("%s\n", buf);
printf("%ld\n", cwd_size);
return cwd_size;
}
int main (int argc, char **argv)
{
char *thisbuf;
get_current_path(thisbuf);
printf("%s", thisbuf);
return 0;
}
You should pass a pointer to char *
int get_current_path(char **buf)
{
*buf = ...;
}
int main()
{
char *thisbuf;
get_current_path(&thisbuf);
}
Parameters in C are pass-by-value, which means that get_current_path can't change the value of "thisbuf" passed in by the caller.
To make the change, you would have to pass in a pointer to "thisbuf":
int get_current_path(char **resultBuf) {
char *buf = (char *) malloc((size_t) cwd_size);
...
*resultBuf = buf; // changes "thisbuf" in the caller
}
....
get_current_path(&thisbuf); // note - passing pointer to "thisbuf"
Try this instead:
int get_current_path(char **buf) {
*buf = something; // Set buf with indirection now.
And:
int main (int argc, char **argv)
{
char *thisbuf;
get_current_path(&thisbuf);
printf("%s", thisbuf);
return 0;
}
You were trying to pass a copy of buf to get_current_path, so when buf was modified, the original pointer to buf was not modified.

Resources