How can I make a copy of a queue in C? - c

I'm trying to COPY a queue into another queue in order that if I destroy one, it doesn't destroy the other one.
I tried using memcpy this way:
memcpy(queue1, queue2, sizeof(queue2));
But I get the following error:
expected ‘void * restrict’ but argument is of type 'Queue'
Is it possible to copy one queue into another?
EDIT
This is the structure of the queue:
typedef char *Following;
typedef struct _NodeQ {
Following element;
struct _NodeQ * next;
} NodeQ;
typedef struct {
int error;
NodeQ * first;
NodeQ * last;
} Queue;

memcpy is definitely not the way, because that would only get you as far as performing a "shallow copy". If you consider that your object can store pointers to external data, a shallow copy of that object will point to the exact same external data instead of duplicating everything ("deep copy").
(image source)
The method to perform a deep copy is entirely dependant on the implementation. It seems like your queue is using a simple linked list implementation (see how each NodeQ struct contains a pointer to another NodeQ struct, which has a pointer to another one, and so on). That is very common in C. The difficult part is figuring out how to copy the "data" portion of each object inside the queue (in this case the Following type variable). I can't tell what kind of library or framework you are using which defines the Queue type, you should refer to some documentation to help you on the specifics. Who knows, maybe you'll find a supported by the library way of copying the way you want. Nevertheless, I will attempt to do what you want, with some assumptions.
Speculation from this point onward
This is only a guess, but it seems like Following could represent a string, since it is a char pointer. The code I've written below uses this assumption. Note though that it is untested and a bit rushed, I'm just trying to illustrate how performing a manual deep copy may looks like in your scenario.
Queue queue2;
NodeQ *e2, *e2prev = NULL, *e2first = NULL;
// Iterate through all elements of the first queue
for (NodeQ *e1 = queue1.first; e1; e1 = e1->next) {
// Allocate memory for the new element of queue 2
if (!(e2 = (NodeQ*)malloc(sizeof(NodeQ)))) {
printf("not enough memory\n");
}
// Remember the first element of queue for future use
if (!e2first)
e2first = e2;
// Note that strlen here could cause a segfault if my guess that "element" is a string is wrong
size_t buflen = strlen(e1->element) + 1; // +1 for null terminator
if (!(e2->element = (Following)malloc(sizeof(char) * buflen))) {
printf("not enough memory\n");
}
strcpy(e2->element, e1->element);
e2->next = NULL;
// Link new element with previous element
if (e2prev)
e2prev->next = e2;
e2prev = e2;
}
queue2.error = queue1.error;
queue2.first = e2first;
queue2.last = e2;

Your compiler is warning you that memcpy wants two pointers as first argument. This would be the correct way to copy:
memcpy(&queue1, &queue2, sizeof(queue2));
The above line will overwrite the structure queue1 with the contents of queue2, effectively copying quque2 over queue1.

Related

Linked List function explanation, subscription of a structure pointer

Programming a simple singly-linked-list in C, I came about this repository on Github: https://github.com/clehner/ll.c while looking for some examples.
There is the following function (_list_next(void *)):
struct list
{
struct list *next; // on 64-bit-systems, we have 8 bytes here, on 32-bit-systems 4 bytes.
void *value[]; // ISO C99 flexible array member, incomplete type, sizeof may not be applied and evaluates to zero.
};
void *_list_next(void *list)
{
return list ? ((struct list *)list)[-1].next : NULL; // <-- what is happening here?
}
Could you explain how this works?
It looks like he is casting a void pointer to a list pointer and then subscripting that pointer. How does that work and what exactly happens there?
I don't understand purpose of [-1].
This is undefined behavior that happens to work on the system where the author has tried it.
To understand what is going on, note the return value of _ll_new:
void * _ll_new(void *next, size_t size)
{
struct ll *ll = malloc(sizeof(struct ll) + size);
if (!ll)
return NULL;
ll->next = next;
return &ll->value;
}
The author gives you the address of value, not the address of the node. However, _list_next needs the address of struct list: otherwise it would be unable to access next. Therefore, in order to get to next member you need to find its address by walking back one member.
That is the idea behind indexing list at [-1] - it gets the address of next associated with this particular address of value. However, this indexes the array outside of its valid range, which is undefined behavior.
Other functions do that too, but they use pointer arithmetic instead of indexing. For example, _ll_pop uses
ll--;
which achieves the same result.
A better approach would be using something along the lines of container_of macro.

