I'm trying to set up a linked list but just get the same element in every location -
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 45
typedef struct node
{
char* word;
struct node* next;
}
node;
int main(void)
{
node* head = NULL; //start of list
// open input file
FILE* inptr = fopen("smalllocal", "r");
if (inptr == NULL)
{
printf("Could not open %s.\n", "smalllocal");
return 2;
}
printf("Opened file\n");
//Get a word from dictionary
char str1[LENGTH +1];
while (fscanf(inptr, "%s", str1) != EOF)
{
node* new_node = malloc(sizeof(node)); //malloc space for a new node
if (new_node == NULL)
{
return 3;
}
new_node->word = str1;
// is it the first insertion at this index?
if (head == NULL)
{
new_node->next = head;
head = new_node;
}
else
// collision so insert at front of list
{
new_node->next = head;
head = new_node;
}
}
fclose(inptr);
printf("Closed file\n");
node* pointer = head;
while (pointer != NULL)
{
printf("%s\n", pointer->word);
pointer = pointer->next;
}
return 0;
}
The file 'smalllocal' contains about 15 different words but the print routine at the end just prints out the last element in the file for every location. Can anybody help please??
This isn't the correct way to copy strings in C (you can't assign them using =).
Instead, you need to allocate a character array long enough to hold the string, and use strcpy().
new_node->word = malloc(strlen(str1) + 1);
strcpy(new_node->word, str1);
Don't forget to free() them later to avoid a memory leak.
The reason your program prints the same value over and over is that every node's word pointer points to the str1 array, but that array is reused for each word. So at any given time, no matter how many nodes you have, you only really have one string: inside str1, and naturally its value will be the last string read in your loop.
You are allocating memory for your strcut, but you also need to allocate memory for your string. Change your
new_node->word = str1;
for
new_node->word = malloc(strlen(str1)+1);
strcpy(new_node->word, str1);
so that you allocate the necessary memory to hold the string and then copy it to this allocated memory. Otherwise, all of your nodes word pointer will be pointing to the same string, str1.
Your new_node->word is a pointer, it doesn't contain any characters. All nodes points to the same block of memory. When you insert a new node, you changed the content of str1 so it just prints out the last string.
Use new_node->word = strdup(str1); instead. You need to include string.h header.
You cannot simply do
new_node->word = str1;
You need to allocate memory first and copy the string into memory ...
new_node -> word = (char *) malloc( sizeof(char)*(LENGTH +1) );
strcpy(new_node -> word, str1);
That should do it. Otherwise, all the pointers in the linked list are pointing to the same memory location.
Related
So I have a file called file.txt and i want to create a linked list from the information it contains, where each line of the file is a new node. So far I have this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct sAirport{
char name;
int number;
struct sAirport *next;
}tAirport;
tAirport *createNode(tAirport *newNode, char str[1000]);
void createLinkedList(tAirport **head, tAiport *newNode);
int main()
{
FILE *fa = fopen("test.txt", r);
char str[1000] = {0};
tAirport *head = NULL;
tAirport *newNode = NULL;
while(fgets(str, sizeof(str), fa) != NULL)
{
newNode = createNode(newNode, str);
createLinkedList(&head, newNode);
free(newNode);
newNode = NULL;
}
return 0;
}
tAirport *createNode(tAirport *newNode, char str[1000])
{
char *aux = NULL;
newNode = malloc(sizeof(tAirport));
if(newNode == NULL)
exit(EXIT_FAILURE);
aux = strtok(str, " ");
strcpy(&newNode->name, aux);
aux = strtok(NULL, " ");
sscanf(aux, "%d", &newNode->number);
newNode->next = NULL;
return newNode;
}
void createLinkedList(tAirport **head, tAirport newNode)
{
tAirport *temp = NULL;
if(*head == NULL)
{
*head = newNode;
return;
}
temp = *head;
while(temp->next != NULL)
temp = temp->next;
temp->next = newNode;
}
I'm getting weird results and Valgrind says I have lost bytes but I don't know what to do.
Edited so that it can run.
For example the file I'm testing with is:
John 33
Mary 42
Peter 12
What should I do?
Aside from all those warning you will get from compiling this. I just want to tell you that you are misunderstanding how malloc(),free(), and pointer work.
First of all, pointer is just an unsigned long, a natural number just like any other number. The difference is that the pointer store the address of the real memory ( in this case is newNode).
In your program, you malloc() to get your memory, asisgn the memory address to newNode, then you tell your list to hold newNode, finally you free it. So you just free the memory you wish to keep, your list now only hold a bunch of address to freed memory.
Solution for this is, get rid of free() while populating your list, and free them later
The sAirport structure is define the name to be one character. However, from the code, looks like the createNode will allow long name (up to 999 characters). When the createNode create the new entry, the strcpy will overwrite data beyond the allocated space, and will likely cause segmentation fault, or "funny" data.
Consider extending name to the proper size, or using dynamic allocation (malloc) for name.
The program specifications are pretty simple, just read in an input file of words and create a linked list where each node contains an entire string.
Here's my node struct:
typedef struct wordNode{
char *word;
token_type type;
struct wordNode *next;
} wordNode;
The token type will come into play later after I get the LL basics working.
The general process of main is to open the input file, set up head with the first word, then iterate through the rest of the input file using a second node pointer, "current". Afterwards, print the list from the head pointer with a print list function.
void printList(wordNode *head)
{
while(head != NULL)
{
printf("%s ", head->word);
head = head->next;
}
}
int main()
{
//Open input file
FILE *input = fopen("input.txt", "r");
char nextWord[12] = "";
//Scan in first word for head node
fscanf(input, "%s", nextWord);
//create head, fill it in with the first word, and create current
wordNode *head = malloc(sizeof(wordNode));
head->next = malloc(sizeof(wordNode));
head->word = nextWord;
printf("%s ", head->word);
wordNode *current = head->next;
//Begin Iteration
while(fscanf(input, "%s", nextWord) != EOF)
{
current = (wordNode*)malloc(sizeof(wordNode));
current->word = nextWord;
current->next = NULL;
printf("%s ", current->word);
current = current->next;
}
printList(head);
}
Together, those printfs within main will give me the output I want, so the strings seem to be being saved properly during the iteration, But the output given by the printList function is the last word in the list repeated a couple times followed by garbage values.
I'm thinking head is tied to current in some way and doesn't stay put at the beginning of the list through the iteration, but I'm not sure how or why its moving.
Also, should I use strcpy for saving the strings to the nodes? I tried earlier but it was leading to crashes when I tried.
nextWord should either be a much larger array (e.g. nextWord[200]) or you should limit the number of characters stored by fscanf, e.g.
fscanf(input, "%11s", nextWord);
Or use a larger array and limit the number of characters.
You need to make a copy of each string after reading it into the nextWord array. The code currently just assigns the address of the nextWord array to each word pointer. So every node in the linked list points to the same string, which will be the last string read from the file. To copy a string, you need to allocate memory and then strcpy. The strdup function will do that for you, but strdup is not supported on all systems.
When the code creates the head it allocates memory for two structures. Instead, it should allocate memory for one structure and set head->next to NULL.
The variable current is a mess, e.g. you set current->next = NULL and two lines later set current = current->next. To make the code work, you need two variables, I would call them tail and current. tail should point to the last node in the linked list. So initially, tail points to head. When you create a new node, the code should look like this
current = (wordNode*)malloc(sizeof(wordNode));
current->word = strdup( nextWord );
current->next = NULL;
tail->next = current;
tail = current;
Also, don't check fscanf for EOF. Instead, check that fscanf returns the expected number of conversions. The reason is that fscanf could get stuck in an infinite loop if a conversion fails before the end-of-file is reached. So the while loop should be
while(fscanf(input, "%11s", nextWord) == 1)
You need to allocate memory for the char *s:
int main()
{
//Open input file
FILE *input = fopen("input.txt", "r");
char nextWord[12] = "";
//Scan in first word for head node
fscanf(input, "%s", nextWord);
//create head, fill it in with the first word, and create current
wordNode *head = malloc(sizeof(wordNode));
head->next = malloc(sizeof(wordNode));
head->word = (char *)calloc(strlen(nextWord) + 1);
strcpy(head->word, nextWord);
printf("%s ", head->word);
wordNode *current = head->next;
//Begin Iteration
while(fscanf(input, "%s", nextWord) != EOF)
{
current = (wordNode*)malloc(sizeof(wordNode));
current->word = (char *)calloc(strlen(nextWord) + 1);
strcpy(current->word, nextWord);
current->next = NULL;
printf("%s ", current->word);
current = current->next;
}
printList(head);
}
Because you are not saving the input. Only their addresses saving in the linked list.
When you assinged head->word = nextWord the address of the nextWord which is a local aray is assigning.
You need to enough space in the struct like char Word[SIZE] or use dynamic allocation char *Word = malloc( SIZE ) and you should use strcpy to copy the input.
head->word = malloc(SIZE);
strcpy(heap->word, nextWord);
Also there is a little mistake
wordNode *head = malloc(sizeof(wordNode));
head->next = malloc(sizeof(wordNode)); /* (1) Allocated */
head->word = nextWord;
printf("%s ", head->word);
wordNode *current = head->next; /* current points allocated memory (1) */
//Begin Iteration
while(fscanf(input, "%s", nextWord) != EOF)
{
current = (wordNode*)malloc(sizeof(wordNode)); /*re-allocation
and (1) is allocated but not used memory you can not access it anymore*/
current->word = nextWord;
current->next = NULL;
printf("%s ", current->word);
current = current->next;
}
printList(head);
}
Here, I am trying to read the contents of a file line by line and create a struct for each line. The problem is when I print the list of words, every single one of them is the last word of the file (which is } in this sample). I believe since line changes frequently and I pass a pointer to a char, value of every struct changes as well. I've been trying to fix this problem for nearly a day without any luck. What's a good way to read every word into a struct and link each struct to the linked list?
Note that there are some helper methods used below. I've tested them multiple times and they are working.
Token struct
typedef struct token
{
char* value;
struct token* next;
}TOKEN;
File content
target1:
dependency1
{
command1,
command2
}
Main
TOKEN *head = NULL;
// represents each formatted line from the script file
char* line = malloc(161*sizeof(char));
FILE* fileRead = openFile("RawRules.txt", "r");
while((line = readLine(line, fileRead)) != NULL)
{
head = add(head, line);
}
displaylist(head);
freeNodes(head);
fclose(fileRead);
Add function Modified from http://cprogramminglanguage.net/singly-linked-list-c-source-code.aspx
TOKEN* add(TOKEN *head, char* value){
TOKEN *tmp;
if(head == NULL){
head=(TOKEN *)malloc(sizeof(TOKEN));
if(head == NULL){
printf("Error! memory is not available\n");
exit(0);
}
head-> value = value;
head-> next = head;
}else{
tmp = head;
while (tmp-> next != head)
tmp = tmp-> next;
tmp-> next = (TOKEN *)malloc(sizeof(TOKEN));
if(tmp -> next == NULL)
{
printf("Error! memory is not available\n");
exit(0);
}
tmp = tmp-> next;
tmp-> value = value;
tmp-> next = head;
}
return head;
}
readline function
// reads a line of a file into buffer
char* readLine(char* buffer, FILE* file) {
buffer = fgets(buffer, 161, file);
return buffer;
}
This did not fix the problem either
while(true)
{
char* ll = malloc(161*sizeof(char));
ll = readLine(ll, fileRead);
f(ll != NULL)
head = add(head, ll);
else
break;
}
Sorry, I progammed in C like billion years ago, so call me a noob!
In the add() function, you're simply assigning a char *, rather than allocating any new memory (and then copying) for each string. So each TOKEN ends up pointing at the original buffer. As you're using a single buffer at the top-level, you're overwriting it over and over again.
In short: You need a separate buffer for each line. One way (not necessarily the best way) is to do the following inside add():
int len = strlen(value);
...
tmp->value = malloc(len+1); /* +1 for null terminator */
strncpy(tmp->value, value, len+1);
Remember that at some point, you'll need to free() all of these extra buffers.
I'm trying to make a program that read a file line by line and then put the readed line into a a linked list, my problem is to add the string to list. Look at the code, in the else test you can see my problem.
#include<stdlib.h>
#include<stdio.h>
struct list_el {
char *ord;
struct list_el * next;
};
typedef struct list_el item;
int main(int argc, char *argv[]) {
int c;
item *curr, *head;
head = NULL;
FILE *fileHandle = fopen("tresmaa.txt", "r");
while((c = fgetc(fileHandle)) != '\n' || c != EOF)
if(c == EOF) {
printf("\n");
break;
} else {
curr = (item*)malloc(sizeof(item));
curr->ord = "I cant point curr -< ord = c, how can i point the readed sentences to the value Ord?";
curr->next = head;
head = curr;
putchar(c);
}
curr = head;
while(curr) {
printf("%s\n", curr->ord);
curr = curr->next ;
}
}
curr->ord = "some string" is wrong
instead you need to allocate a buffer and place the string in it
e.g.
curr->ord = malloc( strlen(yourstring) + 1 );
strcpy(curr->ord, yourstring);
because
curr = (item*)malloc(sizeof(item));
only allocates the struct including the 'ord' pointer, but not what it points to.
another thing that looks a bit suspicious is
curr->next = head;
head = curr;
looks more like the name should have been 'prev' and not 'next' the way you do it (LIFO)
otherwise if you want a "normal" FIFO linked list just have a head ptr and an end ptr, then use the end ptr to append elements while keeping the head pointing to the first list element.
I see your problem in the else. :)
Your malloc of the struct is not sufficient. This malloc only creates the memory of the struct memory (two pointers) not the memory inside. You'll have to malloc your char memory (ord) with the proper size of the string as well. Use strlen and add one for null to determine size of this string.
curr->ord = "some string"
is right!
I'm trying to create a singly linked list from an input text file for an assignment. I'm trying to do it a little bit at a time so I know my code is not complete. I tried creating the head pointer and just printing out its value and I can't even get that to work, but I'm not sure why. I included the struct, my create list, and print list functions. I didn't include the open file since that part works.
typedef struct List
{
struct List *next; /* pointer to the next list node */
char *str; /* pointer to the string represented */
int count; /* # of occurrences of this string */
} LIST;
LIST *CreateList(FILE *fp)
{
char input[LINE_LEN];
LIST *root; /* contains root of list */
size_t strSize;
LIST *newList; /* used to allocate new list members */
while (fscanf(fp, BUFFMT"s", input) != EOF) {
strSize = strlen(input) + 1;
/* create root node if no current root node */
if (root == NULL) {
if ((newList = (LIST *)malloc(sizeof(LIST))) == NULL) {
printf("Out of memory...");
exit(EXIT_FAILURE);
}
if ((char *)malloc(sizeof(strSize)) == NULL) {
printf("Not enough memory for %s", input);
exit(EXIT_FAILURE);
}
memcpy(newList->str, input, strSize); /*copy string */
newList->count = START_COUNT;
newList->next = NULL;
root = newList;
}
}
return root;
}
/* Prints sinly linked list and returns head pointer */
LIST *PrintList(const LIST *head)
{
int count;
for (count = 1; head != NULL; head = head->next, head++) {
printf("%s %d", head->str, head->count);
}
return head; /* does this actually return the start of head ptr, b/c I want to
return the start of the head ptr. */
}
root has an undefined value, so it won't initialize. The second line of CreateList should be
LIST *root = NULL;
Also, further down there is allocation apparently for the details of the item, but a) the code fails to capture the allocation and save it anywhere, and b) the size of the allocation should be strSize, not the length of the variable itself. There are several ways to fix it, but the most straightforward would be:
newList->str = (char *)malloc(strSize);
if (newList->str == NULL)
The second malloc allocates memory but its return value is not assigned to anything, so that allocated memory is lost.
newList is allocated but not initialized, so using a memcpy to copy memory to newList->str will fail since newList->str points to nothing. Probably you wanted the result of the second malloc to be assigned to newList->str, but you forgot it.
You shouldn't be incrementing head after head = head->next in the for loop. PrintList will return NULL every time since the loop wont stop until head is NULL. Why do you need to return the head of the list you just passed to the function anyway?
Edit:
LIST *current = head;
while (current != NULL) {
printf("%s %d", current->str, current->count);
current = current->next;
}