C Linked List from file not exiting after printing - c

So, I have to print a linked list from a file input, which I've managed to get working:
#include <stdio.h>
#include <stdlib.h>
typedef struct Vehicle{
int option;
char make [30];
char model[30];
int car_manufacture_date;
float maximum_velocity;
float mass;
int seats;
struct Vehicle *next;//linked list node
} vehicle_t;
int main (){
FILE* fp;
fp = fopen("vehicles.crash.txt", "r");
vehicle_t* first_car = malloc(sizeof(vehicle_t));
if (first_car == NULL){
printf("Error. Failed to allocate memory to first_car\n");
exit(1);
}
vehicle_t* current_vehicle = malloc(sizeof(vehicle_t));
if (current_vehicle == NULL){
printf("Error. Failed to allocate memory to current_vehicle\n");
exit(1);
}
vehicle_t* new_vehicle = malloc(sizeof(vehicle_t));
if (new_vehicle == NULL){
printf("Error. Failed to allocate memory to new_vehicle\n");
exit(1);
}
printf("GOOD1\n");
current_vehicle = first_car;
new_vehicle = first_car;
printf("GOOD2\n");
//Loading vehicles from file to linked list
if (fp != NULL)
{
printf("GOOD3\n");
while (fscanf(fp,"%d %s %s %d %f %f %d", &new_vehicle->option, new_vehicle->make, new_vehicle->model, &new_vehicle->car_manufacture_date,
&new_vehicle->maximum_velocity, &new_vehicle->mass, &new_vehicle->seats) != EOF)
{
printf("GOOD4\n");
current_vehicle->next = new_vehicle;
current_vehicle = current_vehicle->next;
new_vehicle = malloc(sizeof(vehicle_t));
if (first_car == NULL){
printf("Error. Failed to allocate memory\n");
new_vehicle->next=NULL;
exit(1);
}
printf("GOOD5\n");
}
close(fp);
printf("Input completed\n");
}
else
printf("Error! couldn't find file\n");
current_vehicle = first_car;
while (current_vehicle != NULL)
{
printf("Option: %d\tMake: %s\tModel: %s\tManufactured: %d\tMax Velocity: %.2f\tMass: %.2f\tSeats: %d\n",
current_vehicle->option, current_vehicle->make, current_vehicle->model, current_vehicle->car_manufacture_date,
current_vehicle->maximum_velocity, current_vehicle->mass, current_vehicle->seats);
new_vehicle = current_vehicle->next;
current_vehicle = current_vehicle->next;
};
printf("Printing completed");
return 0;
}
Everything works fine right until the last file item is printed out, after which the program crashes. From what I've seen in other posts, the while loop matches them all.
The printed "GOOD" statements are just checkpoints
The text in the file is formatted as: 1 Toyota Camry 2010 200.0 1100.0 5

I think you forget to set the ->next field of the last list node to NULL. You just called malloc, so the value could be anything random, making your printing failed.

The main reason for the infinite loop was failing to set the final next to NULL [as others have mentioned].
But, I think this is easier to see with the code simplified as yours, although mostly correct, was more complicated than it needed to be.
Anyway, this compiles but I didn't test it [please pardon the gratuitous style cleanup]:
#include <stdio.h>
#include <stdlib.h>
typedef struct Vehicle {
int option;
char make[30];
char model[30];
int car_manufacture_date;
float maximum_velocity;
float mass;
int seats;
struct Vehicle *next; // linked list node
} vehicle_t;
int
main()
{
FILE *fp;
fp = fopen("vehicles.crash.txt", "r");
if (fp == NULL) {
printf("Error! couldn't find file\n");
exit(1);
}
vehicle_t *first_car = NULL;
vehicle_t *previous_vehicle = NULL;
// Loading vehicles from file to linked list
while (1) {
vehicle_t *new_vehicle = malloc(sizeof(vehicle_t));
if (new_vehicle == NULL) {
printf("Error. Failed to allocate memory to new_vehicle\n");
exit(1);
}
// NOTE: the lack of this [in your equivalent code] was the reason
// for the infinite loop
new_vehicle->next = NULL;
if (fscanf(fp, "%d %s %s %d %f %f %d",
&new_vehicle->option, new_vehicle->make, new_vehicle->model,
&new_vehicle->car_manufacture_date, &new_vehicle->maximum_velocity,
&new_vehicle->mass, &new_vehicle->seats) == EOF) {
free(new_vehicle);
break;
}
if (first_car == NULL)
first_car = new_vehicle;
else
previous_vehicle->next = new_vehicle;
previous_vehicle = new_vehicle;
}
fclose(fp);
vehicle_t *current_vehicle = first_car;
while (current_vehicle != NULL) {
printf("Option: %d\tMake: %s\tModel: %s\tManufactured: %d\tMax Velocity: %.2f\tMass: %.2f\tSeats: %d\n",
current_vehicle->option, current_vehicle->make,
current_vehicle->model, current_vehicle->car_manufacture_date,
current_vehicle->maximum_velocity, current_vehicle->mass,
current_vehicle->seats);
current_vehicle = current_vehicle->next;
};
printf("Printing completed");
return 0;
}