Need to check if struct has been initialized

Hi I am making a Queue abstact data type and I ran into a problem which I will try to explain as clearly as possible.
Basically I have a two structs one for an element and one for a queue (so you can initialize multiple queues).
struct element
{
TYPE value;
struct element* next;
};
struct queue
{
struct element* head;
struct element* tail;
int element_counter;
};
And I have a function which initializes my queue struct.
int make_new_queue(struct queue* name)
{
name = malloc(sizeof(struct queue));
name->head = NULL;
name->tail = NULL;
name->element_counter = 0;
}
The problem I ran into is foolproofing this code. For example I initialised my first queue in my main function.
struct queue* first = make_new_queue(first);
But if somebody tries to do the same thing again somewhere in the middle of the code write:
first = make_new_queue(first);
it overrides it and makes the head and tail pointers NULL. The thing I can't figure out is how to make my make_new_queue function better and check if there is something in the queue that I provide it, but still let me initialise empty queues.
Sorry for my english. I hope you get the idea of what I want to do. Thanks.
Initialize it to NULL and pass a pointer to pointer:
void make_new_queue(struct queue **name)
{
if (*name != NULL) return; /* Yet initialized ? */
*name = malloc(sizeof(struct queue));
if (*name == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
*name->head = NULL;
*name->tail = NULL;
*name->element_counter = 0;
}
struct queue *first = NULL;
make_new_queue(&first);
You can simply check if you variable name is NULL.
If your variable is non-null, you can alloc and initialize your queue else just do what you want to do.
There is really no good way to enforce what you want without discipline from the user. In my opinion, the best approach is to stick to known patterns.
You can use Alter Mann's approach to pass a pointer to a pointer to update the struct. The drawback is that is that you have to separate variable declaration and initialisation. It also relies on the user to initialise the pointer to the struct to NULL. If you forget it, the queue pointer will not be initialised and you don't even know, because you can't check against NULL.
struct stuff *stuff = NULL;
stuff_initialise(&stuff);
You can use your original approach to pass in the struct and return the same struct when it was initialised or a new one. It has the same problems as the first approach plus the possibility that you forget to assign the return value. You can, however, combine allocation and initialisation:
struct stuff *stuff = stuff_new(NULL);
The simplest way is not to pass the old pointer and rely on the user not to change the pointer after allocation. After all, the functions of the standard library suffer from the same problem:
char *buf = malloc(BUFSIZE);
buf = malloc(2 * BUFSIZE); // Memory leak
buf++; // Allowed, but a bad idea
free(buf); // Ouch!
FILE *f = fopen("palomino.txt", "r");
f = stdin; // Switch horses midstream?
You should design your API so that you have matching pairs of functions that define the scope of your struct:
struct stuff *stuff = stuff_create(...);
// use stuff ...
stuff_destroy(stuff);
Good naming should make clear that stuff acts as a handle and should not be changed and that after closing or destroying the handle, it is invalid. You should see these calls as first and last statements in functions. (This method is similar to the malloc/free or fopen/fclose pairngs of the standard library.)
Finally, if you as the user of a handle want to avoid accidential changes, you can define the pointer (not what it points to) as const:
struct stuff *const handle = stuff_create("X");
handle = stuff_create("Y"); // Compiler error
But I rarely see this. C programmers usually just use an unadorned pointer and remember to keep their fingers off the hotplate.

Trouble with pointers while making hashmap in C

for a C introduction I need to make a hashmap. These are the structures that I made so far:
typedef struct HashEntry {
char *key;
void* data;
struct HashEntry *next;
}HashEntry;
typedef struct HashMap {
size_t key_space;
hash_function* function;
HashEntry *data;
}HashMap;
When I want to make a new hashlist, I use these commands:
HashMap *hm = calloc(1, sizeof(HashMap));
hm->data = calloc(key_space, sizeof(HashEntry));
So far I guess this is a good design, but I have some problems when I want to add a value that has a key that already exists in my map. (In that case, I want the old value to be free'ed, and the new value to be allocated.
I thought that the following code shoud do the trick:
void* old = current->data;
free(old);
current->data=malloc(length);
current->data = newData; // newdata is a void* type
However my code just stops running, I guess I made a mistake with the pointers but after trying to find it for quite a while I'm a bit depressed.
Do you guys know what I am doing wrong?
Some clarification after the questions:
the code stops executing after:
free(old);
If I uncomment this it works, but why wouldn't I be able to free the data?
Length is de size of the void* string that I want to save.
You most likely need to replace
current->data = newData;
with something like
memcpy(current->data, newData, length);
I assume newData is a pointer to your new data. And current->data is the pointer to the memory you first free and then allocate again.
In order to be able to use memcpy() you must add #include <string.h> at the top of your file.
Your original code may seem to work when you uncomment the free(old) since you then just enter the original newData pointers into your hashmap. If you try to free() them later bad things happen. I assume you want to enter the data contained in newData into the hasmap, not just the pointer to the data.
Note that the compiler will be of little help here. C is not a managed language, which means you need to maintain the lifetime of all your chunks of memories and semantics of all your pointers yourself. Some pointers point to malloc'd memory, some point to static data, it is really up to you and your program to maintain consistency.

C generic linked-list

I have a generic linked-list that holds data of type void* I am trying to populate my list with type struct employee, eventually I would like to destruct the object struct employee as well.
Consider this generic linked-list header file (i have tested it with type char*):
struct accListNode //the nodes of a linked-list for any data type
{
void *data; //generic pointer to any data type
struct accListNode *next; //the next node in the list
};
struct accList //a linked-list consisting of accListNodes
{
struct accListNode *head;
struct accListNode *tail;
int size;
};
void accList_allocate(struct accList *theList); //allocate the accList and set to NULL
void appendToEnd(void *data, struct accList *theList); //append data to the end of the accList
void removeData(void *data, struct accList *theList); //removes data from accList
--------------------------------------------------------------------------------------
Consider the employee structure
struct employee
{
char name[20];
float wageRate;
}
Now consider this sample testcase that will be called from main():
void test2()
{
struct accList secondList;
struct employee *emp = Malloc(sizeof(struct employee));
emp->name = "Dan";
emp->wageRate =.5;
struct employee *emp2 = Malloc(sizeof(struct employee));
emp2->name = "Stan";
emp2->wageRate = .3;
accList_allocate(&secondList);
appendToEnd(emp, &secondList);
appendToEnd(emp2, &secondList);
printf("Employee: %s\n", ((struct employee*)secondList.head->data)->name); //cast to type struct employee
printf("Employee2: %s\n", ((struct employee*)secondList.tail->data)->name);
}
Why does the answer that I posted below solve my problem? I believe it has something to do with pointers and memory allocation. The function Malloc() that i use is a custom malloc that checks for NULL being returned.
Here is a link to my entire generic linked list implementation: https://codereview.stackexchange.com/questions/13007/c-linked-list-implementation
The problem is this accList_allocate() and your use of it.
struct accList secondList;
accList_allocate(&secondList);
In the original test2() secondList is memory on the stack. &secondList is a pointer to that memory. When you call accList_allocate() a copy of the pointer is passed in pointing at the stack memory. Malloc() then returns a chunk of memory and assigns it to the copy of the pointer, not the original secondList.
Coming back out, secondList is still pointing at uninitialised memory on the stack so the call to appendToEnd() fails.
The same happens with the answer except secondList just happens to be free of junk. Possibly by chance, possibly by design of the compiler. Either way it is not something you should rely on.
Either:
struct accList *secondList = NULL;
accList_allocate(&secondList);
And change accList_allocate()
accList_allocate(struct accList **theList) {
*theList = Malloc(sizeof(struct accList));
(*theList)->head = NULL;
(*theList)->tail = NULL;
(*theList)->size = 0;
}
OR
struct accList secondList;
accList_initialise(secondList);
With accList_allocate() changed to accList_initialise() because it does not allocate
accList_initialise(struct accList *theList) {
theList->head = NULL;
theList->tail = NULL;
theList->size = 0;
}
I think that your problem is this:
You've allocated secondList on the stack in your original test2 function.
The stack memory is probably dirty, so secondList requires initialization
Your accList_allocate function takes a pointer to the list, but then overwrites it with the Malloc call. This means that the pointer you passed in is never initialized.
When test2 tries to run, it hits a bad pointer (because the memory isn't initialized).
The reason that it works when you allocate it in main is that your C compiler probably zeros the stack when the program starts. When main allocates a variable on the stack, that allocation is persistent (until the program ends), so secondList is actually, and accidentally, properly initialized when you allocate it in main.
Your current accList_allocate doesn't actually initialize the pointer that's been passed in, and the rest of your code will never see the pointer that it allocates with Malloc. To solve your problem, I would create a new function: accList_initialize whose only job is to initialize the list:
void accList_initialize(struct accList* theList)
{
// NO malloc
theList->head = NULL;
theList->tail = NULL;
theList->size = 0;
}
Use this, instead of accList_allocate in your original test2 function. If you really want to allocate the list on the heap, then you should do so (and not mix it with a struct allocated on the stack). Have accList_allocate return a pointer to the allocated structure:
struct accList* accList_allocate(void)
{
struct accList* theList = Malloc( sizeof(struct accList) );
accList_initialize(theList);
return theList;
}
Two things I see wrong here based on the original code, in the above question,
What you've seen is undefined behaviour and arose from that is the bus error message as you were assigning a string literal to the variable, when in fact you should have been using the strcpy function, you've edited your original code accordinly so.. something to keep in mind in the future :)
The usage of the word Malloc is going to cause confusion, especially in peer-review, the reviewers are going to have a brain fart and say "whoa, what's this, should that not be malloc?" and very likely raise it up. (Basically, do not call custom functions that have similar sounding names as the C standard library functions)
You're not checking for the NULL, what if your souped up version of Malloc failed then emp is going to be NULL! Always check it no matter how trivial or your thinking is "Ah sher the platform has heaps of memory on it, 4GB RAM no problem, will not bother to check for NULL"
Have a look at this question posted elsewhere to explain what is a bus error.
Edit: Using linked list structures, in how the parameters in the function is called is crucial to the understanding of it. Notice the usage of &, meaning take the address of the variable that points to the linked list structure, and passing it by reference, not passing by value which is a copy of the variable. This same rule applies to usage of pointers also in general :)
You've got the parameters slightly out of place in the first code in your question, if you were using double-pointers in the parameter list then yes, using &secondList would have worked.
It may depend on how your Employee structure is designed, but you should note that
strcpy(emp->name, "Dan");
and
emp->name = "Dan";
function differently. In particular, the latter is a likely source of bus errors because you generally cannot write to string literals in this way. Especially if your code has something like
name = "NONE"
or the like.
EDIT: Okay, so with the design of the employee struct, the problem is this:
You can't assign to arrays. The C Standard includes a list of modifiable lvalues and arrays are not one of them.
char name[20];
name = "JAMES" //illegal
strcpy is fine - it just goes to the memory address dereferenced by name[0] and copies "JAMES\0" into the memory there, one byte at a time.

C char array getting corrupted after being passed into function

I'm trying to implement a program similar to 20 Questions, in which a text file of the questions and guesses for answers are loaded, copied into a char array (where the new space lines are replaced by '/0' in order to split the questions into individual strings). The array works fine after the text file is copied into it. A tree structure is set up to organize the phrases into the yes/no question tree, where the left child is the yes response, while the right is the no response, and leaves are the guesses that the program uses to guess at the end.
The issue that I'm having is that after I build the tree (call treeBuilder from InitTree), the contents of the array where the phrases from the text file were copied became corrupted.
Before I call InitTree, the array contents look like this:
Is it furry? Does it meow? a cat a dog Does it have tusks? Does it have big ears? an elephant a rhinoceros an alligator
After calling it, it looks like this:
Is it furry? -???` ?p ?a dog Does it have tusks? Does it have big ears? an elephant a rhinoceros an alligator
I've been testing where it stops working, and within treeBuilder, all of the elements of the array are intact, but as soon as the function call to treeBuilder ends, the array becomes corrupted. I've tried protecting the memory by using calloc whenever I allocate memory, and even by making the character array static, which worked in a similar situation where this happened. But all of my preventative measures don't seem to be working and I'm not sure where the problem lies. I've already tried looking at similar cases here on stackoverflow but I couldn't anything that related to my issue.
This eventually leads to a seg fault, when the program actually starts to use the tree, for obvious reasons.
I've tried running gdb, but for whatever reason it won't let me go through line by line, because it cannot find the line information, and just skips everything until it either prompts for input, or gets a memory error or something, so running gdb isn't very helpful here. I'm guessing this might be because the main function is in an included file or something. But that's beside the point.
Here's the code related to the problem:
struct treeStruct {
char *string;
struct treeStruct *left, *right;
};
typedef struct treeStruct *TreeType;
// Builds a tree
void treeBuilder(TreeType tree, char **phrase, long level){
// Gets the level (number of tabs) of the next phrase
long nextLevel = countTabs(*phrase + strlen(*phrase) + 1);
tree->string = *phrase + level; // Assigns the response pointer to the tree array
// Move the pointer to the next string, since the the strings need to be
// put into the tree in linear order
(*phrase) += strlen(*phrase) + 1;
if (level >= nextLevel){
// Compares the current level with the level of the next string
// to determine if returning up the tree is necessary;
// This should be the answer to a question.
tree->left = NULL;
tree->right = NULL;
return;
}
else{
// Makes sure the left and right pointers of the struct have
// allocated space
tree->left = calloc(1, sizeof(TreeType));
tree->right = calloc(1, sizeof(TreeType));
// Adds the yes and no branches to the tree, recursion will take care
// of adding sub-branches
treeBuilder(tree->left, phrase, level + 1);
treeBuilder(tree->right, phrase, level + 1);
}
return;
}
TreeType InitTree (char *file){
if(file == NULL){
printf("File '%s' does not exist.\n", file);
exit(2);
}
FILE *fp;
fp = fopen(file, "r");
// Create a space in memory for the loaded questions to occupy
static char *phrases;
phrases = (char *)malloc(MAXSTR * MAXNUMQS * sizeof(char));
copyText(fp, phrases);
fclose(fp);
// Create space in memory for the tree structure
TreeType tree;
tree = (TreeType) calloc(1, sizeof(TreeType));
// Create a pointer to a pointer so that treeBuilder can
// change what the first pointer is pointing to, so the strings in
// phrases can be added in order throughout the recursion
static char *phrase_ptr, **phrase_ptr2;
phrase_ptr = &phrases[0];
phrase_ptr2 = &phrase_ptr;
//Build the tree
treeBuilder(tree, phrase_ptr2, 0);
topNode = tree;
return tree;
}
Sorry if this is tl;dr, but I wanted to be as clear as possible on my issue.
Just one thing I noticed is that you're using sizeof(TreeType), but TreeType is a pointer to a struct and not the struct itself. This means that you are creating a pointer that is pointing to nowhere, and that dereferencing the pointer will lead to undefined behaviour. Which having just read the rest of the question would certainly explain the segfaults.
I think you would be better off not typedef-ing your struct as a pointer, and be more explicit with your use of pointers.
eg.
typedef struct treeStruct TreeType;
void treeBuilder(TreeType *tree, char **phrase, long level){
...
if (!tree->left) {
// calloc returns a pointer to a new bit of memory that has been
// assigned on the heap
TreeType *temp = calloc(1, sizeof(TreeType));
// assignments below not explicitly needed as you're using calloc
temp->string = NULL;
temp->left = NULL;
temp->right = NULL;
tree->left = temp;
}
...
}
Here's a question about typedef-ing pointers. Seems to be relatively common in C, and used to imply that the data type is opaque and should not be dereferenced by the user (only by the API calls that the user passes it to).

Resources