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.
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'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;
}
As my current function stands I can only read the first set of data from a file. I am sure that it is because of the !feof not functioning the way I want it to but it might also be caused by a bad print list function but I am not to sure. I am pretty much brand new to using dynamic memory so bear with me.
Load from File
void load(FILE *file, Node *head)
{
char tempArtist[30] = {'\0'}, tempAlbum[30] = {'\0'}, tempTitle[30] = {'\0'}, tempGenre[30] = {'\0'}, tempSpace = '\0';
SongLength *tempLength = NULL;
char tempPlay[100] = {'\0'}, tempRating[6] = {'\0'}, tempMins[3] = {'\0'}, tempSecs[3] = {'\0'};
tempLength = (SongLength *)malloc(sizeof(SongLength));
while (!feof(file))
{
while (head->pNext == NULL) // Here is where I need to shift to the next node
{
fscanf(file, "%s", &tempArtist);
fscanf(file, "%c", &tempSpace);
strcpy(tempLength->mins, tempMins);
strcpy(tempLength->secs, tempSecs);
strcpy(head->data->artist, tempArtist);
strcpy(head->data->length->mins, tempLength->mins);
strcpy(head->data->length->secs, tempLength->secs);
insertNode(head, head->data);
}
}
free(tempLength);
}
Insert to linked list
void insertNode(Node *head, Record *data)
{
while(head->pNext == NULL)
{
head=head->pNext;
}
head->pNext=(Node*)malloc(sizeof(Node));
head->pNext->data = (Record*)malloc(sizeof(Record));
head->pNext->data->length=(SongLength*)malloc(sizeof(SongLength));
(head->pNext)->pPrev=head;
head=head->pNext;
head->data=data;
head->pNext=NULL;
}
Print all of the data in the list(hopefully)
void display (Node *head)
{
while (head->pNext != NULL)
{
printf ("Artist: %s\n", head->data->artist);
printf ("Length(mm:ss) %s:%s\n", head->data->length->mins,head->data->length->secs);
head=head->pNext;
}
putchar ('\n');
}
I have removed all but one of the fscanf()'s and printf()'s to cut down the code.
Structs
typedef struct songlength
{
char mins[3];
char secs[3];
}SongLength;
typedef struct record
{
char artist[30];
struct songlength *length;
}Record;
typedef struct node
{
struct node *pPrev;
struct record *data;
struct node *pNext;
}Node;
the function call insertNode(head,head->data); looks strange. The second argument have to be data not from the head, otherwise data in head is rewritten for any new record.
So allocate memory for Record inside load function and do not use head->data.
The problem is somewhere in here....
char buffer[80];
char *name;
while (1) {
fgets(buffer, 80, inf); //reads in at most 80 char from a line
if (feof(inf)) //this checks to see if the special EOF was read
break; //if so, break out of while and continue with your main
name = (char *) malloc(sizeof(char)*20);
....
name = strtok(buffer, " ");//get first token up to space
stock = newStock(name,...)
....
}
I'm working in C with generic linked lists. I made a list implementation that I've tested and know works with chars. I'm trying to add stocks (I created a stock struct) to the linked list, with each node of the linked list holding a stock struct, but when I finish reading in the stocks all of the nodes point to the same struct and I can't figure out why. Here's some snippets of my code
list *list = malloc(sizeof(list));
newList(list, sizeof(stock_t));
while(1) {
...
(read from file)
...
stock_t *stock;
stock = newStock(name, closes, opens, numshares, getPriceF, getTotalDollarAmountF,getPercentChangeF,toStringF);
addToBack(list, stock);
}
Here's the newStock function:
stock_t *newStock(char *name, float closingSharePrice, float openingSharePrice, int numberOfShares, getPrice getP, getTotalDollarAmount getTotal, getPercentChange getPercent, toString toStr) {
stock_t *stock = malloc(sizeof(stock));
stock->stockSymbol = name;
stock->closingSharePrice = closingSharePrice;
stock->openingSharePrice = openingSharePrice;
stock->numberOfShares = numberOfShares;
stock->getP = getP;
stock->getTotal = getTotal;
stock->getPercent = getPercent;
stock->toStr = toStr;
return stock;
}
In a way I see what's wrong. newStock returns a new pointer every time, but it always gets stored in the variable 'stock' which is what every node points to, so it's going to be equal to whatever the last pointer newStock returned was...but I don't see the way around this. I tried having newStock return just a stock_t, and doing addToBack(list, &stock), but that didn't solve the problem either.
Any help would be appreciated!
Here is some code from the list:
typedef struct node {
void *data;
struct node *next;
}node_t;
typedef struct {
int length;
int elementSize;
node_t *head;
node_t *tail;
} list;
void newList(list *list, int elementSize) {
assert(elementSize > 0);
list->length = 0;
list->elementSize = elementSize;
list->head = list->tail = NULL;
}
void addToBack(list *list, void *element) {
node_t *node = malloc(sizeof(node_t));
node->data = malloc(list->elementSize);
node->next = NULL; //back node
memcpy(node->data, element, list->elementSize);
if (list->length == 0) { //if first node added
list->head = list->tail = node;
}
else {
list->tail->next = node;
list->tail = node;
}
list->length++;
}
Here's code from the stock struct:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef float (*getPrice)(void *S);
typedef float (*getTotalDollarAmount)(void *S);
typedef float (*getPercentChange)(void *S);
typedef char *(*toString)(void *S);
typedef struct stock{
char *stockSymbol;
float closingSharePrice;
float openingSharePrice;
int numberOfShares;
getPrice getP;
getTotalDollarAmount getTotal;
getPercentChange getPercent;
toString toStr;
}stock_t;
The generic functions probably seem like overkill but this is for homework (if you couldn't tell already) so we were asked to specifically use them. I don't think that has anything to do with the problem though.
Here are the definitions for those functions anyway
float getPriceF(void *S) {
stock_t *stock = (stock_t*)S;
return stock->closingSharePrice;
}
float getTotalDollarAmountF(void *S) {
stock_t *stock = (stock_t*)S;
return ((stock->closingSharePrice) * (stock->numberOfShares));
}
float getPercentChangeF(void *S) {
stock_t *stock = (stock_t*)S;
return ((stock->closingSharePrice - stock->openingSharePrice)/(stock->openingSharePrice));
}
char *toStringF(void *S) {
stock_t* stock = (stock_t*)S;
char *name = malloc(20*sizeof(char));
//sprintf(name, "Symbol is: %s. ", (stock->stockSymbol));
return stock->stockSymbol;
}
void printStock(void *S) {
char *str = toStringF(S);
printf("%s \n", str);
}
And this is how I'm traversing the list:
typedef void (*iterate)(void *); //this is in the list.h file, just putting it here to avoid confusion
void traverse(list *list, iterate iterator) {
assert(iterator != NULL);
node_t *current = list->head;
while (current != NULL) {
iterator(current->data);
current = current->next;
}
}
And then in my main I just called
traverse(list, printStock);
I can't find any problems with your code (that would cause your problem, anyway - there are places where you don't check the return from malloc() and stuff like that, but those are not relevant to this question). You don't supply the definition of stock_t, so I made a new data struct, and a new couple of functions, otherwise I just copied and pasted the code you provided:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* Your code starts here */
typedef struct node {
void *data;
struct node *next;
}node_t;
typedef struct {
int length;
int elementSize;
node_t *head;
node_t *tail;
} list;
void newList(list *list, int elementSize) {
assert(elementSize > 0);
list->length = 0;
list->elementSize = elementSize;
list->head = list->tail = NULL;
}
void addToBack(list *list, void *element) {
node_t *node = malloc(sizeof(node_t));
node->data = malloc(list->elementSize);
node->next = NULL; //back node
memcpy(node->data, element, list->elementSize);
if (list->length == 0) { //if first node added
list->head = list->tail = node;
}
else {
list->tail->next = node;
list->tail = node;
}
list->length++;
}
/* Your code ends here */
/* I made a new struct, rather than stock, since you didn't supply it */
struct mydata {
int num1;
int num2;
};
/* I use this instead of newStock(), but it works the same way */
struct mydata * newNode(const int a, const int b) {
struct mydata * newdata = malloc(sizeof *newdata);
if ( newdata == NULL ) {
fputs("Error allocating memory", stderr);
exit(EXIT_FAILURE);
}
newdata->num1 = a;
newdata->num2 = b;
return newdata;
}
/* I added this function to check the list is good */
void printList(list * list) {
struct node * node = list->head;
int n = 1;
while ( node ) {
struct mydata * data = node->data;
printf("%d: %d %d\n", n++, data->num1, data->num2);
node = node->next;
}
}
/* Main function */
int main(void) {
list *list = malloc(sizeof(list));
newList(list, sizeof(struct mydata));
struct mydata * data;
data = newNode(1, 2);
addToBack(list, data);
data = newNode(3, 4);
addToBack(list, data);
data = newNode(5, 6);
addToBack(list, data);
printList(list);
return 0;
}
which outputs this:
paul#MacBook:~/Documents/src$ ./list
1: 1 2
2: 3 4
3: 5 6
paul#MacBook:~/Documents/src$
demonstrating that you have a 3 node list, with all nodes different and where you'd expect them to be.
Either there is some other problem in code you're not showing, or for some reason you are thinking each node points to the same struct when it actually doesn't.
One possibility is that you have a char * data member in your stock struct. It's impossible to tell from the code you provided, but it's possible that you really are creating different nodes, but they all end up pointing to the same name, so they just look like they're the same. If you're assigning a pointer to name, you should make sure it's freshly allocated memory each time, and that you're not just, for instance, strcpy()ing into the same memory and assigning the same address to each stock struct.
EDIT: Looks like that was your problem. This:
name = (char *) malloc(sizeof(char)*20);
....
name = strtok(buffer, " ");
should be:
name = (char *) malloc(sizeof(char)*20);
....
strcpy(name, strtok(buffer, " "));
Right now, you malloc() new memory and store a reference to it in name, but then you lose that reference and your memory when you overwrite it with the address returned from strtok(). Instead, you need to copy that token into your newly allocated memory, as shown.
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));