Related

A function to read a text file and transfer that information to a dynamic vector

Create a function to read a text file and transfer their name to a dynamic vector of structures.
I'm reading the file but it doesn't appear nothing on the screen.
typedef struct aluno student;
struct aluno{
char name[50], address[50], number[9];
int year;enter code here
};
student *lerFicheiroTexto(char *nameFile, int *tam){
FILE *f1;
student buffer;
student *aux;
student *vetor = NULL;
f1 = fopen(nameFile, "rt");
if(f1 == NULL){
printf("Error opening the file text");
return NULL;
}
while(fscanf(f1, "%s %s %d %s", buffer.name, buffer.address, &buffer.year, buffer.number) == 3){
printf("%s\t%s\n%d\n%s\n", buffer.name, buffer.address, buffer.year, buffer.number);
aux = realloc(vetor, sizeof(student)*(*tam+1));
if(aux == NULL){
//realocation failled
printf("Reallocation failled. Maintain tam \n");
(*tam) = 0;
return NULL;
}
else{
vetor = aux;
vetor[(*tam)] = buffer;
}
(*tam)++;
}
fclose(f1);
return vetor;
}
I would need to have your input file to test this but I changed your code a bit.
I'm also a student so my apologies if I've done something wrong.
From what I see, I believe your code could be improved like so:
Definition of struct:
typedef struct aluno {
char name[50], address[50], number[9];
int year;
} Aluno;
Function to read the file and build your array:
Aluno* lerFicheiroTexto(char* nameFile, int tamanho)
{
FILE* file = fopen(nameFile, "r");
if (file == NULL) {
printf("Error opening the file text");
return NULL;
}
Aluno* listaAlunos = malloc(sizeof(Aluno));
char line[255];
while (fgets(line, 255, file) != NULL) {
Aluno currAluno;
sscanf(line, "%s %s %d %s", currAluno.name, currAluno.address, currAluno.year, currAluno.number);
listaAlunos[tamanho] = currAluno;
listaAlunos = realloc(listaAlunos, sizeof(Aluno) * ++tamanho);
}
fclose(file);
return listaAlunos;
}

Are there any differences in the implementation of file or list between OP , because my code worked on windows but not on Linux(Mac OS X)

