I am trying to implement a queue in C (using this implementation) where, given an input file with some number of lines each containing 5 values, a struct Item is created for that line and the values are assigned to the struct variables value1...value5. The struct is then placed in a queue, so the first line of the file will be the first struct in the queue, and the last line will be the last struct.
However, I am getting some weird behaviour when trying to read values from the structs in the queue. The end of the code segment below prints value1 and value5 as a debug check to make sure the values are correct. It should print struct1->value1 and struct1->value5 for both head and tail on the first iteration, and then struct1->value1 and struct1->value5 for head and struct2->value1 and struct2->value5 for tail on the second iteration, but instead it prints strange large values for both head and tail. (plus, it seems to forget about the first struct altogether.) What am I doing wrong here?
Sample file:
1 0 10 1 3
2 0 10 10 1
------------
/* read input file */
/* while the current line of the file is not null */
...
/* create new item */
Item *newItem = malloc(sizeof(Item));
/* string tokenizer */
/* adds tokens from current line to tokens[i] */
...
/* set item variables */
newItem->value1 = strtol(tokens[0], NULL, 10); //should contain e.g. 1
newItem->value2 = strtol(tokens[1], NULL, 10); //should contain e.g. 0
newItem->value3 = strtol(tokens[2], NULL, 10); //should contain e.g. 10
newItem->value4 = strtol(tokens[3], NULL, 10); //should contain e.g. 1
newItem->value5 = strtol(tokens[4], NULL, 10); //should contain e.g. 3
/* add to item queue */
queue_push_tail(itemQueue, &newItem);
/* check queue values */
if(!queue_is_empty(itemQueue)) { //after two lines,
Item *itemHead = queue_peek_head(itemQueue); //this should differ...
printf("Head: %d %d\n", itemHead->value1, itemHead->value5);
Item *itemTail = queue_peek_tail(processQueue); //...from this
printf("Tail: %d %d\n", itemTail->value1, itemTail->value5);
}
Expected output:
Head: 1 3 //when first line is read
Tail: 1 3
Head: 1 3 //when second line is read
Tail: 2 1
Actual output:
Head: 146752 -4196581 //when first line is read
Tail: 146752 -4196581
Head: 146792 -4196581 //when second line is read
Tail: 146792 -4196581
This:
queue_push_tail(itemQueue, &newItem);
doesn't look right, it doesn't match how you peek items from the queue. If the queue is storing pointers, hand it newItem, not the address of newItem.
Related
For one of my school assignments I have to make my own stack library and a POSTFIX calculator.
The calculator has to make use of the stack library and do some calculations.
I am pushing two different numbers to my stack. Number 6 and 3. The header should point to the most recently added node (LIFO). So when 6 is added:
HEADER -> 6 -> NULL
When 3 is being added:
HEADER -> 3 -> 6 -> NULL
When I print the value of my header after adding '6' it's good. It's printing 6.
However, when I print the value of my header BEFORE adding '3' it's printing '3'. When it still should print 6.
So a summary of my problem:
When adding another node to my linkedlist, the header suddenly points to the newest node before even changing it.
You may understand me better with some code and debugging results.
Btw: Don't mind the typedefs, I don't like them. My teacher wants us to use it.
typedef struct stackObject* pStackObject_t;
typedef struct stackObject
{
void* obj;
pStackObject_t next;
} StackObject_t;
typedef struct stackMEta* pStackMeta_t;
typedef struct stackMEta
{
pStackObject_t stack;
size_t objsize;
int numelem; //number of elements
int handle; //welke stack
pStackMeta_t next;
} StackMeta_t;
int mystack_push(int handle, void* obj)
{
**DELETED NON RELATED CODE BASED ON FEEDBACK**
if (currentMeta->handle == handle)
{
pStackObject_t newObject = malloc(sizeof(StackObject_t));
newObject->obj = obj;
printf("%s%d\n", "Wanting to push int to stack: ", *(int*)obj);
//First node
if (currentMeta->stack == NULL)
{
currentMeta->stack = newObject;
currentMeta->stack->next = NULL;
printf("%s%d\n", " FIRST Curentmeta->stack pointing to ", *(int*)currentMeta->stack->obj);
return 0;
}
else
{
printf("%s%d\n", "NOT FIRST Currentmeta->stack pointing to ", *(int*)currentMeta->stack->obj);
newObject->next = currentMeta->stack;
currentMeta->stack = newObject;
printf("%s%d\n", "Currentmeta->stack ", *(int*)currentMeta->stack->obj);
printf("%s%d\n", "Currentmeta->stack->next ", *(int*)currentMeta->stack->next->obj);
printf("%s%d\n", "Succesful pushed int to stack: ", *(int*)currentMeta->stack->obj);
return 0;
}
}
return -1;
}
Terminal:
Created stack with handle: 1 and objsize 4 bytes
Wanting to push int to stack: 6
FIRST Curentmeta->stack pointing to 6
Wanting to push int to stack: 3
NOT FIRST Currentmeta->stack pointing to 3
Currentmeta->stack 3
Currentmeta->stack->next 3
Succesful pushed int to stack: 3
My unit tests are performing good with this code. My calculator does not, while it's the same function call.
I found out that it was working 50/50. Using the same input values in another program resulted in good things.
I changed the code to this:
pStackObject_t newObject = malloc(sizeof(StackObject_t));
newObject->obj = malloc(sizeof(currentMeta->objsize));
memcpy(newObject->obj, obj, currentMeta->objsize);
Now it's working fine. The previous code was somehow using the old values, while it was already out of scope. Thanks everyone for the help.
I'm trying to add strings to a Binary Search Tree using a recursive insert method (the usual for BSTs, IIRC) so I can later print them out using recursion as well.
Trouble is, I've been getting a segmentation faults I don't really understand. Related code follows (this block of code is from my main function):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// Stores the size of the C-strings we will use;
// Standardized to 100 (assignment specifications say
// ALL strings will be no more than 100 characters long)
// Please note that I defined this as a preprocessor
// directive because using the const keyword makes it
// impossible to define the size of the C-String array
// (C doesn't allow for static array struct members whose
// size is given as a variable)
#define STRING_SIZE 100
// The flags for case sensitivity
// and an output file
int cflag = 0, oflag = 0;
// These are intended to represent the boolean
// values true and false (there's no native bool
// data type in C, apparently)
const int TRUE = 1;
const int FALSE = 0;
// Type alias for the bool type
typedef int bool;
// This is the BST struct. A BST is basically just
// a Node with at most two children (left and right)
// and a data element.
typedef struct BST
{
struct BST *left;
struct BST *right;
char *key;
int counter;
} BST;
// ----- FUNCTION PROTOTYPES -----
void insert(BST **root, char *key);
int caseSenStrCmp(char *str1, char *str2);
int caseInsenStrCmp(char *str1, char *str2);
bool existsInTree(BST *root, char *key, int cflag);
void inOrderPrint(BST *root, int oflag, FILE *outFile);
void deallocateTree(BST *root);
int main(int argc, char **argv) {
extern char *optarg;
extern int optind;
int c, err = 0;
// Holds the current line in the file/user-provided string.
char currentLine[STRING_SIZE];
// This will store the input/output file
// directories
char fileDirectory[STRING_SIZE];
static char usage[] = "Usage: %s [-c] [-o output_file_name] [input_file_name]\n";
while ((c = getopt(argc, argv, "co:")) != -1)
switch (c)
{
case 'c':
cflag = 1;
break;
case 'o':
oflag = 1;
// If an output file name
// was entered, copy it
// to fileDirectory
if (argv[optind] != NULL)
{
strcpy(fileDirectory, argv[optind]);
}
break;
case '?':
err = 1;
break;
default:
err = 1;
break;
}
if (err)
{
// Generic error message
printf("ERROR: Invalid input.\n");
fprintf(stderr, usage, argv[0]);
exit(1);
}
// --- BST SORT CODE STARTS HERE ---
printf("This is BEFORE setting root to NULL\n");
// This is the BST. As the assignment instructions
// specify, it is initially set to NULL
BST *root = NULL;
// Pointer to the mode the files
// will be opened in. Starts as
// "w" since we're opening the output file
// first
printf("This is AFTER setting root to NULL\n");
char *mode = (char*)malloc(sizeof(char*));
strcpy(mode, "w");
printf("Wrote w to mode pointer");
// Pointer to the output file
FILE *outFile;
// Attempt to open output file
outFile = fopen(fileDirectory, mode);
printf("Opened outfile \n");
// Now update mode and fileDirectory so
// we can open the INPUT file
strcpy(mode, "r");
printf("Wrote r to mode\n");
// Check if we have an input file name
// If argv[optind] isn't NULL, that means we have
// an input file name, so copy it into fileDirectory
if (argv[optind] != NULL)
{
strcpy(fileDirectory, argv[optind]);
}
printf("Wrote input file name to fileDirectory.\n");
// Pointer to the input file
FILE *inFile;
// Attempt to open the input file
//printf("%d", inFile = fopen(fileDirectory, mode));
printf("Opened input file\n");
// If the input file was opened successfully, process it
if (inFile != NULL)
{
// Process the file while EOF isn't
// returned
while (!feof(inFile))
{
// Get a single line (one string)
//fgets(currentLine, STRING_SIZE, inFile);
printf("Wrote to currentLine; it now contains: %s\n", currentLine);
// Check whether the line is an empty line
if (*currentLine != '\n')
{
// If the string isn't an empty line, call
// the insert function
printf("currentLine wasn't the NULL CHAR");
insert(&root, currentLine);
}
}
// At this point, we're done processing
// the input file, so close it
fclose(inFile);
}
// Otherwise, process user input from standard input
else
{
do
{
printf("Please enter a string (or blank line to exit): ");
// Scanf takes user's input from stdin. Note the use
// of the regex [^\n], allowing the scanf statement
// to read input until the newline character is encountered
// (which happens when the user is done writing their string
// and presses the Enter key)
scanf("%[^\n]s", currentLine);
// Call the insert function on the line
// provided
insert(&root, currentLine);
} while (caseSenStrCmp(currentLine, "") != 0);
}
// At this point, we've read all the input, so
// perform in-order traversal and print all the
// strings as per assignment specification
inOrderPrint(root, oflag, outFile);
// We're done, so reclaim the tree
deallocateTree(root);
}
// ===== AUXILIARY METHODS ======
// Creates a new branch for the BST and returns a
// pointer to it. Will be called by the insert()
// function. Intended to keep the main() function
// as clutter-free as possible.
BST* createBranch(char *keyVal)
{
// Create the new branch to be inserted into
// the tree
BST* newBranch = (BST*)malloc(sizeof(BST));
// Allocate memory for newBranch's C-string
newBranch->key = (char*)malloc(STRING_SIZE * sizeof(char));
// Copy the user-provided string into newBranch's
// key field
strcpy(newBranch->key, keyVal);
// Set newBranch's counter value to 1. This
// will be incremented if/when other instances
// of the key are inserted into the tree
newBranch->counter = 1;
// Set newBranch's child branches to null
newBranch->left = NULL;
newBranch->right = NULL;
// Return the newly created branch
return newBranch;
}
// Adds items to the BST. Includes functionality
// to verify whether an item already exists in the tree
// Note that we pass the tree's root to the insert function
// as a POINTER TO A POINTER so that changes made to it
// affect the actual memory location that was passed in
// rather than just the local pointer
void insert(BST **root, char *key)
{
printf("We made it to the insert function!");
// Check if the current branch is empty
if (*root == NULL)
{
// If it is, create a new
// branch here and insert it
// This will also initialize the
// entire tree when the first element
// is inserted (i.e. when the tree is
// empty)
*root = createBranch(key);
}
// If the tree ISN'T empty, check whether
// the element we're trying to insert
// into the tree is already in it
// If it is, don't insert anything (the
// existsInTree function takes care of
// incrementing the counter associated
// with the provided string)
if (!existsInTree(*root, key, cflag))
{
// If it isn't, check if the case sensitivity
// flag is set; if it is, perform the
// checks using case-sensitive string
// comparison function
if (cflag) {
// Is the string provided (key) is
// greater than the string stored
// at the current branch?
if (caseSenStrCmp((*root)->key, key))
{
// If so, recursively call the
// insert() function on root's
// right child (that is, insert into
// the right side of the tree)
// Note that we pass the ADDRESS
// of root's right branch, since
// the insert function takes a
// pointer to a pointer to a BST
// as an argument
insert(&((*root)->right), key);
}
// If not, the key passed in is either less than
// or equal to the current branch's key,
// so recursively call the insert()
// function on root's LEFT child (that is,
// insert into the left side of the tree)
else
{
insert(&((*root)->left), key);
}
}
// If it isn't, perform the checks using
// the case-INsensitive string comparison
// function
else {
// The logic here is exactly the same
// as the comparisons above, except
// it uses the case-insensitive comparison
// function
if (caseInsenStrCmp((*root)->key, key))
{
insert(&((*root)->right), key);
}
else
{
insert(&((*root)->left), key);
}
}
}
}
// CASE SENSITIVE STRING COMPARISON function. Returns:
// -1 if str1 is lexicographically less than str2
// 0 if str1 is lexicographically equal to str2
// 1 if str2 is lexicographically greater than str1
I'm using getopt to parse options that the user enters. I've been doing a little bit of basic debugging using printf statements just to see how far I get into the code before it crashes, and I've more or less narrowed down the cause. It seems to be this part here:
do
{
printf("Please enter a string (or blank line to exit): ");
// Scanf takes user's input from stdin. Note the use
// of the regex [^\n], allowing the scanf statement
// to read input until the newline character is encountered
// (which happens when the user is done writing their string
// and presses the Enter key)
scanf("%[^\n]s", currentLine);
// Call the insert function on the line
// provided
insert(&root, currentLine);
} while (caseSenStrCmp(currentLine, "\n") != 0);
Or rather, calls to the insert function in general, since the printf statement I put at the beginning of the insert function ("We made it to the insert function!) gets printed over and over again until the program finally crashes with a segmentation fault, which probably means the problem is infinite recursion?
If so, I don't understand why it's happening. I initialized the root node to NULL at the beginning of main, so it should go directly into the insert functions *root == NULL case, at least on its first call.
Does it maybe have something to do with the way I pass root as a pointer to a pointer (BST **root in parameter list of insert function)? Am I improperly recursing, i.e. is this statement (and others similar to it)
insert(&((*root)->right), key);
incorrect somehow? This was my first guess, but I don't see how that would cause infinite recursion - if anything, it should fail without recursing at all if that was the case? Either way, it doesn't explain why infinite recursion happens when root is NULL (i.e. on the first call to insert, wherein I pass in &root - a pointer to the root pointer - to the insert function).
I'm really stuck on this one. At first I thought it might have something to do with the way I was copying strings to currentLine, since the line
if(*currentLine != '\0')
in the while (!feof(inFile)) loop also crashes the program with a segmentation fault, but even when I commented that whole part out just to test the rest of the code I ended up with the infinite recursion problem.
Any help at all is appreciated here, I've been trying to fix this for over 5 hours to no avail. I legitimately don't know what to do.
**EDIT: Since a lot of the comments involved questions regarding the way I declared other variables and such in the rest of the code, I've decided to include the entirety of my code, at least until the insert() function, which is where the problem (presumably) is. I only omitted things to try and keep the code to a minimum - I'm sure nobody likes to read through large blocks of code.
Barmar:
Regarding fopen() and fgets(): these were commented out so that inFile would remain NULL and the relevant conditional check would fail, since that part of the code also fails with a segmentation fault
createBranch() does initialize both the left and right children of the node it creates to NULL (as can be seen above)
currentLine is declared as an array with a static size.
#coderredoc:
My understanding of it is that it reads from standard input until it encounters the newline character (i.e. user hits the enter button), which isn't recorded as part of the string
I can already see where you were going with this! My loop conditional was set for the do/while loop was set to check for the newline character, so the loop would never have terminated. That's absolutely my fault; it was a carryover from a previous implementation of that block that I forgot to change.
I did change it after you pointed it out (see new code above), but unfortunately it didn't fix the problem (I'm guessing it's because of the infinite recursion happening inside the insert() function - once it gets called the first time, it never returns and just crashes with a segfault).
**
I managed to figure it out - turns out the problem was with the insert() function after all. I rewrote it (and the rest of the code that was relevant) to use a regular pointer rather than a pointer to a pointer:
BST* insert(BST* root, char *key)
{
// If branch is null, call createBranch
// to make one, then return it
if (root == NULL)
{
return createBranch(key);
}
// Otherwise, check whether the key
// already exists in the tree
if (!existsInTree(root, key, cflag))
{
// If it doesn't, check whether
// the case sensitivity flag is set
if (cflag)
{
// If it is, use the case-sensitive
// string comparison function to
// decide where to insert the key
if (caseSenStrCmp(root->key, key))
{
// If the key provided is greater
// than the string stored at the
// current branch, insert into
// right child
root->right = insert(root->right, key);
}
else
{
// Otherwise, insert into left child
root->left = insert(root->left, key);
}
}
// If it isn't, use the case-INsensitive string
// comparison function to decide where to insert
else
{
// Same logic as before. If the key
// provided is greater, insert into
// current branch's right child
if (caseInsenStrCmp(root->key, key))
{
root->right = insert(root->right, key);
}
// Otherwise, insert into the left child
else
{
root->left = insert(root ->left, key);
}
}
}
// Return the root pointer
return root;
}
Which immediately solved the infinite recursion/seg fault issue. It did reveal a few other minor semantic errors (most of which were probably made in frustration as I desperately tried to fix this problem without rewriting the insert function), but I've been taking care of those bit by bit.
I've now got a new problem (albeit probably a simpler one than this) which I'll make a separate thread for, since it's not related to segmentation faults.
Happy New Year.
This question arises from a project to program a game called Laby-chiffres in C. To see the game look in the third batch of games on this link: http://www.rci-jeux.com/jeux/labychiffres/laby.swf .
Context:
I am using a linked list to store the path taken by a player through a grid of numbers. The player's aim is to find a path from the departure point to the arrival point, with a given length and given total of the numbers in the path. There is a switch statement for a menu and then one to accept the direction the player wants to move in. This works as I have code that shows that the 'passage' of the player to each number is recorded correctly
Problem:
When I try to print the path (which is a requirement of the assignment - and useful for the player to see) I print the path in the correct order, except that the last element, i.e. where the player most recently moved to, is shown at the start and the end of the list.
Example: Player makes moves through positions with values as follows. Starting with the departure point value 5 -> 8 -> 4-> 1. What is printed at each stage is:
5->
8->8->
4->8->4->
1->8->4->1->
What I have tried
I have looked at several other linked list questions, but none I have seen have the same issue that I have.
I have tried changing lots of things, but to be honest now more experimentally than anything. For example, changing the empiler function to add elements at the wrong end prints the path in the wrong order (as expected) but still prints the most recently reached number twice, just both at the start of the path rather than one at the start and one at the end.
Relevant functions
The lecturer has said explicitly that the printing needs to reverse the order so these are the printing functions:
void affiche_chemin (PLATEAU jeu, PILE pile){
afficher_pile_inverse(&jeu , jeu.chemin.P_sommet);
printf("\n");
}
void afficher_pile_inverse(PLATEAU *P_jeu, ELEMENT *P_cur){
if(P_cur != NULL){
afficher_pile_inverse(P_jeu,P_cur->P_suivant);
printf("%d->",lire_valeur_a(P_jeu,&P_cur->valeur));
}
}
lire_valeur_a reads the value in the grid, which is part of the PLATEAU structure given below and read in from a text file. This appears to work so I am not including it to try to keep the question length down.
The function to add elements is :
ELEMENT* empiler(PILE *P_liste, ELEMENT *P_elt_ajoute){
P_elt_ajoute ->P_suivant = P_liste->P_sommet;
P_liste->P_sommet = P_elt_ajoute;
return P_elt_ajoute;
}
Given the lecturers comments about needing to reverse the order to print correctly I think I am adding elements at the right end of the list.
These functions initialise the path, and allocate a new ELEMENT, and are just given for reference as used in the next extract.
void initialiser_pile(PILE *P_pile){
P_pile->P_sommet = NULL;
}
ELEMENT *nouvel_element (POSITION nouvelle_valeur){
ELEMENT *P_elt;
P_elt =(ELEMENT*) malloc(sizeof(ELEMENT));
if(P_elt ) { /* NULL equivalent to false like 0 */
P_elt->valeur = nouvelle_valeur;
P_elt->P_suivant = NULL;
}
return P_elt;
}
This code sets up the path for the first time when the text file for the game is read, so it is the first time empiler is used to add an element to a path. (This extract is from a long function using fscanf multiple times to read the game text file, and seems to work correctly.)
ELEMENT *P_sommet = nouvel_element(PLAT->dep);
if (P_sommet == NULL){
printf("Erreur d'allocation\n");
return 0;
}
initialiser_pile(&PLAT->chemin);
empiler (&PLAT->chemin,P_sommet);
PLAT->longcur = 1;
PLAT->sumcur=PLAT->grille[PLAT->dep.indl][PLAT->dep.indc];
The following function is used for adding elements during the game.
int choix_indep_jeu_update(PLATEAU *jeu, POSITION *new_pos, int pas, int dir){
ELEMENT *new = nouvel_element(*new_pos);//1 Make new element
if (new == NULL) return 0;
empiler( &jeu->chemin, new );//should add new element
jeu->longcur++;
jeu->sumcur = jeu->sumcur + lire_valeur_a(jeu, new_pos);
affiche_grille(*jeu);
affiche_chemin(*jeu,jeu->chemin);
return 1;
}
Data Structures
typedef struct position_st{
int indl;//indice of ligne
int indc;//indice of colonne
}POSITION;
typedef struct element_st{
POSITION valeur;
struct element_st *P_suivant;
}ELEMENT;
typedef struct pile_st{
ELEMENT * P_sommet;
}PILE;
typedef struct plat_st{
//########## GAME FILE INFORMATION
int nl; //number of lines in grid
int nc; //number of columns in grid
POSITION dep; //position du depart: dep.indl and dep.indc
POSITION arr; //position d'arrive: arr.indl and arr.indc
int longdem; //length demanded
int sumdem; //total demanded
int ** grille; //Playing grid
//#######INFO re GAME IN PROGRESS ########
int longcur; //longueur courant
int sumcur; //totale courant
PILE chemin; //The path
}PLATEAU;
I simplified your code and it seems to be working, assuming that you want empiler() to insert elements into the front of the list, so they end up in reverse order. I added afficher_pile_inverse1() so that the last value doesn't have a "->" after it. So the error is in creating the list or there's an issue with the grid function which you did not show.
#include <stdio.h>
#include <stdlib.h>
typedef int POSITION;
typedef struct element_st{
POSITION valeur;
struct element_st *P_suivant;
}ELEMENT;
typedef struct pile_st{
ELEMENT * P_sommet;
}PILE;
void empiler(PILE *P_liste, ELEMENT *P_elt_ajoute){
P_elt_ajoute ->P_suivant = P_liste->P_sommet;
P_liste->P_sommet = P_elt_ajoute;
}
void afficher_pile_inverse1(ELEMENT *P_cur){
if(P_cur != NULL){
afficher_pile_inverse1(P_cur->P_suivant);
printf("%d->",P_cur->valeur);
}
}
void afficher_pile_inverse(ELEMENT *P_cur){
if(P_cur != NULL){
afficher_pile_inverse1(P_cur->P_suivant);
printf("%d",P_cur->valeur);
}
}
void affiche_chemin (PILE pile){
afficher_pile_inverse(pile.P_sommet);
printf("\n");
}
int main(void){
ELEMENT ae[4] = {{0,NULL},{1,NULL},{2,NULL},{3,NULL}};
PILE P_liste = {NULL};
size_t i;
for(i = 0; i < 4; i++)
empiler(&P_liste, &ae[i]);
affiche_chemin(P_liste);
return 0;
}
I am writing a program to store multiple typedef "Item" instances in a queue (using this queue implementation) and I am running into a problem getting the data back from the queue.
Here is the relevant code, minus the file open/close lines (the code takes an input file and stores individual values into the instance):
Sample file:
1 2 10 20 30
------------
/* create new item */
Item *newItem = malloc(sizeof(Item));
/* string tokenizer */
...
/* set item variables */
newItem->value1 = strtol(tokens[0], NULL, 10); //should contain 1
newItem->value2 = strtol(tokens[1], NULL, 10); //should contain 2
newItem->value3 = strtol(tokens[2], NULL, 10); //should contain 10
newItem->value4 = strtol(tokens[3], NULL, 10); //should contain 20
newItem->value5 = strtol(tokens[4], NULL, 10); //should contain 30
/* add to item queue */
queue_push_tail(itemQueue, &newItem);
/* add second item with different values, same method as above */
...
/* check queue values */
if(!queue_is_empty(itemQueue)) {
Item *itemHead = queue_peek_head(itemQueue); //this should differ...
printf("Head: %d %d\n", itemHead->value1, itemHead->value5);
Item *itemTail = queue_peek_tail(processQueue); //...from this
printf("Tail: %d %d\n", itemTail->value1, itemTail->value5);
}
How can I then access one of these items to view a variable? I thought I could use something like queue_peek_head(itemQueue)->value1 to see the first variable in the item (in the above example, 1 since that was stored in the first newItem.value1 in the queue), but that doesn't work for some reason.
Like #WhozCraig said in the previous comment, queue_peek_head() is supposed to return 'void *' which you should cast to 'Item *'.
Another issue with your code - 'newItem' is an on-stack variable, you can keep in a queue only as long as you are within the call stack of the function that pushed newItem to the queue. A safer practice would be to allocate newItem before pushing to a queue and free it somewhere else when you don't need it to be queued anymore.
I need to make some operations on a list of files with particular extension (*.bob), all stored in the same directory. The files are image frames, and their name format is frame_XXXX.bob. I don't know the number of frames a priori, and I need to make sure I process them in order (from frame 0 to last one). I read the content of the folder with struct dirent *readdir(DIR *dirp), but since it doesn't guarantee files will be read in alphabetical order (even though it always seems to), I want to put them into a single linked list, and then sort them before processing further.
I save the head of the list before populating it to a pointer filesListStart, then read the entire folder content, adding each entry to the list if it has ".bob" extension. This all works great when I have up to 100 frames, but for some reason breaks down above that - the value of what pointer filesListStart points at doesn't contain the filename of the first entry in the list anymore. The code doesn't use any numerals, so I don't know what would be the significance of going over 100 elements.
I wrote out memory address of filesListStart before I start populating the list, and after, and they are the same, but values they show at magically change. When I set filesListStart it points at object with field fileName equals to "frame_0000.bob" (which is as expected), but after populating the list the name it points at becomes "e_0102.bob".
The list structure is defined as
// List structure
struct FilesList {
char *fileName ;
struct FilesList *next ;
} ;
The code in question is:
DIR *moviesDir ;
moviesDir = opendir("movies") ;
if(moviesDir == NULL)
{
printf("Make Movie failed to open directory containing bob frames\n") ;
return ;
}
struct dirent *dirContent ;
// Get first .bob frame name from the directory
dirContent = readdir(moviesDir) ;
// isBobFile(dirContent) returns 1 if entry has ".bob" extension and 0 otherwise
while( !isBobFile(dirContent) )
{
dirContent = readdir(moviesDir) ;
}
struct FilesList *filesList = (struct FilesList*)
malloc( sizeof(struct FilesList) ) ;
// Initialize the list start at that first found .bob frame
filesList->fileName = dirContent->d_name;
// And save the head of the list
struct FilesList *filesListStart = filesList ;
printf("FilesListStart: %s\n", filesListStart->fileName) ;
printf("Address is: %p\n", filesListStart) ;
// For all other bob frames
while( (dirContent = readdir(moviesDir) ) != NULL )
{
if( isBobFile(dirContent) )
{
struct FilesList *temporaryNode = (struct FilesList*)
malloc( sizeof(struct FilesList) );
temporaryNode->fileName = dirContent->d_name ;
filesList->next = temporaryNode ;
filesList = temporaryNode ;
}
}
// Set the 'next' pointer of the last element in list to NULL
filesList->next = NULL ;
// close stream to directory with .bob frames
closedir(moviesDir) ;
// Check what FilesListStart points at
printf("FilesListStart: %s\n", filesListStart->fileName) ;
printf("Address is: %p\n", filesListStart) ;
// Rest of the code
You should be making a copy of dirContent->d_name rather than using the actual value.
The runtime libraries are free to change the contents of that dirent structure whenever you call readdir and, if all you've stored is it's address, the underlying memory may change. From the POSIX man-pages:
The pointer returned by readdir() points to data which may be overwritten by another call to readdir() on the same directory stream.
In other words, replace the lines:
filesList->fileName = dirContent->d_name;
temporaryNode->fileName = dirContent->d_name ;
with:
filesList->fileName = strdup (dirContent->d_name);
temporaryNode->fileName = strdup (dirContent->d_name);
assuming you have a strdup-like function and, if not, you can get one cheap here.
If it's only changing after 100 calls, it's probably the runtime trying to be a bit more intelligent but even it can't store an infinite number so it probably sets a reasonable limit.
Just remember to free all those char pointers before you free the linked list nodes (somewhere in that "rest of code" section presumably).