I'm still fairly new to C programming and I'm having some trouble.
I've written some code to read a file that has information on people's names, ages, weight, and heights. Each new line in the file represents a new person. This information is then stored in a struct, and this struct is then added to a linked list. Essentially I am trying to use this linked list as a queue, with each node being a struct.
This is what the file I am reading will look like: (the format is age, weight, height, name).
20,60,170,Joe
23,70,175,Mike
My issue is that for some reason, every node in the linked list is the exact same, which is the last line of the file text. So for example every time I create a struct and add it to the linked list, each node will have the name 'Mike', age '23', and so forth. I've played around with the code and I notice that there is no issue with the file reading, and the values assigned to the struct members are correct (I printed out the values to check). However when I view the top of the Linked List, then dequeue (remove top), then view the top again, the values are always the same. So I am not sure where my problem is.
Note: I wrote a generic linked list code, and there is no issue with the linked list itself as I have tested it extensively.
This is my code:
#include <stdio.h>
#include "macros.h"
#include <string.h>
typedef struct
{
int AGE;
int WEIGHT;
int HEIGHT;
char NAME[51];
}Person;
int main()
{
void* vdPtr;
Person* topVal;
Person person;
LinkedList* list = createLinkedList();
char line[100];
int i=0;
int numPeople=0;
FILE* fp;
int age, weight, height;
char name[51];
fp = fopen("text.txt","r");
while(fgets(line,100,fp) != NULL)/*reading file to see how many lines, and how many people*/
{
numPeople++;
}
rewind(fp);
while (i<numPeople)/*storing file data in the appropriate member for Person struct*/
{
fscanf(fp,"%d,%d,%d,%s",&age,&weight,&height,name);
person.AGE = age;
person.WEIGHT = weight;
person.HEIGHT = height;
strcpy(person.NAME,name);
insertLast(list,&person);
/*printing to see whether the values added to struct members are correct*/
printf("%d %d %d %s\n",person.AGE,person.WEIGHT,person.HEIGHT,person.NAME);
i++;
}
/*testing*/
printf("\nCount %d",getLinkedListCount(list));/*seeing how many nodes in the linkedList*/
/*using void pointer to get the top value, then typecasting it to Person pointer*/
vdPtr = viewTop(list);
topVal = (Person*)(vdPtr);
/*viewing the top person*/
printf("\ntop is %s %d",topVal->NAME,topVal->AGE);
/*deqeue*/
removeTop(list);
printf("\nCount %d",getLinkedListCount(list));
vdPtr = viewTop(list);
topVal = (Person*)(vdPtr);
printf("\ntop is %s %d",topVal->NAME,topVal->AGE);
}
Can anyone tell me where I went wrong and what to do to fix it?
You are continually adding the same pointer to the list. On every new line you overwrite the same variable. So in the end you have one big list of pointers all pointing to the same thing. You have to make a new person struct for every person like this:
#include <stdio.h>
#include "macros.h"
#include <string.h>
typedef struct
{
int AGE;
int WEIGHT;
int HEIGHT;
char NAME[51];
}Person;
int main()
{
void* vdPtr;
Person* topVal;
LinkedList* list = createLinkedList();
char line[100];
int i=0;
int numPeople=0;
FILE* fp;
int age, weight, height;
char name[51];
fp = fopen("text.txt","r");
while(fgets(line,100,fp) != NULL)/*reading file to see how many lines, and how many people*/
{
numPeople++;
}
rewind(fp);
while (i<numPeople)/*storing file data in the appropriate member for Person struct*/
{
Person *person = (Person *)malloc(sizeof(Person)); //make new person object
fscanf(fp,"%d,%d,%d,%s",&age,&weight,&height,name);
person->AGE = age;
person->WEIGHT = weight;
person->HEIGHT = height;
strcpy(person->NAME, name);
insertLast(list, person);
/*printing to see whether the values added to struct members are correct*/
printf("%d %d %d %s\n",person.AGE,person.WEIGHT,person.HEIGHT,person.NAME);
i++;
}
/*testing*/
printf("\nCount %d",getLinkedListCount(list));/*seeing how many nodes in the linkedList*/
/*using void pointer to get the top value, then typecasting it to Person pointer*/
vdPtr = viewTop(list);
topVal = (Person*)(vdPtr);
/*viewing the top person*/
printf("\ntop is %s %d",topVal->NAME,topVal->AGE);
/*deqeue*/
removeTop(list);
printf("\nCount %d",getLinkedListCount(list));
vdPtr = viewTop(list);
topVal = (Person*)(vdPtr);
printf("\ntop is %s %d",topVal->NAME,topVal->AGE);
}
I recommend reading up on how pointers, and memory management work. Also keep in mind that this code does not free the memory it allocates, which is something you still need to do.
Without seeing code for insertLast() it is difficult too answer but it may be that you would create a new struct for each person and then pass it to insertLast :
Person* newPerson;
while (i<numPeople)/*storing file data in the appropriate member for Person struct*/
{
newPerson = (Person *)malloc(sizeof(Person))
fscanf(fp,"%d,%d,%d,%s",&age,&weight,&height,name);
newPerson->AGE = age;
newPerson->WEIGHT = weight;
newPerson->HEIGHT = height;
strcpy(newPerson.NAME,name);
insertLast(list,newPerson);
...
The list seems to save only the address of the data, that why you need to create new data for each person.
A struct that is to be used in a linked list needs to be self referential. i.e. one of the members (typically the last one) is a pointer to the struct itself. This is what allows segments of data to be linked together . (other members can be thought of as the payload, or data.) For example, your struct:
typedef struct
{
int AGE;
int WEIGHT;
int HEIGHT;
char NAME[51];
}Person;
Can be refactored for example as:
struct Person
{
int AGE;
int WEIGHT;
int HEIGHT;
char NAME[51];
struct Person *node;
};
Look at this simple starter tutorial for creating and using linked lists. (Click the C tab for example code.)
struct Total
{
char Name[40];
int No[40];
};
struct Total *List = NULL;
So let's say my content of txt is "Test;12345" I want to store Test into Name and 12345 into No.
fscanf(fptr, "%[^;], %d", List [0].Name, List [0].No);
I did it this way, it reads the first line correctly but for some reason it doesn't read the number.
Here is what I do:
I count the number of file inside a folder, get data from this file inside a array of struct.
I want to malloc this array of struct, since I do not know the exact number of file before strating the program.
Here is my code:
struct get_data{
int sequence;
int mask_ID;
char *name;
float intensity;
float angle_correction;
double points[10000];
float X_interval;
};
struct get_data all_data[number_of_file];
Consider I get number_of_file before somewhere in the program.
I want to know how to malloc the struct all_data. I search but got lost at some point. Any help would be welcomed. Thank you.
Mel.
I suggest you give a fixed length to the name variable inside the structure or else you would have to malloc that for each structure. The declaration could look like this:
struct get_data
{
int sequence;
int mask_ID;
char name[256];
float intensity;
float angle_correction;
double points[10000];
float X_interval;
};
Then, you may malloc an array of structures using the following code:
struct get_data *all_data;
all_data = malloc(number_of_files * sizeof(struct get_data));
if (all_data == NULL)
{
printf("Malloc failed!\n);
return -1;
}
/* now you can access each file structure using a for instruction */
int i;
for (i = 0; i < number_of_files; i++)
{
all_data[i].sequence = ...;
/* etc. */
}
I have the following code:
if (strcmp(method, "print") == 0){
for (i = 0; i < hashtable->M; i++){
fprintf(fout,"[%d] :", i);
if (hashtable->v[i] != NULL)
while(hashtable->v[i]){
fprintf(fout," ");
((Pair*)hashtable->v[i]->info)->fp(hashtable->v[i], fout);
hashtable->v[i] = hashtable->v[i]->urm;
}
fprintf(fout,"\n");
}
}
In my code, when I encounter a "print" from the file, I have to print out the values stored in my hashtable. M is the size of the hashtable, while v is a void* which points to a linked list. It's all good but if I have to add some values in the hashtable and then print them, after printing I lose all the previously stored values. I think this might have to do with the fact that I'm doing this: hashtable->v[i] = hashtable->v[i]->urm; but even so, I don't know how to recover the values. I was thinking about something as an auxiliary pointer to the hashtable, but that failed for me. Note, the structures are as follow
typedef struct celulag {
void *info;
struct celulag *urm;
} TCelulaG, *TLG, **ALG;
typedef unsigned int (*TFHash)(const void*, size_t M, size_t range);
/* structura tabela Hash */
typedef struct {
size_t M;
TFHash fh;
TLG *v;
} TH;
typedef void (*TPrint)(TLG l, FILE *g);
typedef struct {
void *key;
void *value;
TPrint fp;
int frequency;
} Pair;
Note that this is done in a while so the assignment would look as this:
Add 3 values, print, add another 4 values, print. After adding the first 3 values, if I prind, it's all good, after adding the next 4 values, if I print, only the last 4 values appear.
Can anyone help? Thank you very much.
I am trying to read from a file and save the data into an array of struct. However I am at loss on how do I go about it.
The struct is like this
struct Student students {
int stuid;
char name[21];
double grade;
}
The text file is something like this
1,76.50,Joe Smith
2,66.77,John Campbell
3,88.99,Jane Common
The code I tried ended up something like this
//declaring the struct
struct Student test[3];
int loadgrade(struct Student* student, FILE* file) {
while (fscanf(file, "%d,%lf,%21[^\n]", &student.stuid, &student.grade, &student.name) == 3)
I am not sure how I would save the data into the array, as the way I have it will only save to the first element and never go on. Do I loop inside the while statement of reading the file?
Do I make another struct or temp variable to read the file and then loop it to transfer it? I am at a loss on this and would appreciate any kind of enlightenment.
int loadgrade(struct Student* student, FILE* file) {
int i = 0;
while (fscanf(file, "%d,%lf,%20[^\n]", &student->stuid, &student->grade, student->name) == 3){
++student;
++i;
}
return i;
}
call int n = loadgrade(test, fp);
So this is somewhat confusing because student is a pointer, but the way to do this is as such
fscanf(file, "%d,%lf,%20[^\n]", &(student->stuid), &(student->grade), student->name);
Now if you want to fill the array test, you can do this
for (int i = 0; i < 3; i++)
fscanf(file, "%d,%lf,%20[^\n]", &(test[i]->stuid), &(test[i]->grade), test[i]->name);
Having said that, you need to declare test like this struct Student * test[3].