Issue copying string pointers contained in structs - c

So i have this struct which im using as a tree for a parser.
struct Expr{
struct Expr* a;
char* value;
struct Expr* b;
};
I initialize it with malloc like this.
Expr* initExp(){
Expr* ret;
ret = (Expr*)malloc(sizeof(Expr));
ret->a = (Expr*)malloc(sizeof(Expr));
ret->b = (Expr*)malloc(sizeof(Expr));
ret->value = (char*)malloc(sizeof(char));
ret->value = "18killstreak";
ret->a->value = "18killstreak";
ret->b->value = "18killstreak";
return ret;
}
I have written more here in the function than i needed to in the process of debugging so far and for printing the tree.
So I am trying to copy an Expr* a-> value into a Expr* value like this.
strcpy(temp2->value,ret->a->value);
While the values are "18killstreak" and "x" respectively.
But my program crashes at this line and I have tried many other tactics at this point.

The problem is that you're not managing memeory for your strings, so you can't just use strcpy. For example, when you have:
ret->value = (char*)malloc(sizeof(char));
ret->value = "18killstreak";
this allocats space for a 0-length string (just a NUL), and then throws it away (the memory leaks), overwriting the allocated pointer with a pointer to a static constant string "18Killstreak". When you later try to overwrite the static constant string (with strcpy) you get a crash.
So to do it correctly, you need to allocate and manage memory for the strings. The easiest way to do that is to have each struct Expr own the memory for the string and use strdup/free appropriately to alloc/copy/free that memory. So your init function becomes:
Expr* ret;
ret = (Expr*)malloc(sizeof(Expr));
ret->a = (Expr*)malloc(sizeof(Expr));
ret->b = (Expr*)malloc(sizeof(Expr));
ret->value = strdup("18killstreak");
ret->a->value = strdup("18killstreak");
ret->b->value = strdup("18killstreak");
Later when you want to replace the value of a struct, you do:
free(temp2->value);
temp2->value = strdup(ret->a->value);
and when you want to free an Expr, you need to also (first) free the value:
free(exp->value);
free(exp);
Now one isuue with this is that strdup is not a standard C function -- it's a POSIX function. So it is available on POSIX systems (such as Linux or OSX), but not on non-POSIX systems. So you may need to define it yourself:
char *strdup(const char *str) {
char *rv = malloc(strlen(str) + 1);
if (rv) strcpy(rv, str);
return rv;
}

Related

char* value changing after use of fgets

