add a struct into struct linked list in C - c

I need to write software that gets structure from the user (name, path and time) and then add the structure to the end of a linked list. I wrote two functions that work the problem that it only works in the first run, if the user tries to add another structure to the linked program the program crashes):
Can anyone help me understand what the problem is?
Thank you!
These are the structures I created:
// Frame struct
typedef struct Frame
{
char* name;
int duration;
char* path;
} Frame;
// Link (node) struct
typedef struct FrameNode
{
Frame* frame;
struct FrameNode* next;
} FrameNode;
What are the functions:
FrameNode* addFrame(Frame frame)
{
FrameNode* p = malloc(sizeof frame);
printf("*** Creating a new frame ***\n");
printf("Please insert frame path:\n");
p->frame->path = (char*)malloc(sizeof(char*) * 100);
fgets(p->frame->path, 100, stdin);
p->frame->path[strcspn(p->frame->path, "\n")] = 0;
printf("Please insert frame duration <in miliseconds>:\n");
scanf_s("%d", &(p->frame->duration));
getchar();
printf("Please chooce a name for a new frame:\n");
p->frame->name = (char*)malloc(sizeof(char*) * 100);
fgets(p->frame->name, 100, stdin);
p->frame->name[strcspn(p->frame->name, "\n")] = 0;
while (list != NULL)
{
while (strcmp(list->frame->name, p->frame->name) == 0)
{
printf("The name is already taken, Please enter another name\n");
fgets(p->frame->name, 100, stdin);
}
}
p->next = NULL;
return p;
}
FrameNode* insertAtEnd(FrameNode* list, Frame fr)
{
FrameNode* tmp = addFrame(fr);
if (list != NULL)
{
list = list->next;
}
list = tmp;
return list;
}

The problem is here-
if (list != NULL)
{
list = list->next;
}
list = tmp;
Correct one is
while(list>next != NULL)
{
list = list->next;
}
list->next = tmp;
This will go to next until the last frame and add the new frame. In your code, it works first time because it only executes list=tmp. For other times, we are not going to the end of the list to add tmp. Note if instead of while.
Also, in your code when list becomes NULL, we lose address of last frame, so we need the loop till list>next!=NULL instead of list!=NULL.

Related

Wrong value when inserting into a linked list in c

I am trying to insert words into a hash table and it looks like it works but when I try to print the word inside the node (just to check if its still correct) I get a bogus value. When my code prompts for the word I said 'Hey' and when it prompts for place I said '5'. The string that is printed out(which is supposed to be the word inside the node) is HH9[]A\A]A^A_f. What is happening to the word inside the node and am I inserting the node correctly?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct node
{
char word[20];
struct node *next;
}
node;
int main (void)
{
node* table[10];
char wrd[10];
printf("Word to insert: ");
fgets(wrd, 10, stdin);
int place;
printf("Place to insert word: ");
scanf("%d", &place);
node *n = malloc(sizeof(node));
if(n == NULL)
{
return 1;
}
strcpy(n->word, wrd);
if(table[place] == NULL)
{
n = table[place];
n->next = NULL;
}
else
{
n->next = table[place];
n = table[place];
}
printf("Word inside node: %s \n" , n->word);
}
EDIT
I changed the code and tried to implement it on a larger scale but my while loop gives me a segfault. This is the function I put it in:
FILE* dct = fopen ("/dictionaries/large", "r");
char *wrd = NULL;
while(fscanf(dct, "%s", wrd) != EOF)
{
int place = hash(wrd);
node *n = malloc(sizeof(node));
node *anchor = NULL;
node *end = NULL;
if(n == NULL)
{
return 1;
}
strcpy(n->word, wrd);
n->next = NULL;
if (!end) //Initial state
anchor = end = n;
else //Every following node.
end = end->next = n;
strcpy(n->word, wrd);
n->next = table[place];
table[place] = n;
counter++;
}
return false;
It has to read from the dictionary file and load the word into memory(or a hash table).
A linked list is a linked list because it does not have a fixed size.
The table array is therefor superfluous.
What you need for your linked list to work is to remember the anchor and nothing more.
A small example:
Node *anchor = NULL;
Node *end = NULL;
Node *node = malloc(sizeof(Node));
node->next = NULL;
if (!end) //Initial state
anchor = end = node;
else //Every following node.
end = end->next = node;
At this point, you can still access the node you've just filled. Don't forget to iterate over your list later and free those allocations though.
This code doesn't make any sense:
if(table[place] == NULL)
{
n = table[place]; // since we know table[place] is null, that sets n to null!
n->next = NULL; // We just set n to NULL, we can't access n->next!
}
else
{
n->next = table[place]; // This sets n to a garbage value since table[place] was never assigned a value
n = table[place]; // This leaks the value we malloc'ed. We were supposed to link it to the list!
}

