I am having problem storing all the values into the Generic LinkedList, my linkedlist works totally works on a normal user Keyboard input but when I try to store values(strings) from a file, there is something weird happening, it only store the last value of the file.
I have checked my addToList() function but theres nothing wrong with it.
P.s But I am feeling its either I am printing wrong or my reading from the file into the linkedlist is wrong.
Thank you.
#include<stdio.h>
#include <stdlib.h>
#include<string.h>
#include "LinkedListItems.h"
#define MAX 10000
int main()
{
printf("Testing MissileFIle.txt");
void* secondStr;
//Had to malloc the thing
secondStr = (void*)malloc(1*sizeof(char));
FILE* missileFile;
missileFile = fopen("missiles.txt", "r");
if(missileFile == NULL)
{
printf("The file is empty");
}
number_list_t* missileList = calloc(1, sizeof(number_list_t));
void* input;
//Have to allocate the input
input = malloc(1*sizeof(void*));
//this is to read the data into the second Str
while(fgets(secondStr,MAX,missileFile) != NULL)
{
//Let just print out first just to test my memory
printf("%s\n",secondStr);
//Right now its only reading one string so far which is really weird AFFFFF
addTolist(missileList,secondStr);
}
//Gotta declare another list just to print out the list
number_node_t* current = missileList->head;
while(current != NULL)
{
//There is something wrong with this line
printf("%s\n",current-> number);
current = current-> next;
}
fclose(missileFile);
}
OUTPUT:
Testing MissileFile.txt
splash
single
V-line
h-line
Single
Single
Single
Single
Single
Single
typedef struct NumberNode
{
//It can store any data type
void* number;
struct NumberNode* next;
}number_node_t;
//List of Nodes
typedef struct NumberList
{
number_node_t* head;
int count; //This is not nesssary but it can be useful for counting how many variables
}number_list_t;
void addTolist(number_list_t* list, void* newNumber)
{
//tem[ = newNode]
number_node_t* newNode = calloc(1,sizeof(number_node_t));
newNode->number = newNumber;
newNode->next = list->head;
list->head = newNode;
}
INPUT DATA:
single
splash
single
V-Line
h-line
Single
The way you have implemented this, it cannot work.
The main problem, among many, is related to the void* pointers which cannot be dereferenced.
The size of elements should be given, either on creating the list in which case all elements are of the same type, or separately for each individual element. You can check out this question for an example of something that could work.
As far as the buffer thing is concerned, addToList should allocate new memory for each newNumber. What you are currently doing results in all data of the list pointing to a specific space in memory (the one allocated to secondStr). Each time you change the content of that memory space, all elements in the list are affected. This is why you print the same value for all elements and more specifically the last value in your file.
The way you allocate memory is also not really ok, same goes for the way you open your file, there is memory leaking etc. I am not going into details.
At least this issue:
Copy the string
OP's goal includes the need to copy the string from the read buffer to the list, not just copy the buffer pointer.
// void addTolist(number_list_t* list, void* newNumber) {
void addStringTolist(number_list_t* list, const char *s) {
// number_node_t* newNode = calloc(1,sizeof(number_node_t));
number_node_t* newNode = calloc(1, sizeof *newNode); // todo: add error check
size_t sz = strlen(s) + 1;
newNode->number = malloc(sz); // todo: add error check
strpy(newNode->number, s);
newNode->next = list->head;
list->head = newNode;
}
Note: When freeing the list, newNode->number also needs to be free'd.
regarding:
while(fgets(secondStr,MAX,missileFile) != NULL)
MAX is defined as 10000 but secondStr is defined as pointer to one byte. so when this is executed, a buffer overflow occurs.
This is undefined behavior and probably the root of the problem with reading from a file
Related
I have a code that sorts a list, I can get it to sort when the list is hardcoded. I am now attempting to implement getting the list from an input file and running it the same way through the code then printing it to an output file. I am trying to get a scanned list from an input file to go through what I have (that is working) for sorting and for the result to be printed to an output file.
You have assigned *tmp to head. But I can see that head had always been NULL. So the loop is never entered, and nothing is being inserted to the list.
So what we'd need to do it first initialize head to a node instance
typdef struct node
{
char* data;
struct node *prev;
struct node *next;
}node;
head = malloc(sizeof(node));
then we assign it data.
head->attribute = value;
finally we set this pointer location value to our tmp pointer as well.
tmp = head;
no we can proceed with our loop
strings in C are represented as an array of chars, whose stored location points to the first element of the char array. the array must also end with a NULL chat '\0'. note that strlen(str) will return length of string without the NULL char so you must add 1 while mallocing to take this into sconsideration. i would advise not messing with strings unless absolutely necessary. by that I mean trying to manually manipulate them. this will introduce another set of problems not related to what we're working on in general. we should just use strncar(), strncpy() methods until c style strings become completely intuitive.
I hope I understood right your question. I tried to fix the program like it will read a file and make a list of the data in the file.
I fixed some issues;
For the transverse function, i added a for loop and printed the data using %c.
while (temp != NULL) {
for(i=0; temp->data[i]!='\0'; i++) {
printf("%c\n", temp->data[i]);
}
temp = temp->next;
}
I changed the insertAtEnd function like this;
void insertAtEnd(FILE* f, char* data)
And naturally, in main function, calling this function changed like;
insertAtEnd(ifp, result[i]);
By the way for the following statement, my complier wanted me to express the temp as char, it said it was the first use of this. It also seems like you entered a space after &.
insertAtEnd(ofp, &temp);
I added the following statements to the main function;
argc -= optind;
argv += optind;
I also changed this ifp= fopen(ifilename, "r"); statement with this ifp= fopen("ifilename.txt", "r");statement. I opened a text file named ifilename.txt and wrote some data there.
EDIT:
Ok so if you want to print the strings to an output file and you want to print the words in the lines individually, you will change the code doing the following things:
I changed the struct's data with an array, gave it an expected maximum line length with a sharp defined MAX_LEN;
struct node
{
char* data[MAX_LEN];
struct node *prev;
struct node *next;
};
I changed the insertAtEnd function again because I scanned the file in main function, made an array of the strings, sent it to this function and added it to the end of the list. I used this piece of code in main fuction:
char* result[count];
char* temp = (char*)malloc(sizeof(char));
while (fgets(temp, sizeof(temp), ifp))
{
result[count] = (char*)malloc(sizeof(char)*20);
strcpy(result[count], temp);
insertAtEnd(result, count);
count++;
}
count is the number of strings in the file. I also sent this number to insertAtEnd function;
void insertAtEnd(char* data[], int size)
{
//Create a new node
struct node *newnode = (struct node*)malloc(sizeof(struct node));
newnode->data[size] = data[size];
if (newnode->data[size] != NULL) {
...
I wanted to use the output file you opened in the main function, so I sent this file and sent the count -number of strings- to the printing function transverse like this;
void traverse(FILE *of, int size)
{
int i;
// List is empty
if (head == NULL) {
printf("\nList is empty\n");
return;
};
// Else print the Data
struct node* temp;
temp = head;
while (temp != NULL) {
for(i=0; i<size; i++) {
fputs(temp->data[i], of);
temp = temp->next;
}
fprintf(of, "\n");
}
}
Also in main function, calling this function will be changing like;
traverse(ofp, count);
I still have troubles with the relations between the linked lists and the structures.
See, my objectif is to create a list where each node contains 2 characters strings. So, I tried something like this : first, I create a structure that represent an element with my 2 char ; second, a control structure for my list, thath will point at the beginning of my list. Which, in my .h, gives something like this :
typedef struct s_def { char *first_word; char *second_word; struct s-def *next; } t_def
typedef struct s_type { t_def *first; } t_list;
Next, I try to initialize my list. I make a function that work like this :
t_list *list;
t_def *words;
list = malloc(sizeof(*list));
words = malloc(sizeof(*words));
if (list == 0 || words == 0)
return (NULL);
words = NULL;
words->next = NULL;
list->first = words;
return (list);
Precision : I try to make an empty list for now, so that the user can add some elements later.
And that's where it block : when I run the program, it gives the typical Segmentation Fault. But it don't see what's wrong with what I made ! I put some write in my function to retrace the process : the malloc are working ok, as well as the words = NULL, but then the segment fault seems to run at the line
words->next = NULL;
What do I make wrong ? Why can't I give a NULL value at the next of my words ?
You first initialize the word pointer with allocated memory
words = malloc(sizeof(*words));
Then 3 lines down you set that pointer to NULL again, creating a memory leak
words = NULL;
And then you try to dereference the pointer that you just set to NULL:
words->next = NULL;
So, just remove the words = NULL;
The problem is most likely this part:
words = NULL;
words->next = NULL;
Here you reassign the pointer words to be a null pointer, and directly afterwards you dereference this null pointer, leading to undefined behavior.
When you set words to NULL, you have made a null pointer. Trying to access it immediately afterwards by words->next is effectively doing NULL->next which will cause an error.
Your code looks a little more complex than it needs to be for a simple linked list implementation, you might try something like:
typedef struct s_element
{
char* firstWord;
char* secondWord;
s_element* next;
} t_element;
t_element* list = NULL;
t_element* addFront(t_element* list, char* word1, char* word2)
{
t_element* next = list;
list = malloc(sizeof(t_element));
if (!list) return NULL;
list->firstWord = word1;
list->secondWord = word2;
list->next = next;
return list;
}
Assuming I haven't made any bone-headed syntax mistakes, this should be about as clear as a linked list can get. Notice that it doesn't need to check if the list is empty, the only conditional is in case malloc has failed.
So I'm doing some linked list revison and Im trying to just load a list with some numbers and then print it out. Below is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct stack {
int data;
struct stack *next;
}*stack;
stack create_s(void){
stack s = (void*)malloc(sizeof(stack));
s->next = NULL;
return s;
}
void push_s(stack s, int data) {
while (s->next != NULL) {
s = s->next;
}
s->next = (void*)malloc(sizeof(stack));
s=s->next;
s->data = data;
s->next = NULL;
}
void print_s(stack s) {
if (s==NULL) {
return;
}
else {
while (s->next != NULL) {
printf("%d\n",s->data);
s=s->next;
}
}
}
int main (void) {
stack s = create_s();
push_s(s,2);
push_s(s,4);
push_s(s,6);
push_s(s,8);
print_s(s);
return 0;
}
My output is however:
-1853045587
2
4
6
when it should be
2
4
6
8
Is it printing the address of my struct at the beginning? Also, why is it not printing my last element?
Thanks
The code contains several errors, but the first thing that catches the eye is that your memory allocation is already obviously broken
stack s = (void*)malloc(sizeof(stack));
You defined stack as a pointer type. This means that sizeof(stack) evaluates to pointer size and the above malloc allocates enough space to store a single pointer, not enough for the entire struct stack object. The same memory allocation error is present in push_s as well.
Here's some advice
Don't hide pointer types behind typedef names. Define your stack as
typedef struct stack{
int data;
struct stack *next;
} stack;
and use stack * wherever you need a pointer. I.e. make that * visible instead of hiding it "inside" a typedef name. This will make your code easier to read.
Don't cast the result of malloc. Anyway, what is the point of casting it to void * when it is void * already???
Don't use sizeof with types unless you really really have to. Prefer to use sizeof with expressions. Learn to use the following malloc idiom
T *p = malloc(sizeof *p);
or, in your case
struct stack *s = malloc(sizeof *s);
This will allocate a memory block of appropriate size.
Also, as #WhozCraig noted in the comments, the very first node in your list is apparently supposed to serve as a "sentinel" head node (with undefined data value). In your code you never initialize the data value in that head node. Yet in your print_s function you attempt to print data value from the head node. No wonder you get garbage (-1853045587) as the first line in your output. Don't print the very first node. Skip it, if it really is supposed to serve as a sentinel.
Also, the cycle termination condition in print_s looks strange
while (s->next != NULL)
Why are you checking s->next for NULL instead of checking s itself? This condition will terminate the cycle prematurely, without attempting to print the very last node in the list. This is the reason why you don't see the last element (8) in your output.
The actual cause of the given output can be fixed by changing:
s=s->next;
s->data = data;
to
s->data = data;
s=s->next;
First post on StackOverflow (tester by trade, extremely bad programmer in spare time). For disclosure purposes, this is a university assignment I'm struggling with (asking questions here isn't forbidden as far as I'm aware.
Anyway, I have a program that reads a line from a text file, tokenises the line data, creates a linked list and then inserts each token (2 strings, 1 float, 1 unsigned) into the node. All is fine until the memory being used by the node is freed - the entire program crashes. After debugging, I've seemingly isolated the problem to the two string copy operations. They both seem perfectly valid, but the free() doesn't like them at all. Tried strncpy() - no difference. Tried copying the string char by char - no difference. Now I'm at a loss...
Code below, if anyone would like to take a look (oh, more disclosure - pretty much a complete C n00b, so yes, if you see poor practices below, that would be me...)
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "ts.h"
int main(void)
{
/* Variables */
FILE *stream;
char buf[BUFSIZ];
/* Open stock file */ //TODO - make this dynamic, don't hard-code file name
stream = fopen("stock.csv", "r");
assert(stream);
/* Using addStockNode */
while (fgets(buf, BUFSIZ, stream))
{
addStockNode(buf);
}
}
void addStockNode(char* stockLine)
{
//Create linked list
StockNodePtr head, new, current, previous, nextStock;
unsigned listSize;
char *stkTok1, *stkTok2, *stkTok3, *stkTok4;
unsigned stkLevel;
int i;
float stkPrice;
listSize = 0;
head = NULL;
/* Create new stock node */
if ((new = malloc(sizeof(StockNodePtr))) == NULL)
{
fprintf(stderr,"\nMemory allocation for node insertion failed\n");
fprintf(stderr,"Aborting\n");
exit(EXIT_FAILURE);
}
/* Tokenise data */
stkTok1 = strtok(stockLine, ",");
stkTok2 = strtok(NULL, ",");
stkTok3 = strtok(NULL, ",");
stkTok4 = strtok(NULL, ",");
/* Search to find where in insert new list node */ //TODO - needs to be adapted to sort by stock DESCRIPTION
current = head;
previous = NULL;
/* stockID */
// strcpy(new->stockID, stkTok1); //falls over at free()
// strncpy(new->stockID, stkTok1, STOCKID_LEN); //falls over at free()
for(i = 0; i < strlen(stkTok1); i++) //still falls over at free()
{
new->stockID[i] = stkTok1[i];
}
/* description */
// strcpy(new->description, stkTok2); //falls over at free()
/* unitPrice */
stkPrice = strtof(stkTok3, NULL);
new->unitPrice = stkPrice;
/* StockLevel */
stkLevel = strtol(stkTok4, NULL, 10);
new->stockLevel = stkLevel;
/*nextStock */
new->nextStock = current;
/* Increment listSize */
listSize++;
//TAKE OUT LATER - loadData can iterate through each line of the file */
if(previous == NULL)
{
head = new;
}
else
{
previous->nextStock = new;
}
/* Print node details */
current = head;
printf("%s,%s,%f,%i\n", current->stockID, current->description, current->unitPrice, current->stockLevel);
/* Deallocate memory used by node */
current = head;
while(current != NULL)
{
nextStock = current->nextStock;
free(current); //EXECUTE THIS, IT FALLS OVER (with strcpy lines uncommented)
current = nextStock;
}
return EXIT_SUCCESS;
}*
For completeness purposes, here's the stock node struct...
typedef struct stockNode
{
char stockID[STOCKID_LEN + 1];
char description[DESCRIPTION_MAX + 1];
float unitPrice;
unsigned stockLevel;
StockNodePtr nextStock;
} StockNodeType;
If anyone can point out where I'm going wrong, I'd appreciate it!
Edit - Here are the stock node constants...
#define STOCKID_LEN 5
#define DESCRIPTION_MAX 40
#define PRICE_COLWIDTH 7
#define STOCKLEVEL_COLWIDTH 3
#define STOCKLEVEL_MAX 100
Oh, and the stock data that's being added (not that there's anything wrong with it)...
S0001,Slazenger Classic Racquet,150.00,5
S0002,Slazenger Lite Racquet,98.00,3
S0003,Wilson Tournament Gold Balls,14.95,20
S0004,Dunlop Grand Prix Balls,10.95,25
S0005,Luft Nemesis Racquet,125.00,1
S0006,Wilson Tournament Balls,12.95,12
Main Defect
Your fundamental problem is under-allocation, specifically this:
if ((new = malloc(sizeof(StockNodePtr))) == NULL)
Which means you're allocating space large enough to hold a pointer; not a stock node.
Try this instead:
if ((new = malloc(sizeof(*new))) == NULL)
Note: I've not thoroughly read the rest of this, but that is pretty huge in itself, as you're never allocating more memory per node than the size of a pointer. If there are other issues, I'll comment as I see them.
General Review
The following a general observations and suggestions within the code body not necessarily related to the main defect. Most of them point out problems that could, however, contribute to future defects.
Variable Initialization
Regarding general coding practice. never declare an uninitialized pointer. Ideally, never declare uninitialized anything. Things like this:
StockNodePtr head, new, current, previous, nextStock;
unsigned listSize;
can come back to really bite you on the bum. These should be as such:
StockNodePtr head=NULL, new=NULL, currentNULL, previousNULL, nextStockNULL;
unsigned listSize = 0;
If you're worried about initializing a value only to have it written over immediately after the declaration, fret not. The compiler will optimize that for you (volatile not withstanding).
Linked List Construction
A common problem in constructing a tail-appended linked list is knowing where the last "next" pointer is. People often jumble with two or three pointers, special case the head pointer on initial construction etc. I'm here to tell you none of that is needed.
Consider how a dbl-pointer (a pointer that holds the address of another pointer variable) can be very effective in assisting a tail-appended list during construction:
StockNodePtr head = NULL;
StockNodePtr *next = &head; // points to the next pointer to assign.
while(not finished)
{
StockNodePtr newNode = malloc(sizeof(*newNode));
// ...
// set all your fields.
//
// whatever pointer `next` points to gets the new node. on an
// initial list it will be the `head` pointer. on a subsequent
// node it will be the `nextStock` pointer of the last-node-added.
*next = newNode;
// now just set the new next-pointer-to-populate to be the `nextStock`
// pointer of the node we just added.
next = &newNode->nextStock;
}
// terminate the last node
*next = NULL;
The next pointer in the previous code always holds the address of the next pointer to fill. Initially it is populated with the address of the head pointer variable. When the loop finishes, whatever pointer next is pointing to needs to be set to NULL to terminate the list. Note: you need not set newNode->nextStock = NULL; when setting your fields. Either the next iteration of the loop will set it for you (to the next node) or the *next = NULL; after the loop will set it to NULL if it was the last node added.
I would dive into the usages of strtok() and all those pointers, but I'm late for dinner and my better half is calling. I hope this is at least somewhat helpful. Good luck, and have a dynamite day.
I am only allowed to use following headers
#include <stdio.h>
#include <stdlib.h>
and I defined my struct student as following:
struct dict
{
char* word;
struct dict* link;
};
There are many functions, but only one function that I have problem right now.
This function inserts a struct dict with certain name at the end of the link.
struct student *Linsert(struct dict *list, char *name)
{
struct student *pnew;
struct student *pn;
int exist = 1;
pnew = (struct dict *)malloc(sizeof(struct dict));
pnew -> next = NULL;
pnew -> name = name;
if (list != NULL)
{
for (pn = list; pn -> next != NULL; pn = pn -> next) ;
pn -> next = pnew;
}
else
list = pnew;
return list;
}
Using the following function,
//print all the values in the list
void printList(struct dict* list);
I did this:
int main(void)
{
struct dict *list = NULL;
char *name;
while (1) {
scanf("%s", name);
if (name == 'Q')
break;
list = Linsert(list, name);
printList(list);
}
return 0;
}
Lets say for input, I typed three
apple banana and orange, my result shows three of my last input.
What is the issue here?
I see two problems with your code:
You need to pass scanf a char array of size sufficient to store the input string, not simply a char pointer.
You need to copy strings passed into Linsert (use strdup).
Your main snippet alone has a whole bunch of problems:
name is an uninitialized pointer; it's pointing to some unknown location in memory that you haven't allocated and are allowed to use, therefore causing undefined behaviour. Perhaps you want char name[20] to allocate an array of 20 chars on the stack, and have scanf store the input in this buffer.
You're comparing a char* (a pointer to the start of a string) to a single char 'Q' - you're comparing a pointer and an integer value as your compiler warnings will tell you. You're not comparing the contents of the string for the value 'Q', you're comparing the memory address of name and the integer value for 'Q'. If you want to compare the string name with the string "Q", use strcmp and check for a return value of 0.
You also want to be making a copy of the variable passed to Linsert otherwise, as you've noticed, you'll be passing a pointer to the same location in memory every time, and a change to this block of memory will change each of your items.
If you turn your compiler warnings up you'll get even more warnings.
You are not allocating any memory for the name, so scanf is writing to some random location, and overwriting that every time through the loop.
One issue is that you've not allocated storage for the word member to point to. You have also not allocated space for name to point at. That is a principle cause of trouble.
You need to allocate space for name; the easiest way is:
char name[128];
You need to allocate space to store the word, and you need to copy the contents of name into the word so that when the next line overwrites name, it does not destroy the saved word.
Adapting your code, you might use:
struct student *Linsert(struct dict *list, char *name)
{
struct student *pnew;
struct student *pn;
pnew = (struct dict *)malloc(sizeof(struct dict));
if (pnew == 0)
...error...
pnew->next = NULL;
pnew->word = malloc(strlen(name) + 1);
if (pnew->word == 0)
...error...
strcpy(pnew->word, name);
if (list != NULL)
{
for (pn = list; pn->next != NULL; pn = pn->next)
;
pn->next = pnew;
}
else
list = pnew;
return list;
}
Do not omit the error checks on memory allocation - painful though it be. It will bite you when you forget.
Stylistically, do not use spaces around either -> or .; they are operators that bind very tightly, and they should not be spaced out like other binary operators.
There's a convenient function, strdup(), the duplicates a string, but it is not standard C (it is standard POSIX).
Since name is a char pointer, your assignment to the field of each dict struct will use the latest value it points to.