My code works on a Windows PC but not on my Mac OS X. I m sure the code is correct, or at least this code works on windows.
My project is about a menu using structure and file ( adding point of interest , add a comment, printf info) and initially I implemented the binary file as function but then I re wrote them in the main to check if something changed
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//STRUCT WITH POI LIST
typedef struct {
char title[20];
char key[5];
} t_poi;
typedef struct _t_nodo_poi {
t_poi poi;
struct _t_nodo_poi *next;
}_t_nodo_poi;
typedef _t_nodo_poi* ptr_nodo_poi;
typedef struct{
ptr_nodo_poi head;
ptr_nodo_poi tail;
}t_lista_poi;
typedef t_lista_poi* lista_poi;
//Inizialization of list
lista_poi new_lista_poi() {
lista_poi new_list = malloc(sizeof (t_lista_poi));
new_list->head = NULL;
new_list->tail = NULL;
return new_list;
}
//READ POI
t_poi read_poi() {
t_poi poi;
printf("Title POI: \n");
scanf(" %[^\n]s\n", poi.title); //NO NUMERI E CARATTERI SPECIALI
printf("\nDescription POI: \n");
scanf(" %[^\n]s", poi.key);
return poi;
}
//INSERT POI IN THE LIST
int insert_poi(lista_poi _lista, t_poi _new_poi) {
ptr_nodo_poi new_node = (ptr_nodo_poi) malloc(sizeof (_t_nodo_poi));
if (new_node == NULL)
return 0;
new_node->poi = _new_poi;
new_node->next = NULL;
if ((_lista)->head == NULL) {
(_lista)->head = new_node;
(_lista)->tail = new_node;
} else {
(_lista)->tail->next = new_node;
(_lista)->tail = new_node;
}
return 1;
}
//SAVING FILE
void saving_file(lista_poi _lista, FILE * _file) {
ptr_nodo_poi ptr = _lista->head;
while(fwrite(&ptr->poi, sizeof(t_poi), 1, _file)) {
ptr = ptr->next;
printf("Check");
}
}
int main(int argc, const char * argv[]) {
int test,choice,check;
t_poi new_poi;
lista_poi _lista_poi;
_lista_poi = new_lista_poi();
FILE * file;
file= fopen("saving", "rb");
if (file == NULL) {
printf("Failed");
exit(1);
}else{
while (fread(&new_poi ,sizeof(t_poi),1, file)) {
insert_poi(_lista_poi,new_poi);
}
fclose(file);
}
do{
printf("Choice: ");
scanf("%d",&choice);
switch (choice) {
case 1:
printf("Insert new POI:");
new_poi = read_poi();
test = insert_poi(_lista_poi, new_poi);
if (test == 0)
printf("Error memory");
else
printf("Inserted succesfully");
break;
case 2:
printf("Saving on file\n");
if (_lista_poi->head != NULL) {
file = fopen("saving", "wb");
printf("\nCheck");
if (file==NULL) {
printf("\nFailed");
exit(1);
}else{
saving_file(_lista_poi, file);
fclose(file);
}
}else
printf("List empty!");
printf("EXIT FROM PROGRAM");
default:
break;
}
} while (choice != 2);
}
Right now it doesn't give me any error but it doesn't save anything either and when I had the loading and saving of file as function it gave me an Exception about allocated memory and it pointed me at line mentioned in the Code.
EDIT: I guess now you can copy/paste... and by the way this code on Xcode give me exit code 1 saying that the file is NULL
You're opening the file twice:
file= fopen("saving", "rb");
file = fopen("saving", "wb");
There are a few things you need to do:
Change the first to file = fopen("saving", "w+b");.
Remove the second fopen
Move the fclose down to the end of the program
Then your code should be fine.

how data can be read from a text file and stored as as a structure?

Let's call this file f1.txt and it has given attributes.
Student code
name
ID
and resident structure from another file let's call f2.txt will be read with the following attributes
ID
City
and residence will be asked from keyboard.
I tried to but gett stucked at some point
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student
{
int student_code;
char name[20];
char ID[20];
};
int main()
{
FILE *input_file;
struct student input;
input_file = fopen("f1.txt", "r");
if(input_file == NULL)
{
fprintf(stderr, "\nError!\n");
exit(1);
}
while(fread(&input, sizeof(struct student), 1, input_file))
printf("student code = %d name = %s ID = %s", input.student_code,
input.name, input.ID);
fclose(input_file);
return 0;
}
I'm new at C programming
for example f1.txt file will be in the following format
f1.txt
123456 yourname 987654
564566 test 454545
Use fscanf to read the lines because you know the format
Store the values into temporary variables
Copy them into a proper data structure: if you don't know the number of students use a dynamic array or a list.
EDIT:
Arrays allow random access, on the other hand lists only allow sequential access.
Here's my attempt using lists:
typedef struct student
{
int student_code;
char name[20];
char ID[20];
struct student* next;
}student_t;
typedef struct list_s
{
int size;
student_t* head;
student_t* tail;
} list_t;
void list_push_back(list_t* l, int code, char n[20], char id[20])
{
student_t* tmp = (student_t*)calloc(1,sizeof(*tmp));
tmp->student_code = code;
strncpy(tmp->name, n, 20);
strncpy(tmp->ID, id, 20);
if (l->head == NULL)
{
l->head = tmp;
l->tail = tmp;
l->size++;
return;
}
l->tail->next = tmp;
l->size++;
}
void list_print(list_t* l)
{
student_t* it = l->head;
while (it)
{
fprintf(stdout, "%d %s %s\n", it->student_code, it->name, it->ID);
it = it->next;
}
}
int main(int argc, char* argv[])
{
FILE *input_file;
struct student input;
input_file = fopen("f1.txt", "r");
if (input_file == NULL)
{
fprintf(stderr, "\nError!\n");
exit(1);
}
list_t* list = (list_t*)calloc(1,sizeof(*list));
char tmp_name[20];
char tmp_id[20];
int tmp_code = 0;
while (fscanf(input_file, "%d %s %s", &tmp_code, tmp_name, tmp_id) != EOF)
{
list_push_back(list, tmp_code, tmp_name, tmp_id);
}
fclose(input_file);
list_print(list);
return 0;
}
To read a single record into the structure input:
fscanf( input_file, "%d %s %s", &input.student_code, input.name, input.ID )
to read a integer and two strings into the relevant members.
fscanf() returns the number of formatted fields successfully assigned, so to display all records in the file in the manner your code attempts:
while( fscanf( input_file, "%d %s %s", &input.student_code,
input.name,
input.ID ) == 3 )
{
printf( "student code = %d, name = %s, ID = %s\n", input.student_code,
input.name,
input.ID ) ;
}