print from users input linked list of struct

I am required to have a list of structs of sentence nodes that point to a struct of word nodes. I am trying to print the user's input.
I have a program that runs properly when I manually give it the input (see test section of the code). It does not, however, work when I use my input1() function.
I've tried debugging it, but I can't seem to find the problem.
I removed all printf lines that I used to debug. I also removed all the irrelevant code.
I am looking to know how to fix it and what is wrong so I can run it with no problems.
What I learned from debugging it is that (only when using input1() and not in the test) the head is overwritten every time and all the nodes as well.
I also tried using a double pointer instead of returning para but that didn't help.
any help will be appreciated,
thanks in advance
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct word
{
char * ch;//poiter to char
}
W;
typedef struct sentence
{
W * currentWord;//pointer to a word
int lineNumber;// holds the line number
int numbersOfWords;//holds the number of words
struct sentence* link;
}
sent;
typedef struct list
{
sent* head;
int count;
}
LISTS;
LISTS* createList()
{
LISTS* list;
list= (LISTS*) malloc (sizeof (LISTS));
if (list)
{
list-> head = NULL;
list-> count = 0;
}
return list;
} // createList
void printList(LISTS* list)
{
sent *temp = list -> head;
//iterate the entire linked list and print the data
while(temp != NULL)
{
printf("%s\n", temp->currentWord->ch);
temp = temp->link;
}
// printf("NULL\n");
}
void insertSentList (LISTS* list, W* itemPtr)
{
sent* newPtr; //new node
if (!(newPtr = (sent * ) malloc(sizeof(sent)))){
printf(" Memory can not be allocated.");
return;
}
newPtr->currentWord = itemPtr;
newPtr->link = NULL;
if(list->head == NULL)
{
list->head = newPtr;
}else{
sent* current = list->head;
while(current->link != NULL){
current = current->link;
}
current -> link = newPtr;
}
(list->count)++;
return;
} // insertList
LISTS * input1(LISTS *para)
{
char * line;
line = (char * ) malloc(1000 * sizeof(char));
line[0] = '\0';
while (line[0] != '\n')
{
W word;
word.ch = (char * ) malloc(100);
printf(" Please input a line : ");
fgets(line, 1000, stdin);
if(line[0] != '\n'){
strcpy(word.ch, line);
insertSentList(para,&word);
}
}
free(line);
return para;
}
int main()
{
///////////////////test////////////////
LISTS* list = createList();
W word;
word.ch= "word0 ";
W word1;
word1.ch= "word1 ";
W word2;
word2.ch= "word2";
insertSentList(list,&word);
insertSentList(list,&word1);
insertSentList(list,&word2);
insertSentList(list,&word);
insertSentList(list,&word1);
insertSentList(list,&word2);
printList(list);
///////////////////test////////////////
LISTS *para = createList();
para= input1(para);
printList(para);
return 0;
}
Main problem with the posted code is that "ownership" of the sent and W objects in a list is not well defined. For example word.ch= "word0 "; in main sets the ch pointer pointing to a string literal (which it does not own), but word.ch = malloc(100); in input1 points it to dynamically allocated memory (which it should own, and remember to free later). Because of this, memory allocations cannot be tracked reliably and, even in the cases where things appear to "work", there are multiple memory leaks. It also breaks when the inserted objects are local variables that do not live for the entire lifetime of the list object.
The simplest (if not necessarily the best or most efficient) solution would be to dynamically allocate all objects that go into the list, make the list own them all, and add a function to cleanup once done. To that end insertSentList could be modified as follows.
void insertSentList (LISTS* list, W* itemPtr)
{
sent* newPtr; //new node
if (!(newPtr = malloc(sizeof(sent)))){
printf(" Memory can not be allocated.\n");
return;
}
W *newItem = malloc(sizeof(W)); // <-- make a deep copy of the `itemPtr` argument
newItem->ch = strdup(itemPtr->ch); // including a copy of the string itself
newPtr->currentWord = newItem; // <-- save the copy in the list, not the argument
newPtr->link = NULL;
if(list->head == NULL)
{
list->head = newPtr;
}else{
sent* current = list->head;
while(current->link != NULL){
current = current->link;
}
current->link = newPtr;
}
list->count++;
} // insertList
For proper cleanup and to avoid memory leaks, the following freeList should be called for each list pointer returned by createList and filled by insertSentList.
void freeList(LISTS *list)
{
sent *temp = list->head;
while(temp != NULL)
{
sent *next = temp->link;
free(temp->currentWord->ch);
free(temp->currentWord);
free(temp);
temp = next;
}
free(list);
}

