I want to make a program that would load data from txt file and put it into a linked list then print that linked list out. It seems to work but it also prints out some junk too. I'm quite new to linked lists so it's probably some obvious mistake. I would appreciate if someone told how to fix it, thanks in advance.
That's what inside my txt file:
FORD FIESTA 2010 1.6
OPEL ASTRA 2005 1.4
And that's what my program prints out:
FORD FIESTA 2010 1.6
OPEL ASTRA 2005 1.4
iŁ ;C:\Windows;C:\Windows\System32\ 1251983754 132.41
And here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Cars
{
char brand[30], model[30];
int year;
float engine;
struct Cars *next;
} Cars_t;
void load_cars(Cars_t *head, char file_name[30])
{
Cars_t *temp = head;
FILE *baza = fopen(file_name, "r");
if(baza!=NULL)
{
while(fscanf(baza, "%s%s%d%f", temp->brand, temp->model, &(temp->year), &(temp->engine)) == 4)
{
temp->next=malloc(sizeof(Cars_t));
temp=temp->next;
}
temp->next=NULL;
}
fclose(baza);
}
void print_list(Cars_t *head)
{
Cars_t *current = head;
while (current != NULL)
{
printf("%s\t%s\t%d\t%.2f\n", current->brand, current->model, current->year, current->engine);
current = current->next;
}
}
int main()
{
Cars_t *head = malloc(sizeof(Cars_t));
load_cars(head, "baza.txt");
print_list(head);
return 0;
}
You read 2 structs and alloc 3 times! First in main for head, then twice when you sucessfuly read from file. So your last alloc make no sense. I also add some security checks for your code but you only need to pay atention to lines comented with // <---- Special atention here!
Btw this example is not the best aproach i just did a fast fix for you to understand where is the problem.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Cars Cars_t, *pCars_t;
struct Cars
{
char brand[30], model[30];
int year;
float engine;
pCars_t next;
};
void load_cars(Cars_t *head, char file_name[30])
{
Cars_t *temp = head;
Cars_t *previous = NULL; // <---- Special atention here!
FILE *baza = fopen(file_name, "r");
if(baza!=NULL)
{
while(fscanf(baza, "%s%s%d%f", temp->brand, temp->model, &(temp->year), &(temp->engine)) == 4)
{
temp->next=malloc(sizeof(Cars_t));
if(temp->next == NULL)
{
fprintf(stderr, "Allocation error!\n");
exit(1);
}
previous = temp; // <---- Special atention here!
temp=temp->next;
}
temp->next=NULL;
free(previous->next); // <---- Special atention here!
previous->next=NULL; // <---- Special atention here!
}
else
{
fprintf(stderr, "File problem!");
return;
}
fclose(baza);
}
void print_list(Cars_t *head)
{
Cars_t *current = head;
while (current != NULL)
{
printf("%s\t%s\t%d\t%.2f\n", current->brand, current->model, current->year, current->engine);
current = current->next;
}
}
int main()
{
pCars_t head = malloc(sizeof(Cars_t));
if(head == NULL)
{
fprintf(stderr, "Allocation error!\n");
return 1;
}
load_cars(head, "baza.txt");
print_list(head);
return 0;
}
Related
I have a project that I'm working on for a Systems Programming course. I'm building off of my professor's code. (Please don't mind her lack of labelling, etc. - I'm gonna try to clean this up as best as I can.)
Does anybody know why her linked list code is printing backwards?
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char name[15];
char title[15];
int year;
struct Node *next;
struct Node *prev;
};
typedef struct Node *Box;
Box print_list(Box pointer);
Box insert_node(FILE *inputp);
int main() {
Box head = NULL, temp;
FILE *inputp, *outputp;
int i;
inputp = fopen("input.txt", "r");
outputp = fopen("output.txt", "w");
head = insert_node(inputp);
for (i = 0; i < 4; i++) {
temp = insert_node(inputp);
temp->next = head;
head = temp;
}
print_list(head);
return 0;
}
Box print_list(Box pointer) {
Box here = pointer;
while (here != NULL) {
printf("%s, %s, %d \n", here->name, here->title, here->year);
here = here->next;
}
return pointer;
}
Box insert_node(FILE *inputp) {
Box temp = NULL;
temp = (Box)malloc(sizeof(struct Node));
fscanf(inputp, "%s", &temp->name);
fscanf(inputp, "%s", &temp->title);
fscanf(inputp, " %d", &temp->year);
temp->next = NULL;
temp->prev = NULL;
return temp;
}
This program's purpose is to read a .txt file "playlist" of songs and create a linked list out of them. The input is:
Rachmaninov Concerto_No_2 1999
Mozart Symphony_No_41 2000
Vivaldi The_Seasons 2003
Beethoven Symphony_No_5 1994
Bach Toccatas 2005
While the program outputs:
Bach, Toccatas, 2005
Beethoven, Symphony_No_5, 1994
Vivaldi, The_Seasons, 2003
Mozart, Symphony_No_41, 2000
Rachmaninov, Concerto_No_2, 1999
(I also don't know why she included an output file in the code, all of the output is in the console, not stored in a file. Ignore that.)
The list prints in reverse order because you insert each new node at the beginning of the list. You should use a tail pointer to keep track of the end of the list.
Also note these remarks:
both the next and the prev links should be updated.
hiding pointers behind typedefs as in typedef struct Node *Box; is considered bad practice because it is confusing and error prone.
insert_node is a confusing name for a function that merely allocates a new node from file data.
insert_node should test if fscanf() succeeded at reading the data
fscanf(inputp, "%s", &temp->name); has undefined behavior if the name of the composer exceeds 14 bytes. The same applies to the title. The maximum number of characters to store into the destination arrays before the null terminator should be specified as %14s and these arrays should be defined with a larger length.
main should check if a node was successfully allocated and initialized from file data. Instead of hardcoding the number of nodes, one should iterate as long as nodes can be read from the file.
Here is a modified version:
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char name[40];
char title[40];
int year;
struct Node *next;
struct Node *prev;
};
void print_list(const Node *pointer);
Node *read_node(FILE *inputp);
int main() {
Node *head = NULL;
Node *tail = NULL;
Node *node;
FILE *inputp, *outputp;
int i;
inputp = fopen("input.txt", "r");
if (!inputp) {
fprintf(stderr, "cannot open input.txt: %s\n", strerror(errno));
return 1;
}
outputp = fopen("output.txt", "w");
if (!outputp) {
fprintf(stderr, "cannot open output.txt: %s\n", strerror(errno));
return 1;
}
while ((node = read_node(inputp)) != NULL) {
if (!head) {
head = tail = node;
} else {
node->prev = tail;
tail = tail->next = node;
}
}
print_list(head);
// should free node list
return 0;
}
void print_list(const Node *pointer) {
while (pointer != NULL) {
printf("%s, %s, %d\n", pointer->name, pointer->title, pointer->year);
pointer = pointer->next;
}
}
Node *read_node(FILE *inputp) {
Node *temp = malloc(sizeof(*temp));
if (temp != NULL
&& fscanf(inputp, "%39s%39s%d", &temp->name, &temp->title, &temp->year) == 3) {
temp->next = NULL;
temp->prev = NULL;
return temp;
} else {
free(temp);
return NULL;
}
}
I start learning linked lists.
My problem is that the conditional statement is not working. Here is the problem code.
'''
Node* search_word(Node* head, Word target)
{
Node*p=head;
while(p != NULL)
{
if(p->data.name==target.name)
{
printf("%s founded", target.name);
return p;
};
p=p->nextNodeAddress;
};
printf("There is no %s. \n", target.name);
return NULL;
}
'''
Here is my full source code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
# create struct named Word that have char name[100]
typedef struct Word
{
char name[100];
} Word;
# create struct named Node
typedef struct node
{
Word data;
struct node* nextNodeAddress;
} Node;
# Function that can insert node to the first of list
Node* insert_first(Node*head, Word newData)
{
Node* p=(Node*)malloc(sizeof(Node));
p->data = newData;
p->nextNodeAddress=head;
head=p;
return head;
};
# Function that can print out list
void print_listedNode(Node* head)
{
for(Node* i=head; i!=NULL; i=i->nextNodeAddress)
{
printf("%s->", i->data.name);
};
printf("NULL\n");
}
# Function that can search word (conditional statement is not working. But no error.)
Node* search_word(Node* head, Word target)
{
Node*p=head;
while(p != NULL)
{
if(p->data.name==target.name)
{
printf("%s founded", target.name);
return p;
};
p=p->nextNodeAddress;
};
printf("There is no %s. \n", target.name);
return NULL;
}
# int main()
int main(int argv, char* argc)
{
Node* head = NULL;
Word data;
strcpy(data.name, "APPLE");
head = insert_first(head, data);
print_listedNode(head);
strcpy(data.name, "LEMON");
head = insert_first(head, data);
print_listedNode(head);
strcpy(data.name, "BANANA");
head = insert_first(head, data);
print_listedNode(head);
strcpy(data.name, "BANANA");
head = search_word(head, data);
print_listedNode(head);
return 0;
}
and the result is
APPLE->NULL
LEMON->APPLE->NULL
BANANA->LEMON->APPLE->NULL
There is no BANANA.
NULL
I expect to get
APPLE->NULL
LEMON->APPLE->NULL
BANANA->LEMON->APPLE->NULL
BANANA founded
BANANA->LEMON->APPLE->NULL
Thank you for reading the eye-breaking code.
In this if statement
if(p->data.name==target.name)
there are compared two pointers (after the implicit conversion of the array designators to pointers to their first elements) instead of the strings pointed to by the pointers.
You need to write
if( strcmp( p->data.name, target.name ) == 0 )
I am trying to use an array-based linked list to read in values from data.txt and then display those items. The list does not need to be ordered. Currently, it is only printing the last item on the list. I am not positive if I am reading the entire list currently or just the last word. I would appreciate any advice. I have made some changes since earlier. It compiles but I get a segfault which valgrind states "Invalid write or size 1".
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_SIZE 25
#define MAX_NODES 100
#define FILENAME "data.txt"
char buffer[WORD_SIZE];
int count = 0, i = 0;
typedef struct WORDNODE {
char word[WORD_SIZE];
struct WORDNODE *next;
} t_word_node;
t_word_node node_array[MAX_NODES];
t_word_node *free_list = NULL;
t_word_node *tail = NULL;
t_word_node *create_node(void);
void add_word(char *buffer, t_word_node **);
void node_init() {
for(int count = 0; count < MAX_NODES-2; count++) {
node_array[count].next = &node_array[count+1];
}
node_array[MAX_NODES - 1].next = NULL;
free_list = &node_array[0];
}
void add_word(char *buffer, t_word_node **list) {
t_word_node *temp = NULL;
t_word_node *last = NULL;
t_word_node *this = *list;
temp = create_node();
strcpy(temp->word, buffer);
while(this && strcmp(buffer, this->word) > 0) {
last = this;
this = this->next;
}
if(last == NULL) {
temp->next = this;
*list = temp;
} else {
last->next = temp;
temp->next = this;
}
}
t_word_node *create_node() {
t_word_node *new = NULL;
if(free_list != NULL)
{
new = free_list;
free_list = free_list->next;
}
return new;
}
void print_nodes(t_word_node *this) {
if(this == NULL) {
return;
}
while(this != NULL) {
printf("%s\n", this->word);
this = this->next;
}
}
int main() {
count = 0;
FILE *infile;
t_word_node *new_list = NULL;
node_init();
if((infile = fopen(FILENAME, "r")) != NULL) {
while (fscanf(infile, "%s", buffer) != EOF) {
add_word(buffer, &new_list);
}
fclose(infile);
}
print_nodes(new_list);
return 0;
}
data.txt
Kaleidoscope
Rainbow
Navy
Highway
Printer
Junk
Milk
Spectrum
Grapes
Earth
Horse
Sunglasses
Coffee-shop
Ice
Spice
Tennis racquet
Drill
Electricity
Fan
Meat
Clown
Weapon
Drink
Record
Spiral
Air
Data Base
Cycle
Snail
Child
Eraser
Meteor
Woman
Necklace
Festival
Eyes
Foot
Diamond
Chocolates
Explosive
Web
Rifle
Leather jacket
Aeroplane
Chisel
Hose
Flower
Space Shuttle
Radar
Hieroglyph
Ice-cream
Insect
Feather
Ears
Square
Software
Cup
Comet
Church
PaintBrush
Slave
Elephant
Sphere
Aircraft Carrier
Fork
Needle
Prison
Solid
Window
Dress
Knife
Spot Light
Onion
Horoscope
Chief
Crystal
Coffee
Microscope
Freeway
Fruit
Kitchen
Desk
Spoon
Pyramid
Restaurant
Adult
Potato
Egg
Telescope
Family
Sports-car
Television
Jet fighter
Thermometer
Wheelchair
X-ray
Sun
Worm
Church
The problem is you are misusing your tail pointer as a temp pointer. Use temp for a temporary pointer. Next validate that every word read will fit in an array of WORD_SIZE and validate EVERY allocation.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_SIZE 25
#define FILENAME "data.txt"
typedef struct WORDNODE {
char word[WORD_SIZE];
struct WORDNODE *next;
} t_word_node;
t_word_node *head, *tail, *temp;
t_word_node *create_node()
{
return(t_word_node *)malloc(sizeof(t_word_node));
}
int main (int argc, char **argv) {
char buffer[WORD_SIZE];
FILE *infile;
infile = fopen(argc > 1 ? argv[1] : FILENAME, "r");
while (fgets (buffer, sizeof(buffer), infile) != NULL) {
size_t len;
buffer[(len = strcspn (buffer, "\n"))] = 0;
if (len >= WORD_SIZE) {
fputs ("error: word exceeds WORD_SIZE\n", stderr);
continue;
}
if (!(temp = create_node())) {
perror ("malloc-create_node()");
return 1;
}
strcpy(temp->word, buffer);
temp->next = NULL;
if (head == NULL)
head = tail = temp;
else {
tail->next = temp;
tail = temp;
}
}
temp = head;
while (temp != NULL) {
puts (temp->word);
temp = temp->next;
}
return 0;
}
You have a tail pointer -- there is never a need to iterate over the list to insert-at-end (that's what the tail pointer is for). Note above how tail is initialized when the first node is added to the list.
Example Use/Output
Do not hardcode filenames. That's what argc and argv are for in int main (int argc, char **argv), pass the filename to read as the first argument to your program or read from FILENAME by default if no argument is provided:
$ ./bin/llarraywords dat/datallwords.txt
Kaleidoscope
Rainbow
Navy
Highway
Printer
Junk
Milk
Spectrum
Grapes
Earth
Horse
Sunglasses
...
<snip>
...
Egg
Telescope
Family
Sports-car
Television
Jet fighter
Thermometer
Wheelchair
X-ray
Sun
Worm
Church
Look things over and let me know if you have further questions.
I'm pretty new to C and pointers.
Following codes are for implementing a linked list in which each node contains a data of record.
However, when I compile and run this program, it shows an error "segmentation fault", and I guess the following part from my code makes an error.
head->next = NULL in functions in list.c
I doubt the segmentation fault error happens due to dereferencing a null pointer but have no idea what's wrong with my code.
list.h
#ifndef LIST_H
#define LIST_H
#include <stddef.h>
#include "record.h"
typedef struct node node;
struct node {
record data;
node *next;
};
typedef node *record_list; /* a record list is represented by its "head"
pointer */
void list_init(record_list *plist);
int list_insert(record_list *plist, const record *prec);
void list_clear(record_list *plist);
void list_print(const record_list *plist);
#endif
io.h
#ifndef IO_H
#define IO_H
#include "record.h"
void print_record(const record *p);
int read_record(record *p);
/* reads a string from stdin */
int get_word(const char prompt[], char word[]);
/* reads an int from stdin */
int get_int(const char prompt[], int *p);
#endif
record.h
#ifndef RECORD_H
#define RECORD_H
#define IDSIZE 10
#define NAMESIZE 20
typedef struct {
char last[NAMESIZE];
char first[NAMESIZE];
} name;
typedef struct {
char id[IDSIZE];
name name;
int score;
} record;
#endif
list.c
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "record.h"
#include "list.h"
#include "io.h"
/* initializes a record list (specified via plist) to an empty list */
void list_init(record_list *plist) {
node *head;
head = *plist;
head = NULL;
head->next = NULL;
printf("%s", "segmentation???\n");
}
/*
* inserts a record (specified via prec) into a record list
*/
int list_insert(record_list *plist, const record *prec) {
node *current, *temp;
printf("%s", "list insert\n");
current = *plist;
while (current->next != NULL) {
current = current->next;
}
temp = (node *)malloc(sizeof(node));
if (temp == NULL) {
fprintf(stderr, "memory allocate failed");
return 0;
}
current->next = temp;
current->next->data = *prec;
current->next->next = NULL;
printf("%s", "list insert done\n");
return 1;
}
/*
* deallocates all dynamic memory associated with a record list (specified
* via plist) & resets the record list to an empty list
*/
void list_clear(record_list *plist) {
printf("%s", "list clear\n");
free((*plist)->next);
plist = NULL;
(*plist)->next = NULL;
}
/* prints all records in a record list (specified via plist) */
void list_print(const record_list *plist) {
node *current;
current = *plist;
printf("%s", "list print\n");
while (current->next != NULL) {
print_record(&(current->data));
current = current->next;
}
}
io.c
#include <stdio.h>
#include <string.h>
#include "record.h"
#include "io.h"
#define LINESIZE 1024
/*
* prints a record (specified via p);
*/
void print_record(const record *p) {
printf("%d %s %s %s\n", p->score, p->name.last, p->name.first, p->id);
}
/*
* reads a record from stadard input & stores it via p;
*/
int read_record(record *p) {
return (
get_word("Enter id: ", p->id)
&& get_word("Enter last name: ", p->name.last)
&& get_word("Enter first name: ", p->name.first)
&& get_int("Enter score: ", &(p->score))
);
}
/* reads a string from stdin */
int get_word(const char prompt[], char word[]){
char line[LINESIZE];
char temp[LINESIZE];
while (1) {
printf("%s", prompt);
if(!fgets(line, LINESIZE, stdin)){
clearerr(stdin);
return 0;
}
if (sscanf(line, "%s", temp) == 1){
strcpy(word, temp);
return 1;
}
}
}
/* reads an int from stdin */
int get_int(const char prompt[], int *p) {
char line[LINESIZE];
while (1) {
printf("%s", prompt);
if (!fgets(line, LINESIZE, stdin)) {
clearerr(stdin);
return 0;
}
if (sscanf(line, "%d", p) == 1) {
return 1;
} else {
printf("%s", "Error: The input is not given in integer.\n");
}
}
}
main.c
#include <stdio.h>
#include "record.h"
#include "list.h"
#include "io.h"
int main(void) {
record_list list;
record r;
printf("address of list: %ld\n", &list);
printf("address of list: %ld\n", &(list->next));
list_init(&list);
while (read_record(&r)) {
printf("%s\n", "read success");
if (!list_insert(&list, &r))
break;
}
list_print(&list);
return 0;
}
If your goal is to create an empty list and plist is the pointer to the head of the list you have to set the variable pointed by plist to NULL with *plist = NULL; , you can get rid of the code is causing the segmentation fault
Ok I think I find the next error:
current = *plist;
while (current->next != NULL) {
current = current->next;
}
Will cause errors because the first time you call list_insert you have *plist equals to NULL because the list is empty and so current->next != NULL will cause the error (current is also equals to NULL)
I suggest the following:
printf("%s", "list insert\n");
if (*plist == NULL) {
temp = (node * )malloc(sizeof(node));
if (temp == NULL) {
fprintf(stderr, "memory allocate failed");
return 0;
}
plist = temp;
(*plist) ->data = *prec;
(*plist) ->next = NULL;
return 1;
}
current = *plist;
while (current->next != NULL) {
current = current->next;
}
And the rest of the code as it was, I added an if for the case *pilist is equals to NULL, in that case temp is going to point at the first element and has to be assigned to plist
I'm working on two functions. The first one loads a list from a file into the program (at the start) and the second one saves the list's data to the file. I've tried to write the two functions but I'm having a hard time(I'm not really good at programming). Here are the structs I'm using I'm also adding the define of index and the creation of the list:
#define index 30
typedef struct dataR* data;
struct dataR{
int age;
char name[index];
};
typedef struct nodeR* node;
struct nodeR{
data a;
node next;
};
typedef struct listR* list;
struct listR{
node head, tail, curr;
int size;
};
list list_create(){
list List=malloc(sizeof(struct listR));
assert(List);
List->head=NULL;
List->tail=NULL;
List->curr=NULL;
List->size=0;
return List;
}
Here is the function to load the file data into the list (at the start of the program). Obviously it is wrong but I don't know how to load the data to each node since the list is empty:
list load(char *filename, list List)
{
FILE *fd=fopen("filename","r");
fscanf(fd, "%d",&(List->head->a->age));
fscanf(fd, "%s",&(List->head->a->name[index-1]));
fclose(fd);
fd=NULL;
}
And here is the function that save all of the list's data at the end of the program :
void save(char *filename, list List)
{
FILE *fd=fopen("filename.dat","w");
if (fd==NULL)
{
printf("File does not exist");
return;
}
fwrite(List->head->a, sizeof(struct dataR),1,fd);
node tmp=List->head->next;
while(tmp->next!=NULL)
{
fwrite(tmp->next->a, sizeof(struct dataR),1,fd);
tmp=tmp->next;
}
fclose(fd);
fd=NULL;
}
The data in the file should look kind like this:
35 Nick
29 Jim
19 Helen
Well, ofcourse the functions don't do that as they are. So I need some help to improve them. Any tips (on files) and help is much appreciated.I'm sorry for the long post. Thank you for your time.
To fix like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define S_(v) #v
#define S(v) S_(v) //stringify
#define MAX_NAME_LENGTH 30 //index is bad name
typedef struct dataR* data;
struct dataR{
int age;
char name[MAX_NAME_LENGTH + 1];
};
typedef struct nodeR* node;
struct nodeR{
data a;
node next;
};
typedef struct listR* list;
struct listR{
node head, tail, curr;//curr unused?
int size;
};
list list_create(void){
list List = malloc(sizeof(*List));
assert(List);
List->curr = List->tail = List->head = NULL;
List->size=0;
return List;
}
void addList(list List, data new_data){
node new_node = malloc(sizeof(*new_node));
new_node->a = new_data;
new_node->next = NULL;
if(List->head == NULL)
List->head = List->tail = new_node;
else
List->tail = List->tail->next = new_node;
++List->size;
}
list load(const char *filename, list List){
FILE *fd = fopen(filename,"r");//"filename"--> filename, LOL
if(!fd){
fprintf(stderr, "%s can't open in load.\n", filename);
perror("fopen");
return NULL;
}
int age;
while(EOF != fscanf(fd, "%d", &age)){// or 1 == fscanf(fd, "%d", &age)){
data new_data = malloc(sizeof(*new_data));
new_data->age = age;
fscanf(fd, "%" S(MAX_NAME_LENGTH) "s", new_data->name);
addList(List, new_data);
}
fclose(fd);
//fd=NULL;//meaningless
return List;//need return value;
}
void save(const char *filename, list List){
FILE *fd=fopen(filename, "w");
if(!fd){
fprintf(stderr, "%s can't open in save.\n", filename);
perror("fopen");
return ;
}
//fwrite(List->head->a, sizeof(struct dataR),1,fd);//fwrite doesn't match load
node tmp = List->head;
while(tmp){
fprintf(fd, "%d %s\n", tmp->a->age, tmp->a->name);
tmp = tmp->next;
}
fclose(fd);
}
int main(void){
list List = list_create();
load("list.txt", List);
printf("List hold %d data.\n", List->size);
data addData = malloc(sizeof(*addData));
addData->age = 73;
strcpy(addData->name, "Ken");
addList(List, addData);
save("list.txt", List);
//deallocate
return 0;
}