C dynamic array of structures, no errors, program terminates when ran

When ran, the program immediately terminates from an issue I believe to be associated with memory allocation. The main function only calls this function and another to delete the memory allocated
DrinkMachine *create(void){
FILE *inFile;
//Pointer to data structure
DrinkMachine *drinkMachine;
// Memory allocation
drinkMachine = calloc(1, sizeof(DrinkMachine));
if(drinkMachine == NULL) // Check success
return NULL;
// Open the input file for reading
inFile = fopen("drink_machine.txt" , "r");
if(!inFile){
puts("Error opening file");
return NULL;
}
// Read drink count from file
fscanf(inFile, "%d", &(drinkMachine->numItems));
printf("DEBUG read file arrayLen: %d\n", drinkMachine->numItems);
// Dynamically create array of drink item structures
drinkMachine->drinkItem = malloc(drinkMachine->numItems*sizeof(DrinkItem));
if(drinkMachine->drinkItem == NULL){
puts("ERROR: Failed to allocate memory");
return NULL;
}
// Put information from file into drinkItem structs
for(int i=0; i < drinkMachine->numItems; ++i){
fscanf(inFile, "%s %lf %d", (drinkMachine->drinkItem[i].name), &(drinkMachine->drinkItem[i].price), &(drinkMachine->drinkItem[i].drinkLeft));
printf("DEBUG drink %d is: %s %lf %d\n", i, (drinkMachine->drinkItem[i].name), (drinkMachine->drinkItem[i].price), (drinkMachine->drinkItem[i].drinkLeft));
}
// Close inFile
fclose(inFile);
// Force output to screen
puts("DEBUG readFile Success!");
fflush(stdout);
return drinkMachine;
}
The program ran into errors or wouldn't properly allocate memory and would successfully output the error message when ran, until I put in the line:
drinkMachine->drinkItem = malloc(drinkMachine->numItems*sizeof(DrinkItem));
At this point the program compiles without warning or errors, but terminates immediately when ran without any output. In case it helps, here are the structures:
typedef struct _DrinkItem{
int id;
char *name;
double price;
int drinkLeft;
int drinkSold;
} DrinkItem;
typedef struct _DrinkMachine{
int version;
int numItems;
int drinkLocation;
DrinkItem *drinkItem;
} DrinkMachine;
You have to allocate storage for each name too. You are reading characters into an unallocated pointer on line 30. You should read the name into a temporary array, get the name’s length, allocate (length+1) bytes of storage to name, and strncpy the data over.
You didn't allocate name space, you didn't handle any input error, you use int without verify that it not negative for a size, you didn't use stderr for error, you used reserved identifier and more.
Here a proposition of code, that I think fix all your errors (didn't test it as you didn't give example of input and output):
#include <stdio.h>
#include <stdlib.h>
typedef struct DrinkItem {
int id;
char *name;
double price;
int drinkLeft;
int drinkSold;
} DrinkItem;
typedef struct DrinkItem {
int version;
size_t numItems;
int drinkLocation;
DrinkItem *drinkItems;
} DrinkMachine;
static void helper_free(DrinkItem *drinkItems, size_t n) {
for (size_t i = 0; i < n; i++) {
free(drinkItems[i].name);
}
free(drinkItems);
}
DrinkMachine *create(char const *path) {
FILE *inFile = fopen(path, "r");
if (!inFile) {
fprintf(stderr, "Error opening file");
return NULL;
}
size_t numItems;
if (fscanf(inFile, "%zu", &numItems) != 1) {
fprintf(stderr, "Error parsing\n");
return NULL;
}
#ifndef NDEBUG
printf("DEBUG read file arrayLen: %zu\n", numItems);
#endif
DrinkItem *drinkItems = malloc(numItems * sizeof *drinkItems);
if (!drinkItems) {
fprintf(stderr, "ERROR: Failed to allocate memory");
return NULL;
}
for (size_t i = 0; i < numItems; ++i) {
char *name = malloc(100);
if (!name) {
helper_free(drinkItems, i);
fprintf(stderr, "ERROR: Failed to allocate memory");
return NULL;
}
double price;
int drinkLeft;
if (fscanf(inFile, "%99s %lf %d", name, &price, &drinkLeft) != 3) {
free(name);
helper_free(drinkItems, i);
fprintf(stderr, "Error parsing\n");
return NULL;
}
drinkItems[i] =
(DrinkItem){.name = name, .price = price, .drinkLeft = drinkLeft};
#ifndef NDEBUG
printf("DEBUG drink %zu is: %s %lf %d\n", i, name, price, drinkLeft);
#endif
}
fclose(inFile);
DrinkMachine *drinkMachine = malloc(sizeof *drinkMachine);
if (!drinkMachine) {
helper_free(drinkItems, numItems);
fprintf(stderr, "ERROR: Failed to allocate memory");
return NULL;
}
*drinkMachine =
(DrinkMachine){.drinkItems = drinkItems, .numItems = numItems};
#ifndef NDEBUG
puts("DEBUG readFile Success!\n");
#endif
return drinkMachine;
}