so my first question would be. Does fgets overwrite other char* values?
Otherwise, I'm not really sure how I have messed up my mallocs. Below is the code where the value is changing. First line is where the variable is being created.
data[dataIndex++] = createVariable(varName, 1, value, -1, line, NULL);
The code where the variable is being created
Variable *createVariable(char *name, int type, int val, int len, int line, char *string)
{
Variable *var = malloc(sizeof(Variable));
var->name = name;
var->setting = type;
var->num = val;
var->length = len;
var->line = line;
var->string = string;
return var;
}
What data looks like and how it was created.
Variable **data;
data = malloc(4 * sizeof(Variable *));
Forgot to add this, but below is my fgets code
if (fgets(line, MAX_LINE_LENGTH, in) == NULL)
{
break;
}
The problem is this line in your createVariable function:
var->name = name;
What this does is copy the pointer given as the first argument to the name field in the var structure; it doesn't make a (separate) copy of the data that is pointed to! So, assuming you call createVariable many times with the same variable as the first argument, then every object created will have the same address in its name field, and any modifications you make to any of them (via fgets) will change all of them.
To get round this, you need to allocate new memory for the name field, each time you call the createVariable function, then copy the string data to it. The simplest way to do this is using the strdup function:
Variable *createVariable(char *name, int type, int val, int len, int line, char *string)
{
Variable *var = malloc(sizeof(Variable));
var->name = strdup(name);
//...
var->string = strdup(string);
//...
But note, you will now need to be sure to free that memory from each object when you (eventually) delete it. Something like this:
void deleteVariable(Variable** var)
{
free((*var)->name); // free the name memory
free((*var)->string); // free the string memory
free(*var); // free the actual structure
*var = NULL; // set the pointer to NULL - to prevent multiple frees
}
EDIT: Just re-read your question, and noticed that you are making the same mistake with the string field! The same fix needs to be applied to that!

When to free pointers

I'm a bit of a C newbie, so I'm still trying to get my head fully around when to worry about memory issues.
Suppose I have the following simple program:
#include <stdlib.h>
/* this returns a malloc()'d string */
char *get_str(int whichone);
int main(void)
{
char *s;
if ((s = get_str(0)) == NULL) {
exit(1);
}
/* position 1 */
if ((s = get_str(1)) == NULL) { /* position 2 */
exit(2);
}
return 0;
}
Obviously, this simple of a program has no worries about memory. It allocates a few bytes (for all intents and purposes), and it exits provided our dear function didn't fail.
Now, suppose I am running similar code inside of a looping and fork()ing program. Should I be using free(s) at position 1 since at position 2 I leave the old value behind and assign a new location for the pointer?
Yes. free releases the memory associated with the pointer that is being free'd. Once you reassign s so that it holds a different memory location, you will have lost your opportunity to free the memory associated with the original value of s.
You should definetly free the memory at position 1, because once you reassigned s you lost any chance to do so. And I'd do it one way or another because you can never know when somebody else is instructed to build a fork into your application and he will assume you did everything right.
If you have a pointer to memory that have been allocated using one of the malloc() type calls then when you are done with the memory area, you should deallocate the memory using free(). Similarly using calloc(), which also allocates from the heap, should be followed by the use free() to deallocate the memory when done with it.
The other memory allocator such as alloca() which allocates from the stack and not the heap see On the use and abuse of alloca does not use the free() function and that memory will be recovered automatically as the stack pointers are adjusted when the function in which it is used returns. Naturally that means that using a pointer from alloca() is only good for the function and any functions it calls and the address becomes invalid as soon as the function using alloca() returns.
In your simple example, I would use free() just before the call to the get_str(1) function at position 2 so the source would look something like"
int main(void)
{
char *s;
if ((s = get_str(0)) == NULL) {
exit(1);
}
// doing stuff with the string pointed to by s
/* position 1 */
// free up the string area so that we can get another one.
free (s);
if ((s = get_str(1)) == NULL) { /* position 2 */
exit(2);
}
return 0;
}
I might also be tempted to modify your example a touch and do something like the following. This was all written without testing in a compiler so there may be a compilation error or two however this should provide the basic idea.
The idea with this approach is to have a struct that contains state information as well as a pointer so that you will know which type of get_str() pointer came from, if you are interested, and when you call the get_str() function, it will deallocate the memory for you. You could also add intelligence so that if there is memory already allocated and it is the correct type, then you do not do a free() followed by a malloc() but instead just return back.
Another bonus provided by this approach is when a free() is done, the char * member of the struct is set to NULL which should give you a crash if you try to dereference the pointer and since the whichone member of the struct indicates the last type of get_str() used, your debugging may be easier depending on how good you are with interpreting a crash dump.
#include <stdlib.h>
typedef struct {
int whichone;
char *s;
} GetStrStruct;
/* this returns a malloc()'d string */
GetStrStruct *get_str(int whichone, GetStrStruct *pStruct)
{
free(pStruct->s); // we depend on pStruct->s being valid or NULL here
pStruct->s = NULL;
pStruct->whichone = -1;
switch (whichOne) {
case 0: // allocate string one
pStruct->s = malloc (32); // string one type of memory allocation
pStruct->whichone = whichone;
break;
case 1: // allocate string two
pStruct->s = malloc (64); // string two type of memory allocation
pStruct->whichone = whichone;
break;
default:
break;
}
// if the malloc() failed then return a NULL pointer
// we just reuse the pStruct pointer here, it is local and one less variable to make
if (pStruct->s == NULL) pStruct = NULL;
return pStruct;
}
int main(void)
{
GetStrStruct myStruct = {0}; // create and initialize the struct
if (get_str(0, &myStruct) == NULL) {
exit(1);
}
// do things with myStruct.s, the string from last get_str() call
// this would be using myStruct.s and not just myStruct or s so maybe awkward?
/* position 1 */
if (get_str(1, &myStruct) == NULL) { /* position 2 */
exit(2);
}
// do things with the second type of get_str()
// this would be using myStruct.s and not just myStruct or s so maybe awkward?
// release the memory as I am done. This may seem a bit strange to get a nothing string.
get_str (-1, &myStruct);
return 0;
}
If you added a debug facility you could even track which line of source did the last allocation and the last deallocation. Or if the malloc() fails, you could implement a debugger interrupt or other mechanism to immediately stop so you will know exactly which line the function call failed.
In the include file with the prototype for the get_str() function and the GetStrStruct struct you would use C Preprocessor as follows. If you change the 0 in the #if 0 to a 1 then the debug version is enabled otherwise it is not. The idea is to use a macro through the C Preprocessor to replace calls to get_str() with a call to get_str_Debug() and provide additional arguments with the source file path and the line number in the source file.
#if 0
typedef struct {
int whichone;
char *s;
struct {
int lineNo;
char file[64];
} myDebug;
} GetStrStruct;
GetStrStruct *get_str_Debug(int whichone, GetStrStruct *pStruct, char *file, int line);
#define get_str(wo,ps) get_str_Debug (wo,ps,__FILE__,__LINE__)
#else
typedef struct {
int whichone;
char *s;
} GetStrStruct;
GetStrStruct *get_str(int whichone, GetStrStruct *pStruct);
#endif
And then in the implementation file you could use the C Preprocessor with something like the following to allow you to specify whether the get_str() function should be replaced by a get_str_Debug() function with additional debug aids at compile time.
#if defined(get_str)
// provide a prototype for the replacement function signature.
GetStrStruct *get_str_Special(int whichone, GetStrStruct *pStruct);
// provide the debug information wrapper so that we can track where the last use came from
GetStrStruct *get_str_Debug(int whichone, GetStrStruct *pStruct, char *file, int line)
{
GetStrStruct *pTemp = get_str_Special (whichone, pStruct);
if (pTemp) {
// update the debug information. we keep only last 60 chars of file path.
int iLen = strlen (file);
if (iLen > 60) iLen -= 60; else ilen = 0;
strcpy (pStruct->myDebug.file, file + iLen);
pStruct->myDebug.lineNo = line;
} else {
// cause a debugger interrupt or a crash dump or something.
}
return pTemp;
}
GetStrStruct *get_str_Special (int whichone, GetStrStruct *pStruct)
#else
/* this returns a malloc()'d string */
GetStrStruct *get_str(int whichone, GetStrStruct *pStruct)
#endif
{
free(pStruct->s);
pStruct->s = NULL;
pStruct->whichone = -1;
switch (whichOne) {
case 0: // allocate string one
pStruct->s = malloc (32); // string one type of memory allocation
pStruct->whichone = whichone;
break;
case 1: // allocate string two
pStruct->s = malloc (64); // string two type of memory allocation
pStruct->whichone = whichone;
break;
default:
break;
}
// if the malloc() failed then return a NULL pointer
if (pStruct->s == NULL) pStruct = NULL;
return pStruct;
}
Then where ever you use get_str() if you turn on the debugging, the C Preprocessor will substitute a call to get_str_Debug() with the arguments used in the get_str() call along with two additional arguments, a char pointer to the source file name where the get_str() is being replaced by the get_str_Debug() and the source file line number.

Freeing memory, functions

I am trying to free some memory that I allocated in one functions in another function. An example of this would be:
MusicRec * createRecord(char * title, char * artist, double fileSize, int length, char theType)
{
MusicRec * newRecord;
MusicRec * next;
newRecord = malloc(sizeof(MusicRec));
newRecord->title = malloc(sizeof(char)*(strlen(title))+1);
strcpy(newRecord->title, title);
newRecord->artist = malloc(sizeof(char)*(strlen(artist))+1);
strcpy(newRecord->artist, artist);
newRecord->sizeInKB = fileSize;
newRecord->lengthInSeconds = length;
newRecord->type = theType;
newRecord->next = NULL;
next = NULL;
return(next);
}
I have malloced memory in that function, but now i am trying to free this malloced memory in a different function such as my main function. How would i do this?
Just use the corresponding deallocation function free() Remember you cannot use already deallocated memory at all.
Some points to consider:
Better change how you allocate memory, so you can more easily change the type:
Was: newRecord = malloc(sizeof(MusicRec));
Should be: newRecord = malloc(sizeof *newRecord);
Consider defining some helper functions for things you often do. Example (this function is often actually already defined):
Was: newRecord->title = malloc(sizeof(char)*(strlen(title))+1);strcpy(newRecord->title, title);
Should be: newRecord->title = strdup(title);
Never use sizeof(char): It looks illiterate, because you are literally asking: How many char's do I need to save one char?
For cases it's not defined:
char* strdup(const char* str) {
size_t len = strlen(str) + 1;
char* ret = malloc(len);
memcpy(ret, str, len);
return ret;
}
If you have passed that variable as reference from another function then you can free that variable from that function using free() function; otherwise you can not free that variable from another function if you have passed by value.

How to design libraries written in ANSI C?

I want to develop a library with ANSI C.
I have a string struct:
struct libme_string
{
char* buffer;
int length;
};
I want to write a function, libme_create_string(), that creates and initializes a string (like constructors in C++).
Which of these methods is better for designing libme_create_string()?
Method #1
Allocate memory for string object in libme_create_string() and return it:
struct libme_string* libme_create_string(int length)
{
// Check arguments...
// Allocate memory for object.
struct libme_string* str = malloc(sizeof(struct libme_string));
// Handle memory allocation errors...
str->buffer = malloc(length);
str->length = length;
// Handle memory allocation errors...
return str;
}
void libme_delete_string(struct libme_string* str)
{
// Check arguments...
free(str->buffer);
free(str);
}
Use
struct libme_string* str;
str = libme_create_string(1024);
// ...
libme_delete_string(str);
str = NULL;
Method #2
Do not allocate memory for string object in libme_create_string() function, accept it as an argument:
struct void libme_create_string(libme_string* str, int length)
{
// Check arguments...
// Just allocate memory for members.
str->buffer = malloc(length);
str->length = length;
// Handle memory allocation errors...
}
void libme_delete_string(struct libme_string* str)
{
// Check arguments...
free(str->buffer);
}
Use
struct libme_string str; // << different, not a pointer!
libme_create_string(&str, 1024);
// ...
libme_delete_string(&str);
Notes
string just a sample.
Method #2 is faster, isn't it?
Lastly, are there any good design guidelines for designing libraries written in C?
Personally, I would view the second version as less intuitive and more error prone.
If you're trying your hardest to encapsulate instantiation (which you should be doing anyway), then the first really is the only way to go — one step, done. The second version means that in order to have a fully initialized variable, you need to not only instantiate it, but you need to call a helper function on it immediately. That extra step is a bug waiting to happen.
Personally I prefer the first method. Agreed: it's a bit C++ like, but ...
thing_t *thing_new(...);
void thing_delete(thing_t *ptr);
I do think that all "size" or "count" members should be unsigned, preferably size_t.
Also: you last snippet tries to free() an automatic variable. That is a good reason not to use it.
EDIT:
There is (at least) a third way: return the entire object as a value. I don't particularly like the method, but it at least avoids the double allocation. It goes like this:
typedef struct {
StrLen length;
StrType type; /* type is not stored in the brainfile
**but recomputed on loading */
char *word;
} STRING;
STATIC STRING new_string(char *str, size_t len)
{
STRING this;
if (str) {
if (!len) len = strlen(str);
if (len) { this.word = malloc(len); memcpy(this.word, str, len); }
else { this.word = malloc(1); memset(this.word, 0, 1); }
this.length = len;
this.type = word_classify(this);
}
else {
this.word = NULL;
this.length = 0;
this.type = 0;
}
return this;
}
Typical usage goes like this:
if (*np == WORD_NIL) {
STRING this;
*np = dict->size++;
this = new_string(word.word, word.length);
dict->entry[*np].string = this;
dict->entry[*np].hash = hash_word(this);
}
(code inherited from megahal, reused in wakkerbot)
As I said, I don't like this method, but the struct assignment definitely has its advantages.
Why not factor the process into two functions, so you can use whichever you need:
struct libme_string * create_string();
void destroy_string(struct libme_string *);
struct libme_string * init_string(struct libme_string * str, unsigned int length);
struct limbe_string * deinit_string(struct libme_string * str);
Usage #1, all dynamic allocations:
struct libme_string * str = init_string(create_string(), 10);
destroy_string(deinit_string(str));
Usage #2, automatic outer struct:
struct libme_string str;
init_string(&str);
deinit_string(&str);
Make sure that the init functions return the pointer, so that you can compose the calls like I did.
If deinit() also sets the pointer to zero, then you could make destroy() call deinit() if the pointer is non-zero, though that breaks the symmetry a bit.

Copy two structs in C that contain char pointers

What is the standard way to copy two structs that contain char arrays?
Here is some code:
#include stdio.h>
#include string.h>
#include stdlib.h>
typedef struct {
char* name;
char* surname;
} person;
int main(void){
person p1;
person p2;
p1.name = (char*)malloc(5);
p1.surname = (char*)malloc(5);
strcpy(p1.name, "AAAA");
strcpy(p1.surname, "BBBB");
memcpy(&p2, &p1, sizeof(person));
free(p1.name);
printf("%s\n", p2.name);
return 0;
}
The line printf("%s\n", p2.name); does not print something, because I freed the buffer.
The problem with my structs is that they are bigger than struct person. They contain hundreds of char pointers, and I have to copy every member one by one.
Is there another way to copy two structs that contain char arrays without using malloc and strcpy for every member?
You have no choice but provide a copy function yourself:
void copy_person(person *dst, const person *src)
{
dst->name = malloc(strlen(src->name) + 1);
dst->surname = malloc(strlen(src->surname) + 1);
strcpy(dst->name, src->name);
strcpy(dst->surname, src->surname);
}
which may be more elaborated than that: checking for errors, factoring the strlen + strcpy in an auxilliary function, etc.
That's what copy constructors in C++ are for.
Yes, copying struct that contain char arrays will work without any problem, but struct with char pointers (or any type of pointer for that matter) you will have to do manually.
Also note that the cast of malloc's return type is not needed in C (it is in C++) and can hide a missing prototype for malloc.
To elaborate on the answer of Alexandre C. you might want to do the malloc() as a single operation so that a free() is also simple.
This approach provides a degree of protection in that the single malloc() will either succeed or fail so that you would not have a problem of malloc() failing midway through constructing a copy. With this approach you would mix person with pointers to person that have been malloced so you might want to have two different data types something along the lines of the following in order to better mark which is which.
I have provided two alternatives for the copying with one using C Standard library functions strcpy() and strlen() and the other using a simple function that does a straight copy and returns a pointer to where it left off in the destination buffer.
I have not tried to compile this example so there may be problems with it.
There is one possible concern with this approach. Since the individual strings are not malloced you may run into a problem if you are moving the individual strings around using their pointers with the idea that each of the individual strings is its own malloced area of memory. This approach assumes the entire object is wanted or none of it is wanted.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char* name;
char* surname;
char* address1;
} person, *personptr;
// copy a string to destination string return pointer after end of destination string
char * StrCpyRetEnd (char *pDest, char *pSrc)
{
while (*pDest++ = *pSrc++);
return pDest;
}
personptr DeepCopyPerson (person *pSrc)
{
personptr pDest = 0;
unsigned int iTotalSize = sizeof(person);
iTotalSize += (strlen(pSrc->name) + 1) * sizeof(char);
iTotalSize += (strlen(pSrc->surname) + 1) * sizeof(char);
iTotalSize += (strlen(pSrc->address1) + 1) * sizeof(char);
pDest = malloc(iTotalSize);
if (pDest) {
#if 1
// alternative one without a helper function
pDest->name = (char *)(pDest + 1); strcpy (pDest->name, pSrc->name);
pDest->surname = pDest->name + strlen(pDest->name) + 1; strcpy (pDest->surname, pSrc->surname);
pDest->address1 = pDest->surname + strlen(pDest->surname) + 1; strcpy (pDest->address1, pSrc->address1);
#else
// alternative two using StrCpyRetEnd () function
pDest->name = (char *)(pDest + 1);
pDest->surname = StrCpyRetEnd (pDest->name, pSrc->name);
pDest->address1 = StrCpyRetEnd (pDest->surname, pSrc->surname);
strcpy (pDest->address1, pSrc->address1);
#endif
}
return pDest;
}
int main(void){
person p1; // programmer managed person with separate mallocs
personptr p2; // created using ClonePerson()
p1.name = malloc(5);
p1.surname = malloc(5);
p1.address1 = malloc(10);
strcpy(p1.name,"AAAA");
strcpy(p1.surname,"BBBB");
strcpy(p1.address1,"address1");
p2 = DeepCopyPerson (&p1);
free(p1.name);
printf("%s\n", p2->name);
free (p2); // frees p2 and all of the memory used by p2
return 0;
}
You have to allocate memory to any pointer if you want to do a copy. However you can always make a pointer point to already allocated memory. For example, you can do the following:
p2.name = p1.name (p1.name is already allocated memory)
This is dangerous as there are more than one reference to the same memory location. If you free either p1.name or p2.name, it results in a dangerous situation.
In order to copy the entire content you have to allocate memory to the pointers of the struct p2.
p2.name = <allocate memory>
Copy individual struct members instead of a memcpy of the entire struct
This is because memory is not allocated in a contiguous manner. Also sizeof(struct) will give you size of the members of the struct and not the memory allocated to it.
For example sizeof(p2) = 8 = sizeof(p1)= sizeof(person) even after allocating memory to members of p1.
It would be a different case had the members been char arrays.
A bit out-of-the-box thinking:
Since the structure of your struct is static, you could write a small utility program or script to generate the copy code for you.
Take the source-code of your struct definition as input, and then devise a set of rules to generate the copying code.
This is quickshot, and I don't know if it were faster to just write the copy-code manually - but at least it is a more interesting problem.

Resources