I'm trying to learn how to work with dynamic lists in C, but can't seem to wrap my head around it - so help would be appreaciated. I've got a struct that has some info that i'm reading from a txt file in the command line and would need to add the info to a dynamic list..
this is what i have so far. I'm at a loss with pointers and don't know if the arguments are correct and where to go from there.
Have spent the better part of the weekend looking for a way to get this done. It isn't hard as I get the concept, just that the nuts and bolts of it are just eluding me...
#include <stdio.h>
#include <stdlib.h>
#define SIZE_MAX 20
#define BUFFER_MAX 256
FILE *file;
/*struct*/
struct student {
char name[SIZE_MAX];
int grade;
struct student *next;
};
typedef struct student Student;
int addToList(Student **head, char *, int);
void printList(Student **head);
void releaseMem(Student **head);
/*functions*/
void addToList(Student **head, char *name, int grade ){
//???
}
/*Main*/
int main (int argc, char *argv[]){
Student *head=NULL,*tail=NULL;
int grade = 100 ;
char buffer [BUFFER_MAX];
char name[SIZE_MAX];
/*opening file*/
file = fopen(argv[1], "r");
if (file == NULL){
printf("\n\tWARNING: No data found.\n");
exit(1);
}
else{
printf("Reading file %s \n",argv[1]);
}
/*creating first node*/
Student* new_student(Student*)malloc(sizeof(Student));
while(fgets(buffer, BUFFER_MAX,file)!= NULL){
sscanf(buffer,"%s%d",name,&grade);
//printf("%s %d\n",string, grade);
addToList(&head,name,grade);
}
return 0;
}
Edit: So far I've managed to add the data from the file to a dynamic list (thank you for the help). Here is what I have:
#include <stdio.h>
#include <stdlib.h>
#define SIZE_MAX 20
#define BUFFER_MAX 256
FILE *file;
/*Struct*/
struct student {
char name[SIZE_MAX];
int grade;
struct student *next;
};
typedef struct student Student;
int addToList(Student **head, char *, int);
void printList(Student *head);
void releaseMem(Student *head);
/*functions*/
int addToList(Student **head, char *name, int grade ){
Student *new_student = malloc( sizeof( Student ) );
{
Student *new_student = malloc( sizeof( Student ) );
int success = new_student != NULL;
if ( success )
{
strcpy( new_student->name, name );
new_student->grade = grade;
new_student->next = *head;
*head = new_student;
}
return success;
}
}
void printList(Student *head){
Student * current = head;
int i = 1;
while (current != NULL) {
printf("%d. Student: %s grade %d\n",i,current->name ,current->grade);
i++;
current = current->next;
}
}
void releaseMem(Student *head){
Student * current = head;
while (current != NULL) {
free(current);
current = current->next;
}
printf("mem cleared.\n");
}
/*Main*/
int main (int argc, char *argv[]){
Student *head=NULL,*first=NULL, *temp = NULL;
int grade = 100 ;
char buffer [BUFFER_MAX];
char name[SIZE_MAX];
/*opening file*/
file = fopen(argv[1], "r");
if (file == NULL){
printf("\n\tWARNING: No data found.\n");
exit(1);
}
else{
printf("reading file %s. \n",argv[1]);
}
printf("data added to list.\n");
while(fgets(buffer, BUFFER_MAX,file)!= NULL){
sscanf(buffer,"%s%d",name,&grade);
addToList(&head,name,grade);
}
printList(head);
releaseMem(head);
return 0;
}
Works (almost) like i'd like it to work. For some reason the printList function prints the content of the file in reverse order and after fiddling with it for some time I don't know how to print it from the beginning to the end instead from the end to the beginning. I suppose it has to do with pointers but more than that i'm at a loss what to do... What am I missing here? How would I go about reversing the printing order with keeping the (formatting) as it currently is?
you should allocate new students in the student list and place it to the last member's next like this :
//since we are adding new members after the last member in linked list
//we are not going to change value of head so sending **head is not useful
void addToList(Student *head,char *name,int grade){
Student *node;
for(node = head; node->next != NULL; node = node->next );
// now node points the last member of your linked list
// now we are adding new student to the linked list with allocating memory
node->next = (Student *)malloc(sizeof(student));
node->next->grade = grade;
strcpy(node->next->name,name);
}
The program will not compile at least because this statement
Student* new_student(Student*)malloc(sizeof(Student));
is invalid. And even if to write it like
Student* new_student = (Student*)malloc(sizeof(Student));
it does not make sense because new items should be added to the list by using the function addToList.
The declaration of the variable tail also does not make sense because it is impossible to pass it to the function (as it is declared) addToList along with the head.
As for the function itself then it is better to declare it the following way
int addToList( Student **head, const char *name, int grade );
The function can be defined like
int addToList( Student **head, const char *name, int grade )
{
Student *new_student = malloc( sizeof( Student ) );
int success = new_student != NULL;
if ( success )
{
strcpy( new_student->name, name );
// or
// strncpy( new_student->name, name, SIZE_MAX );
// new_student->name[SIZE_MAX - 1] = '\0';
new_student->grade = grade;
new_student->next = *head;
*head = new_student;
}
return success;
}
Related
I am attempting to create a linked list from a file using structs, when I run the print_list it is not printing the name or threat level, but it is printing the ID. I have little experience with structs but I believe I am not understanding if the pointers are being used correctly here.
void insert(struct poi_t_struct **head_ref, char *name, long int id, int threat_level) {
// printf("Name from insert %s \n", name); // debug
struct poi_t_struct newNode = { name, id, threat_level, NULL };
struct poi_t_struct *ptr_newNode = &newNode;
struct poi_t_struct *temp = *head_ref;
}
void buildLList(char *filename) {
FILE *poiProfiles;
// char line[MAX_LINE_LENGTH];
// have 3 char arrays. One for each name, id, threat level
char idLine[MAX_LINE_LENGTH];
char nameLine[MAX_LINE_LENGTH];
char threat_levelLine[MAX_LINE_LENGTH];
while (fgets(idLine, MAX_LINE_LENGTH, poiProfiles)) {
long int id;
id = atoi(idLine);
fgets(nameLine, MAX_LINE_LENGTH, poiProfiles);
char* name;
name = nameLine;
fgets(threat_levelLine, MAX_LINE_LENGTH, poiProfiles);
int threat_level;
threat_level = atoi(threat_levelLine);
insert(&head, name, id, threat_level);
}
void print_list(struct poi_t_struct *p) {
struct poi_t_struct *temp = p;
while (temp != NULL) {
print_record(temp);
temp = temp->next;
}
}
There are multiple problems in your code:
you do not open nor close the file for poiProfiles
there is a missing } at the end of the buildLList() function.
the insert function must allocate memory for the new node, inserting a local struct object is incorrect as this object becomes invalid as soon as the function returns. You attempt to insert the new node at the beginning of the list, but you neither set the next member of the struct, not set *head_ref to point to the new node.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct poi_t_struct {
char *name;
long int id;
int threat_level;
struct poi_t_struct *next;
} *head;
int insert(struct poi_t_struct **head_ref, const char *name, long int id, int threat_level) {
// printf("Name from insert %s \n", name); // debug
struct poi_t_struct *ptr_newNode = malloc(sizeof *ptr_newNode);
if (ptr_newNode == NULL)
return -1;
ptr_newNode->name = strdup(name);
ptr_newNode->id = id;
ptr_newNode->threat_level = threat_level;
ptr_newNode->next = *head_ref;
*head_ref = ptr_newNode;
return 0;
}
int buildLList(const char *filename) {
// have 3 char arrays. One for each name, id, threat level
char idLine[MAX_LINE_LENGTH];
char nameLine[MAX_LINE_LENGTH];
char threat_levelLine[MAX_LINE_LENGTH];
FILE *poiProfiles;
int count = 0;
poiProfiles = fopen(filename, "r");
if (poiProfiles == NULL) {
fprintf(stderr, "cannot open %s: %s\n", filename, strerror(errno));
return -1;
}
while (fgets(idLine, MAX_LINE_LENGTH, poiProfiles)
&& fgets(nameLine, MAX_LINE_LENGTH, poiProfiles)
&& fgets(threat_levelLine, MAX_LINE_LENGTH, poiProfiles)) {
long int id = atoi(idLine);
char *name = nameLine;
int threat_level = atoi(threat_levelLine);
if (!insert(&head, name, id, threat_level))
count++;
}
fclose(poiProfiles);
return count;
}
void print_list(const struct poi_t_struct *p) {
const struct poi_t_struct *temp = p;
while (temp != NULL) {
print_record(temp);
temp = temp->next;
}
}
I am trying to read a binary file which it has names,years, from movies and then to create a list from that file data....but when am using this code am getting a blank screen.
struct node *next;
}node;
node *head;
node *tail;
node*inventory = NULL;
int main(int argc , char * argv){
node *current;
node n;
node *p;
FILE *ptr;
ptr=fopen("movies.dat", "rb");
head= NULL;
while(!feof(ptr))
{
p = (node*)malloc(sizeof(node));
if (!head)
{
head =(node*) malloc(sizeof(node));
current = head;
}
fread(p, sizeof(node), 1, ptr);
current->next = p;
p=current;
}
fclose(ptr);
The example output should look like this:
$ ./a.out --list-all
The Godfather 1972 245066416.00
Snatch 2000 30093108.00
Thanks in regards
First of all a list should look like this
Inside the header file :
typedef struct Node_t Node;
struct Node_t
{
void* data;
int id;
Node_t* next_node; //next node
};
typedef struct List_t
{
int number_of_nodes;
Node_t* start_index; //pointer , points at first node , start of the list.
}List;
So upon reading (which seems ok) , for each movie you have to create a structure to hold movie data.Let's say
typedef struct Movie_t
{
char name[16];
int year;
}Movie_t;
So in every element you read you store name and year in a struct and then you create a Node_t that points for void* data in the pointer of the Movie_t object and you add Node_t in list.
Your code is not enough to help you where exactly you made the mistake. Hence I have developed the below codes for you. Just modify the structure for more field and change the code accordingly so that you can learn properly.
struct Movie
{
char *name;
char *date;
struct Movie *next;
};
struct Movie * initialize(char *);
void display(struct Movie *);
int main()
{
struct Movie *head;
char fname[100];
head=initialize("movies.dat");
display(head);
}
struct Movie * initialize(char *fname)
{
FILE* fpointer;
char ch;
fpointer = fopen(fname,"r");
if(fpointer == NULL)
{
printf("\nFile not found");
exit(1);
}
//FILE IS OPENED
struct Movie *head=NULL;
struct Movie *t;
char line[255];
char sent[2]=";";
while(!feof(fpointer) && fgets(line,sizeof line,fpointer))
{
char *name=strtok(line,sent);
char *date=strtok(NULL,sent);
if(head == NULL)
{
head=(struct Movie*)malloc(sizeof(struct Movie));
t = head;
t->name = (char *)malloc(strlen(name));
t->date = (char *)malloc(strlen(date));
strcpy(t->name,name);
strcpy(t->date,date);
t->next=NULL;
}
else
{
t->next=(struct Movie*)malloc(sizeof(struct Movie));
t=t->next;
t->name = (char *)malloc(strlen(name));
t->date = (char *)malloc(strlen(date));
strcpy(t->name,name);
strcpy(t->date,date);
t->next=NULL;
}
}
return head;
}
void display(struct Movie *h)
{
while(h!=NULL)
{
printf("Name :%20s %10s\n",h->name,h->date);
h=h->next;
}
}
now create movies.dat with below information:-
The Godfather;1972;
Snatch;2000;
here in the file you can add as many as film information. Here every field has been separated by ; you can separate field with any special character as per your wish but you need to make necessary changes in the below line of code each time.
char sent[2]=";";
Your field separator can be any character for example The Godfather|1972| in this case you need to modify your code like char sent[2]="|"; Better give it a proper name like char seperator[2]=":"; here your separator is :
Also do not forget to add header files , and
Wish you all the very best.
So my assignment is to take in letters (6 per line) of a text file, save it into linked lists, and then print out the information of specific "die"(in this case) - which is each group of 6 letters.
I've got the data to read in correctly (I think) in the readData function, but am unsure if that linked list is getting passed correctly. When I try to print out the linked list in main (lines ~40-41) I get nothing. Am I passing my function incorrectly to readData?
Here's my code:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define LENGTH 80
struct boggleDataNode {
char data[3];
struct boggleDataNode *nextData;
};
struct boggleDieSideNode{
char dieSideData[3];
struct boggleDieSideNode *nextSide;
};
void readData(struct boggleDataNode *temp);
void printData(struct boggleDataNode *temp);
int main() {
int counter = 0;
struct boggleDataNode *head;
struct boggleDieSideNode *head1;
struct boggleDataNode *temp;
head = NULL;
head1 = NULL;
temp = head;
printf("test\n\n");
readData(&temp);
// printData(temp);
while(counter = 0, counter<100, counter++)
printf("%s ", temp->data[counter]);
system("pause");
return 0;
}
void readData(struct boggleDataNode *temp) {
//initializing variables including
//opening the input file
FILE *input = fopen("BoggleData.txt","r");
char data[96] = {};
struct boggleDataNode *new;
int counter = 0;
temp = new;
//error checking that the file opened
if (input == NULL) {
fprintf(stderr, "Can't open input file!\n");
exit(1);
}
new = (struct boggleDataNode *)malloc(sizeof(struct boggleDataNode));
while (fscanf(input, "%s", data) != EOF) {
printf("%s ", data);
strcpy(temp->data, data);
printf("Data number %d %s \n",counter,temp->data);
temp->nextData = NULL;
counter++;
}
}
You are passing your structure incorrectly to readData. Your declare your variable like so:
struct boggleDataNode *temp;
You invoke readData thusly:
readData(&temp);
You declare readData as such:
void readData(struct boggleDataNode *temp){
So, you declare both temp and readData's input as struct boggleDataNode *, but you pass &temp to readData. & means you are sending the address of what follows, so &temp is a pointer to a pointer to a struct boggleDataNode, which is a struct boggleDataNode **.
There are other problems with your code, but that is beyond the scope of your question. I will point out that your output loop is very, very wrong.
I am working on a program that can process structure items in linkedlist/nodes.
I have most of the functions running fine, however am stuck on how to read from a txt file into a structure (the readFromFile function).
I have been reading around but am still quite confused, mainly on how to write this as a function instead of in main, and also reading into a structure
any help would be appreciated.
EDIT:
I cannot seem to get the functions in the answers to work at the moment, so I am changing to trying to make the program read from txt in main.
I could open the file, but the problem is:
How do I read data into my linked list?
(code has been modified)
The text file I am reading from is formatted like this:
#1 Flat Blade Screwdriver
12489
36
.65
1.75
#2 Flat Blade Screwdriver
12488
24
.70
1.85
#1 Phillips Screwdriver
12456
27
0.67
1.80
#2 Phillips Screwdriver
12455
17
0.81
2.00
Claw Hammer
03448
14
3.27
4.89
Tack Hammer
03442
9
3.55
5.27
Cross Cut Saw
07224
6
6.97
8.25
Rip Saw
07228
5
6.48
7.99
6" Adjustable Wrench
06526
11
3.21
4.50
My program so far:
#include "stdafx.h"
#include <stdlib.h>
typedef struct inventory
{
char invName[36];
int invPartNo;
int invQOH;
float invUnitCost;
float invPrice;
}stock;
struct NODE
{
union
{
int nodeCounter;
void *dataitem;
}item;
struct NODE *link;
};
struct NODE *InitList();
void DisplayNode(struct inventory *);
struct inventory * ReadData(FILE *);
void DisplayList(struct NODE *);
struct NODE* GetNode(FILE *);
void Add2List(struct NODE *, struct NODE *);
struct NODE* SearchList(struct NODE *, int );
void DeleteNode(struct NODE *, int );
int main(int argc, char* argv[])
{
struct NODE *header;
header = InitList();
char ch, file_name[25];
FILE *fp;
printf("Enter the name of file you wish to see\n");
gets(file_name);
fp = fopen(file_name,"r"); // read mode
if( fp == NULL )
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
printf("The contents of %s file are :\n", file_name);
while( ( ch = fgetc(fp) ) != EOF )
{
//what to put here?
}
fclose(fp);
DisplayList(header);
return 0;
}
struct NODE *InitList()
{
struct NODE *temp = (struct NODE*)malloc(sizeof NODE);
temp->item.nodeCounter = 0;
temp->link = NULL;
return temp;
}
void Add2List(struct NODE *start, struct NODE *NewNode)
{
struct NODE *current = start;
while (current->link != NULL)
current = current->link;
current->link = NewNode;
NewNode->link = NULL;
start->item.nodeCounter++;
}
struct NODE* GetNode(FILE *fptr)
{
struct NODE *temp = (struct NODE*)malloc(sizeof NODE);
temp->item.dataitem = ReadData(fptr);
temp->link = NULL;
return temp;
}
void DisplayList(struct NODE *start)
{
struct NODE *current = start->link;
while (current != NULL)
{
DisplayNode((struct inventory *)current->item.dataitem);
current = current->link;
}
}
void DisplayNode(struct inventory *stuff)
{
/*
char invName[36];
int invPartNo;
int invQOH;
float invUnitCost;
float invPrice;
*/
printf("Name: %s", stuff->invName);
printf("Part Number: %d", stuff->invPartNo);
printf("Quantity on hand: %d", stuff->invQOH);
printf("Unit Cost: %0.2f", stuff->invUnitCost);
printf("Price %0.2f", stuff->invPrice);
}
struct inventory * ReadData(FILE *fptr)
{
struct inventory *temp = (struct inventory *)malloc(sizeof inventory);
if(fptr==stdin)
printf("Enter item name: ");
fscanf_s(fptr, "%s", temp->invName);
if(fptr==stdin)
printf("Enter item part number: ");
fscanf_s(fptr, "%d", &temp->invPartNo);
if(fptr==stdin)
printf("Enter item quantity on hand: ");
fscanf_s(fptr, "%d", &temp->invQOH);
if(fptr==stdin)
printf("Enter item unit cost: ");
fscanf_s(fptr, "%f", &temp->invUnitCost);
if(fptr==stdin)
printf("Enter item price: ");
fscanf_s(fptr, "%f", &temp->invPrice);
return temp;
}
struct NODE* SearchList(struct NODE *start, int oldData)
{
struct NODE* current = start;
struct inventory * st = (struct inventory *)current->link->item.dataitem;
while (st->invPartNo != oldData && current != NULL)
{
current = current->link;
if(current->link)
st = (struct inventory *)current->link->item.dataitem;
}
return current;
}
void DeleteNode(struct NODE *start, int oldData)
{
struct NODE *current, *oldNode;
current = SearchList( start, oldData);
oldNode = current->link;
current->link = oldNode->link;
free(oldNode);
start->item.nodeCounter -= 1;
}
You can use fscanf() and fgets() to read the data as,
void readFromFile( )
{
stock array[20];
int i,j;
i=0;
fp = fopen("input.txt", "r");
if( fp != NULL ){
while ( !feof(fp ) ){
fgets(array[i].invName,sizeof array[i].invName,fp);
fscanf(fp,"%d %d %f %f ",&array[i].invPartNo,&array[i].invQOH,&array[i].invUnitCost,&array[i].invPrice);
i++;
}
}
The array[] will have the data and i will be number of struct data read.
Here all spaces in fscanf() are put to skip the [enter] character since the data is in different lines.
read about fscanf() with its format matching and fgets() it can help in reading files.
To avoid feof() can use,
while (fgets(array[i].invName,sizeof array[i].invName,fp)) {
fscanf(fp,"%d %d %f %f ",&array[i].invPartNo,&array[i].invQOH,&array[i].invUnitCost,&array[i].invPrice);
i++;
}
for This particular file format.
The algorithm:
Open the text file in 'text' 'read' mode.
Create an array of stock structures, if you know number of items beforehand, else use a linked list with each node of type stock.
To read data from file to corresponding field you can use fscanf .
When you think you have finished reading data, close the file.
Notes:
The file pointer is automatically incremented so you need not worry about incrementing it to read next set of data.
Do not forget to close the file.
To check whether the file handling functions are working fine, do check the return value of all the functions.
Important:
Since your invPartNo field in the file has integer data starting with 0, you may not want to read it as integer, otherwise it will be treated as "octal number" not a decimal number.
Your _tmain could look like below, this code assumes that the contents in the file are complete (i.e. contains the correct number of lines):
int _tmain(int argc, _TCHAR* argv[])
{ struct NODE *header = InitList();
if (argc > 1)
{ FILE *f;
if ((f = fopen(argv[1], "rt") == NULL)
{ printf(_T("Could not open file %s\n"), argv[1]);
return 1;
}
while (!feof(f))
Add2List(header, GetNode(f));
fclose(f);
}
else
{ int PCounter = 2;
while (PCounter--)
Add2List(header,GetNode(stdin));
}
DisplayList(header);
return 0;
}
EDIT:
Run the program from the command-prompt and pass the file name as a parameter
The processFilefunction scans the information from the file correctly to p, however the addNodeLast function doesn't add the information from p to the linked list employees because it crashes.
Can someone help me fix the crashing, so that it will link each node together?
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
void processFile(NODEPTR *employees, FILE *fp);
void outputPayFile(NODEPTR employees);
FILE *fp;
int main(void) {
NODEPTR employees;
if (fopen_s(&fp, "payfile2.txt", "r") != 0) {
printf("Failed to open payfile.txt for reading\n");
exit(0);
}
...missing code...
}
void processFile(NODEPTR *employees, FILE *fp) {
int i = 0;
NODEPTR p;
while(i < 5) {
printf("Entered Loop\n");
p = (NODEPTR) malloc(sizeof(node));
fscanf(fp, "%s %s %c %d %c %f\n", p->firstName, p->lastName, &(p->gender),
&(p->tenure), &(p->rate), &(p->rate), &(p->salary));
addNodeLast(employees, p);
i++;
}
}
In list.h:
void addNodeLast(NODEPTR *list, NODEPTR t) {
NODEPTR p;
if (*list == NULL)
*list = t;
else {
p = *list;
while (p->next)
p = p->next;
p->next = t;
}
}
Definition of NODEPTR:
typedef struct node {
char firstName[11];
char lastName[16];
char gender;
int tenure;
char rate;
float salary;
struct node *next;
} node, *NODEPTR;
You never initialise the next pointer. This is a common mistake. The call to malloc does not zero your memory. As a result, when you add a node to a non-empty list, you are likely to run straight off the end because the first node's next pointer could be non-null.
You need to at least do this:
p = malloc(sizeof(node));
if( p != NULL ) p->next = NULL;
You could consider using calloc, which does zero:
p = calloc(1, sizeof(node));