Reading text into a linked list using structs in C

I'm attempting to create a linked list using a struct from a txt file. Initially, I'm testing it with a txt file with only one line of information. This code compiles correctly, however when I run it, it returns "Line...didn't scan properly". As an aside, if I remove the if statement that returns such a value I get complete gibberish. I have no clue why the line isn't being scanned correctly, however I feel as though it may having something to do with the hyphen/plus sign in two of the terms that I tried to scan as strings. Thank you very much for any help you can provide.
This is the txt file:
1 20959U 90103A 14091.58762725 -.00000015 00000-0 00000+0 0 3197
This is the tester.c file:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct noradData {
// line one
int lineNum;
char * satNum;
char * intDesig;
float epoch;
float firstTimeDeriv;
char * secondTimeDeriv;
char * drag;
int zero;
int set;
struct noradData * next;
} Data;
Data * first = NULL, * last = NULL;
int main() {
char line[80], secondTimeDeriv[7], drag[7], satNum[6], intDesig[6];
int lineNum, zero, set;
float epoch, firstTimeDeriv;
FILE * fIn;
Data * node;
fIn = fopen("data1.txt", "r");
if (fIn == NULL) {
printf("Cannot open file\n");
return 1;
}
while (fgets(line, sizeof(line), fIn) != NULL) {
// Check line for various problems (too short, too long).
if (line[0] == '\0') {
printf ("Line too short\n");
return 1;
}
if (line[strlen (line)-1] != '\n') {
printf ("Line starting with '%s' is too long\n", line);
return 1;
}
line[strlen (line)-1] = '\0';
// Scan the individual fields.
if (scanf("%d %s %s %f %f %s %s %d %d", &lineNum, satNum, intDesig,
&epoch, &firstTimeDeriv, secondTimeDeriv, drag, &zero, &set)
!= 9) {
printf ("Line '%s' didn't scan properly\n", line);
return 1;
}
node = malloc(sizeof(Data));
if (node == NULL) {
printf ("Ran out of memory\n");
return 1;
}
node->lineNum = lineNum;
node->satNum = strdup(satNum);
node->intDesig = strdup (intDesig);
node->epoch = epoch;
node->firstTimeDeriv = firstTimeDeriv;
node->secondTimeDeriv = strdup(secondTimeDeriv);
node->drag = strdup(drag);
node->zero = zero;
node->set = set;
node->next = NULL;
if (first != NULL) {
last->next = node;
last = node;
}
else {
first = node;
last = node;
}
}
fclose (fIn);
node = first;
while (node != NULL) {
printf("%d %s %s %f %f %s %s %d %d", node->lineNum, node->satNum,
node->intDesig, node->epoch, node->firstTimeDeriv,
node->secondTimeDeriv, node->drag, node->zero, node->set);
node = node->next;
}
return 0;
}
First of all change size of character arrays satnum and intdDesig to 7
that is satnum[7] and intDesig[7]. You want to store 6 characters in these leave last index for null value.
if (line[strlen (line)-1] != '\n') {
printf ("Line starting with '%s' is too long\n", line);
return 1;
}
This if statement instead of line[strlen(line)-1]!='\n' put this-
line[strlen(line)-1]=='\n'
and statement goes like this
if (line[strlen (line)-1]=='\n') {
printf ("Line starting with '%s' is too long\n", line);
return 1;
}
And remove this line
line[strlen (line)-1] = '\0';
Then line will not be returned twice .

Resources