Related
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.)
I am working on a program to store data from a text file within a structure. The goal is to perform the file processing completely within the function outside of the main. The function opens and closes the file, and when it is called by the main function it is to populate the particular structure array element is supposed to be performed upon. The test file I am using is just a text file containing 3 lines:
Gates M 60
Jobs M 55
Jane F 45
These should be populated into an array of structures when called by the function. However, when I call the function it only populates the same first line to all array elements, I believe because the file pointer resets everytime I call the function. How can I remedy this? My code is below!
#include <stdio.h>
struct Individual
{
char LastName[30];
char gender;
unsigned int age;
};
int function(struct Individual *person)
{
FILE *cfPtr;
char holder[100];
cfPtr = fopen("C:\\Users\\Nick\\Desktop\\myfile","r");
fscanf(cfPtr, "%10s %c %3d", &person->LastName, &person->gender, &person->age);
fclose(cfPtr);
}
int main(void)
{
struct Individual person[3];
function(&person[0]);
function(&person[1]);
printf("%s %c %d", person[0].LastName, person[0].gender, person[0].age);
printf("%s %c %d", person[1].LastName, person[1].gender, person[1].age);
return 0;
}
FILE already tracks position for you; you don't need to do it yourself. The problem is that you keep re-opening the file, which resets the location back to the beginning of the file each time.
Open it once, read multiple times, then close it. Make your function take a FILE * parameter.
#include <stdio.h>
struct Individual
{
char LastName[30];
char gender;
unsigned int age;
};
int function(FILE *cfPtr, struct Individual *person)
{
fscanf(cfPtr, "%10s %c %3d", &person->LastName, &person->gender, &person->age);
// TODO: Check for failure
// TODO: Return appropriate value
}
int main(void)
{
struct Individual person[3];
FILE *cfPtr;
cfPtr = fopen("C:\\Users\\Nick\\Desktop\\myfile","r");
// TODO: Check for failure
function(cfPtr, &person[0]);
function(cfPtr, &person[1]);
fclose(cfPtr);
printf("%s %c %d", person[0].LastName, person[0].gender, person[0].age);
printf("%s %c %d", person[1].LastName, person[1].gender, person[1].age);
return 0;
}
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].
I have a file and i need to read data from it. I have to read 2 int and 1 c string.
This is my struct
typedef struct seats
{
int number, reserved;
char * name;
} seats;
This is my main
FILE *data;
seats input;
data = fopen("data.txt", "r+");
while(fscanf(data,"%s %d %d", input.name, &input.number, &input.reserved) != EOF)
{
printf("%s %d %d", input.name, input.number, input.reserved);
}
Every time when i compile and run this software it crashes for some reason. Is there any solution?
You haven't assigned any value to input.name, but you pass its garbage value to fscanf. You need to assign a variable a value before you attempt to use that value.
Change your struct to something like this:
typedef struct seats{
int number, reserved;
char name[1000];
} seats;
and put a fflush(stdin), after printf(...)
I'm a new programmer and I am having some troubles writing a linked list to a text file.
Here's my code:
typedef struct N {
int code;
char name[MAX1];
int items;
float price;
struct N *next;
} node_t;
typedef struct {
int code;
char name[MAX1];
int items;
float price;
} product;
product p;
product *ptr = &p;
node_t *iterator = head;
FILE *fp;
fp = fopen("newfile.txt", "w+");
while (iterator != NULL) {
p.code = iterator->code;
strcpy(p.name, iterator->name);
p.items = iterator->items;
p.price = iterator->price;
fwrite(ptr, 1, sizeof(product),fp);
iterator = iterator->next;
}
at this point, I read from stream and display what I should have written on "newfile.txt", but all it prints out is '0' where there should be an integer/float and nothing where there should be a string.
I've also tried writing to the file a simple integer with fputs() and other functions, but it printed out random numbers.
In case you are wondering, since I haven't copied the whole code here, the list is NOT empty and I can display correctly all of the items in it.
I'm sorry if I haven't been clear, but this is my first post here. Hope someone can help me, thank you!
I would suggest the following changes:
Divide the struct for each node into two structs - one for holding the data and one for capturing the next pointer.
typedef struct
{
int code;
char name[MAX1];
int items;
float price;
} NodeData;
typedef struct N {
NodeData data;
struct N *next;
} node_t;
Now the function to write the contents of a linked list can be:
fp = fopen("newfile.txt", "w+");
// Get the size of the linked list and write as the first piece of data.
size_t listSize = getLinkedListSize(head)
fwrite(&listSize, 1, sizeof(size_t), fp);
// Now write each node of the linked list.
while (iterator != NULL) {
fwrite(&(iterator->data), 1, sizeof(iterator->data), fp);
iterator = iterator->next;
}
fwrite just writes the binary representation of the data, rather than an ASCII representation as you might expect to see in a text file. An integer, for instance, will be represented by four NUL characters, which you won't be able to see. So your code might well be working.
If you want to write something out as text, use fprintf, e.g.:
fprintf(fp, "%d,%d,%lf,\"%s\"\n",
iterator->code, iterator->items, iterator->price, iterator->name);
would be a rough approximation of CSV (note it doesn't escape characters inside the name).
By the way, why not just make add a member variable of node_t which is a product? Then you can avoid all that copying about.