Address of nodes keep overwriting each other when being added to linked list

I'm trying to use tasklist and pipe the output to my code and parse each line to then create nodes of every process. I will later be filtering through them but that is not in the code yet. I'm having problems with the LIST. I have implemented 3 structs for this program: LIST (head for first node, rear for last node and count for number of nodes in list), NODE (pointer to PROCESS_INFO and pointer to next NODE), PROCESS_INFO (4 char pointers for process name, PID, memory usage and cputime). I've used printf to track my code and everything seems to work properly until I get to adding them to the linked list. The address of each nodes are different but it always seems to overwrite the last one in the list instead of adding the new address of the node to the next* of the previous node.
I'm mostly positive my algorithm is correct, it's the same one I've used multiple times just with different data. My malloc functions have dynamic checks incase they fault and I've checked and played with my pointers incase I was missing a dereference of some sort but I get errors if I change anything so I don't think those are the problem funny enough.
The only thing I can think of that would be the problem is the fact that all this doing resides in a loop in a function (I read somewhere that pointers on a stack can't remember their address?). What would I have to change though to fix this? I've moved everything to main but nothing changed.
Struct Definitions:
typedef struct processInfo{
char *pName;
char *processId;
char *memUsage;
char *cpuTime;
}PROCESS_INFO;
typedef struct node{
PROCESS_INFO* data;
struct node* next;
}NODE;
typedef struct li{
int num;
NODE* head;
NODE* rear;
}LIST;
Main function:
int main()
{
LIST* list;
list = buildList();
printList(list);
}
List functions:
//function that creates a new list and returns it as null
LIST* createList()
{
LIST* newListPtr;
newListPtr = (LIST*)malloc(sizeof(LIST));
if (newListPtr)
{
newListPtr->num = 0;
newListPtr->head = NULL;
newListPtr->rear = NULL;
}
return newListPtr;
}
//function that creates the struct for the information of the process
PROCESS_INFO* createPinfo(char* name, char* pid, char* kb, char* cTime)
{
PROCESS_INFO* pInfoPtr;
pInfoPtr = (PROCESS_INFO*)malloc(sizeof(PROCESS_INFO));
if (pInfoPtr)
{
pInfoPtr->pName = name;
pInfoPtr->processId = pid;
pInfoPtr->memUsage = kb;
pInfoPtr->cpuTime = cTime;
}
return pInfoPtr;
}
//function to create new node and set its data
NODE* createNode(PROCESS_INFO* dataPtr)
{
NODE* nodePtr;
nodePtr = (NODE*)malloc(sizeof(NODE));
if (nodePtr)
{
nodePtr->data = dataPtr;
nodePtr->next = NULL;
}
return nodePtr;
}
//Get process information node via the path
PROCESS_INFO* parseInfoFromPath (char str[])
{
char *pName;
char *processId;
char *memUsage;
char *time;
char *parse;
parse = strtok(str, " ");
pName = parse;
parse = strtok(NULL, " ");
processId = parse;
parse = strtok(NULL, " "); //Console
parse = strtok(NULL, " "); //session
parse = strtok(NULL, " "); //memory
memUsage = parse;
parse = strtok(NULL, " ");
parse = strtok(NULL, " ");
parse = strtok(NULL, " ");
parse = strtok(NULL, " "); //CPUTIME
time = parse;
PROCESS_INFO* pInfoPtr;
pInfoPtr = createPinfo(pName, processId, memUsage, time);
return pInfoPtr;
}
BuildList() function where I seem to be getting the semantic error:
LIST* buildList()
{
FILE *fp;
char path[PATH_MAX];
fp = popen("tasklist /v /fi \"STATUS eq running\" /nh ", "r");
if (fp == NULL)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
LIST* list_;
PROCESS_INFO* p;
NODE* n;
list_ = createList();
while (fgets(path, PATH_MAX, fp) != NULL)
{
if (path != NULL)
{
//create the process info struct
p = parseInfoFromPath(path);
//create the node
n = createNode(p);
//add node to list
//if empty list set as head
if (list_->head == NULL){
list_->head = n;
}
//otherwise set last->next to point to the new node
else {
list_->rear->next = n;
}
//rear points to last node
list_->rear = n;
(list_->num)++;
}
}
//They always print out the same data!!!!
printf("\nIn Loop: Head Node name: %s", list_->head->data->pName);
printf("\t\tIn Loop: Read Node name: %s", list_->rear->data->pName);
return list_;
}
You are not copying the strings for each input field you find. Instead you are holding pointers into your path buffer, which gets overwritten every time you do fgets. Try using strdup in createPinfo:
PROCESS_INFO* createPinfo(char* name, char* pid, char* kb, char* cTime)
{
PROCESS_INFO* pInfoPtr;
pInfoPtr = (PROCESS_INFO*)malloc(sizeof(PROCESS_INFO));
if (pInfoPtr)
{
pInfoPtr->pName = strdup(name);
pInfoPtr->processId = strdup(pid);
pInfoPtr->memUsage = strdup(kb);
pInfoPtr->cpuTime = strdup(cTime);
}
return pInfoPtr;
}
Also, since strdup allocates heap memory, don't forget to add a function to free the memory and call it every time you remove something from the list. Eg:
void destroyPinfo(PROCESS_INFO* pInfoPtr)
{
if (pInfoPtr)
{
free(pInfoPtr->pName);
pInfoPtr->pName = NULL;
free(pInfoPtr->processId);
pInfoPtr->processId = NULL;
free(pInfoPtr->memUsage);
pInfoPtr->memUsage = NULL;
free(pInfoPtr->cpuTime);
pInfoPtr->cpuTime = NULL;
}
}
You will probably want to NULL check the results of strdup like you do malloc (I'm too lazy to add this in to the answer though, as long as you get the basic idea).

strcmp in Linked List insertion crashing program

As part of an assignment, I'm supposed to implement a singly linked list in c.
I've done this plenty of times before in a few different languages, but after a few hours of pain I've gotten stuck on a problem using strcmp.
This is the structure I'm using:
typedef struct node {
char *name;
float score;
struct node *next;
} node;
The problem is specific to the insertion function, which is supposed to be similar to an insertion sort, since I need to have the nodes in the list sorted in alphabetical order.(my professor specified that the insertion function does the sorting, despite not calling it an insertion sort).
void insert(node **start, char *name, float score) { // to insert a record into the linked list sorted by name in dictionary order.
//create new node
node *n_node = new_node(name, score);
node *current;
current = *start;
if (current != NULL) { //-----------if list is not empty
node *prev = NULL;
if (current->next != NULL) { //--if list has more than 1 element
while (current != NULL && strcmp(name, current->name) > 0) { //cycle through list to sorted insertion point
// ^^^^^^^Problem Here^^^^^^^^
//while name is greater than current name, means lower on alphabet (z>a)
prev = current;
current = current->next;
}
if (current != NULL) { //-----not at end of list
//once current is not < new node, connect between prev and current
prev->next = n_node;
n_node->next = current;
} else { // ------------------at end of list
prev->next = n_node;
}
} else { //-----------------------list has only one element
current->next = n_node;
}
} else { //--------------------------List is empty - assign new node as first element
*start = n_node;
}
}
The problem is that my program crashes and burns without any errors or warnings (I'm using eclipse with CDT).
The program works fine when
while (current != NULL && strcmp(name, current->name) > 0)
is modified to
while (current != NULL /*&& strcmp(name, current->name) > 0*/).
It seems obvious to me that name or current->name are causing a problem with the operation of strcmp, but I can't seem to get around that.
Edit:
I'll add that this function is called from another function, which retrieves and tokenises strings from a file containing pairs of names and marks, but my testing hasn't suggested that it passes a bad string or characters via the call.
For some extra detail, here's my new_node function:
node *new_node(char *name, float score) {
node *new = (struct node*) malloc(sizeof(struct node));
new->name = malloc(strlen(name) + 1);
strcpy(new->name, name);
new->score = score;
new->next = NULL;
return new;
}
(I realise using new as the name of the node isn't smart, and I will change that)
and the function that calls insert:
int data_import(node **startp, char *infilename) { // to import data from the file and insert .
int max_line = 100;
char line[max_line];
char delimiters[] = ",";
char name[500] = "";
char *namep;
namep = &name[0];
float score = 0.0f;
int i = 0;
FILE *fi;
char *token;
// open file to read
fi = fopen(infilename, "r");
if (fi == NULL) { // Cannot open the file.
perror("error");
return 0;
}
// read each line, increase counter, retrieve data
while (fgets(line, max_line, fi) != NULL) {
//fputs(line, stdout); //console output confirmation
token = strtok(line, delimiters);
strcpy(namep, token);
token = strtok(NULL, delimiters); //increment token to mark variable
score = atof(token);
insert(startp, namep, score);
i++;
}
//close file
fclose(fi);
return i;
}
what happens if you have element called apple as your first element and you try to add element called about ?
you will be thrown out of below while loop straight away and your prev will be unassigned :
while (current != NULL && strcmp(name, current->name) > 0) { //cycle through list to sorted insertion point
// ^^^^^^^Problem Here^^^^^^^^
//while name is greater than current name, means lower on alphabet (z>a)
prev = current;
current = current->next;
}
this particular part looks suspicious to me :
after that you will enter in below routine :
if (current != NULL) { //-----not at end of list
//once current is not < new node, connect between prev and current
prev->next = n_node;
n_node->next = current;
}
as your *prev is unassigned and you try to access it (prev->next = n_node;).you will get crash here.

Circular Doubly Linked List, Print Function

I need to create a circular doubly linked list with a sentinel node which is supposed to read data from a file and insert it in the list, than perform some operations with it. For now I'm stuck on a simple print function which won't print from a list for some reason. The data in the file is in the form of strings,
example: "Popular Sorting Algorithms,
Bubble Sort, Merge Sort, "empty line", etc
Here is my code so far:
Header file contains:
typedef struct NODE {
struct NODE *prev;
char *value;
struct NODE *next;
} NODE;
typedef struct LIST {
int count;
struct NODE *next;
struct NODE *prev;
} LIST;
int InsertEnd(NODE *head, char * value, int *lineCount);
void printLines(int *lineCount);
void Traverse(NODE *head);
Main contains:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "header.h"
int main()
{
int lineCount = 0;
NODE *head;
head = (NODE *)malloc(sizeof(NODE)); /* creates head node dynamically */
head->next = NULL; /* points to first element */
head->prev = NULL; /* points to last element */
head->value = "HEAD"; /* not needed, but it was pretty useful when debugging */
//*********BEGIN OF OPEN FILE FUNCTION
FILE* fp;
char *fname = NULL;
fname = (char *)malloc(200); <<<<<===== I would prefer to set the size dynamically adjusting but I dont know how
printf("Reading file input.txt\n");
//Checks if the file us unable to be opened, then it shows the error message
if ( !(fp = fopen("input.txt", "r")))
{
printf("\nError, Unable to open the file for reading \n");
exit(100);
}
//*********BEGIN OF READ FROM FILE FUNCTION
while (!feof(fp))
{
fgets(fname, 150, fp); //reads the file and stores in buffer
fname[strlen(fname) - 1] = '\0'; // reduces empty strings for input
if (fname != '\0')
{
InsertEnd(head, fname, &lineCount);
//printf("%s\n", head->next->value); <<<<==== If uncomment this print function would work properly but only in this context
}
else
{
printf("Error'\n"); // For debugging
}
}
Traverse(head); // Print Function Should Be Working in Here
printf("Debugging print\n");
printLines(&lineCount); // Shows Line Count
return 0;
}
// Function inserts a new node at the end of the LIST
int InsertEnd(NODE *head, char * value, int* lineCount)
{
int lineCounter = *lineCount;
/* create new node */
NODE *newnode;
newnode = (struct NODE *)malloc(sizeof( struct NODE));
newnode->value = value;
/* placing new node in LIST */
if (head->next == NULL) /* LIST was empty */
{
newnode->next = head;
newnode->prev = head;
head->next = newnode;
head->prev = newnode;
lineCounter++; // Increment line counter
}
else /* LIST wasn't empty */
{
newnode->next = head;
newnode->prev = head->prev;
head->prev->next = newnode; /* adjust node that was previously last */
head->prev = newnode; /* adjust head node */
lineCounter++; // Increment line counter
}
*lineCount = lineCounter;
return lineCount;
}
// This function prints how many lines there are in the LIST, but I need to get rid of the empty spaces
void printLines(int *lineCount)
{
printf("Line counter is %d", *lineCount); // Shows the number of lines, but doesn't skip empty ones.
}
void Traverse(NODE *head)
{
NODE *current = head;
printf("Forward:");
while (current!= head->prev)
{
printf("%s \n", current->value);
current = current->next;
}
printf("\n");
}
Therefore, I have several problems so far:
1) I need to get rid of empty strings in my list most likely. What would be a better approach, to get rid of them while reading or just not displaying when printing? How would I do this exactly?
2) How can I fix my print(traverse) function and whats wrong there?
3) Additionally all of this should be going on through the menu manager which would prompt for a command ( I got this right I think). But there are some functions that I don't know how to implement. For example when used hits "I" it should call Insert functions and prompt the user to enter two more values and , and later insert at the appropriate . How would I do that? Example "I 1 8"
4) Similarly to the previous one, there should be List function which should print lines between specific values. User input format should be "L to " list inclusively. Example "L 2 5"
5) Similarly to previous there should be a delete function with the format "D " inclusively. Example "D 3 7"
6) And the very last is the Save function in the format "S " Example "S output.txt"
Thank You for the help!
I see at least these issues in your code,
In main()
if (fname != '\0')
this should be
if (fname[0] != '\0')
In InsertEnd()
newnode->value = value;
should be
newnode->value = strdup(value);
In you code there should be some correctness which is very help full first as per your request you need to allocate buffer dynamically but not know file length so it can be achived by this one
int sz;
printf("Reading file input.txt\n");
//Checks if the file us unable to be opened, then it shows the error message
if ( !(fp = fopen("sample.txt", "r")))
{
printf("\nError, Unable to open the file for reading \n");
exit(100);
}
fseek(fp, 0L, SEEK_END);
sz = ftell(fp);
printf("size of file %d\n",sz);
fname = (char *)malloc(sz);
rewind(fp);
Now for reading content from file you checked fname to \0 which is not correct i corrected your while..loop.
while (!feof(fp))
{
if(fgets(fname,256, fp) != 0)
{
fname[strlen(fname) - 1] = '\0'; // reduces empty strings for input
InsertEnd(head, fname, &lineCount);
}
else
{
printf("Error'\n"); // For debugging
}
}

Resources