Unexpected behaviour of fread() reading from binary file - c

This program basically creates a list of flights with all their infos (read by the fread() function from a ListaVoli.bin).
The list is made up mainly by nodes and each node contains a flight.
#include <stdio.h>
#include <stdlib.h>
#define FILE_NAME "/Users/Matt/Downloads/ListaVoli.bin"
struct flight {
int flightCode;
char destination[3];
int scheduledDepHour;
int scheduledDepMinute;
int realDepHour;
int realDepMinute;
int passengers;
};
struct node {
struct flight volo;
struct node *next;
};
struct node *addToList(struct node *list, struct flight voloIn) {
struct node *newNode;
newNode = malloc(sizeof(struct node));
if (newNode == NULL) {
printf("Error: malloc failed\n");
exit(EXIT_FAILURE);
}
newNode -> volo = voloIn;
newNode -> next = list;
return newNode;
}
void printList(struct node *list) {
for (; list != NULL; list = list -> next) {
printf("Code:%d\nDestination:%s\nDeparture:%d-%d\nReal:%d-%d\nPassengers:%d\n\n\n",
list -> volo.flightCode,
list -> volo.destination,
list -> volo.scheduledDepHour,
list -> volo.scheduledDepMinute,
list -> volo.realDepHour,
list -> volo.realDepMinute,
list -> volo.passengers
);
}
}
void decolla(struct node *list, int flightCode, int realDepHour, int realDepMinute) {
for (; list != NULL; list = list -> next) {
if (flightCode == (list -> volo.flightCode)) { /*
printf("Inserisci ora di partenza per il volo %d: ", flightCode);
scanf("%d", &(list -> volo.realDepHour));
printf("Inserisci minuto di partenza: ");
scanf("%d", &(list -> volo.realDepMinute)); */
list -> volo.realDepHour = realDepHour;
list -> volo.realDepMinute = realDepMinute;
}
}
}
void delay(struct node *list) {
for (; list != NULL; list = list -> next) {
if ((list -> volo.realDepHour) - (list -> volo.scheduledDepHour) == 0) {
if ((list -> volo.realDepMinute) - (list -> volo.scheduledDepMinute) > 5 && (list -> volo.realDepMinute) - (list -> volo.scheduledDepMinute) < 30) {
printf("Il volo %d ha più di 5 minuti di ritardo\n", list -> volo.flightCode);
continue;
}
if ((list -> volo.realDepMinute) - (list -> volo.scheduledDepMinute) > 30) {
printf("Il volo %d ha più di 30 minuti di ritardo\n", list -> volo.flightCode);
continue;
}
} else
printf("Il volo %d ha più di 30 minuti di ritardo\n", list -> volo.flightCode);
}
}
void passengersCount(struct node *list) {
for (; list != NULL; list = list -> next) {
if (list -> volo.passengers > 200) {
printf("Il volo %d ha più di 200 passeggeri\n", list -> volo.flightCode);
continue;
}
}
}
int main() {
FILE *fp;
struct node *first = NULL;
struct flight volo;
/* Apro il file e controllo che sia stato aperto correttamente */
if ((fp = fopen(FILE_NAME, "rb")) == NULL) {
printf("Can't open %s\n", FILE_NAME);
exit(EXIT_FAILURE);
}
for (int i = 0; i < 4; i++) {
fread(&volo, sizeof(int), 7, fp);
first = addToList(first, volo);
}
decolla(first, 3497, 11, 30);
decolla(first, 2193, 11, 53);
decolla(first, 4284, 11, 07);
decolla(first, 5536, 12, 26);
printList(first);
delay(first);
passengersCount(first);
/* Controllo che il file sia chiuso correttamente */
if (fclose(fp) == EOF) {
printf("File not closed properly!");
exit(EXIT_FAILURE);
}
return 0;
}
The code compiles correctly so don't worry about the entire code, focus on the main() functions and the two structs.
I have two questions regarding the fread() function in the main() function:
Why, if I put sizeof(int) as the second parameter, the flight.destination value is assigned correctly? Shouldn't a char[3] variable be larger than sizeof(int)?
Why, if I put sizeof(struct flight) as second parameter (which would be the best choice), I get segmentation fault:11?

An array of three characters is three bytes. An int is usually (at least on modern 32 and 64 bit platforms) 4 bytes. It works to read sizeof(int) because the compiler adds padding.
But the "correct" (or at least usual) way to read the structure would be to read the whole structure as one single unit, i.e. using sizeof(volo) in your case:
fread(&volo, sizeof(volo), 1, fp);
If you get other errors because of it, you are doing something else wrong.

Related

how to take input from a text scanf and put it in linkedlist in C

i'm trying to take input from a text file and put the value in a linked list variables,
my file(text.txt) in in the following format:
the first value is my burst time, the second arrival and the last value is the priority, i want to make operations on all of these value from the same line like burst time + prioriy and so on, and when the operation for the first line ends up, the program should pass to the next line until the time the prom will fin the EOF.
now the big issue is when i'm trying to read each character and store each in a variable of a linked list for manipulation. find down my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node{
int x;
struct Node* next;
}Node;
void insert_end(Node** root, int value)
{
Node* new_node = malloc(sizeof(Node));
if(new_node == NULL)
{
exit(1);
}
new_node->next = NULL;
new_node->x = value;
if(*root == NULL)
{
*root = new_node;
return;
}
Node* curr = *root;
while(curr->next != NULL)
{
curr = curr->next;
}
curr->next = new_node;
}
//the part i'm reading the file
void deserialize(Node** root)
{
FILE* file = fopen("text.txt","r");
if(file == NULL)
{
exit(2);
}
int val;
int val2;
while(fscanf(file, "%d", &val)>0)
{
insert_end(root, val);
}
fclose(file);
}
int main(int argc, char* argv[])
{
Node* root = NULL;
if(root == NULL)
{
exit(2);
}
root->x = 15;
root->next = NULL;
deserialize(&root);
for(Node* curr = root; curr != NULL; curr = curr->next)
{
printf("%d\n",curr->x);
}
deallocate(&root);
return 0;
}
i really need your help, thank you
A complete example including serialize() deserialize() and linked list functions are here after the "Now What?" paragraph
May be you could write this in 2 steps. First try to consume the data on file, then put the code to insert this into a linked list..
About the struct
typedef struct Node
{
int x;
struct Node* next;
} Node;
maybe not the best way to describe a linked list. This is just a node and not a list. You will be better served with a bit of encapsulation. A list has metadata and pointers to nodes. Nodes points to or contain data. A list is NOT a node. A node is NOT a list. Program a linked list with just a node is problematic at best. Many loose pointers and your case even more problematic Node** pointers.
Compare with something like
typedef struct
{
unsigned burst;
unsigned arrival;
unsigned priority;
} Info;
typedef struct st_node
{
Info* info;
struct st_node* next;
struct st_node* prev;
} Node;
typedef struct
{
Node* head;
Node* tail;
unsigned size;
} List;
List* create();
List* destroy(List* list);
int insert(Info* one_item, List* list);
And see that a list is a list of nodes. Nodes points to info and info is the unit of data. Any data.
insert() inserts an item into a list, create() and destroy() manages lists and the encapsulation makes everything far more easier than just using pointers and pointers to pointers.
Consuming the file
Using this file as input.txt
2:101:34
20:10:3
5:1:4
and this data unit
typedef struct
{
unsigned burst;
unsigned arrival;
unsigned priority;
} Info;
See that the input is a CSV --- from Comma Separated Values --- file, a format from '70s. The separator is a ':'.
scanf() and family was written for this: Scan Formatted Files, hence the name. It is a scanner. So it is easier to just use it in this way.
See this example
List* deserialize(const char* file)
{
FILE* in = fopen(file, "r");
if (in == NULL) return NULL;
Info info = {0};
List* new_l = create(); // new list here
while (3 == fscanf(
in, "%d:%d:%d", &info.arrival,
&info.burst, &info.priority))
{
fprintf(
stderr, "%d:%d:%d\n", info.arrival, info.burst,
info.priority);
insert(&info, new_l); // insert data into list
};
fclose(in);
return new_l; // returns a list with the data on file
}
and the output
2:101:34
20:10:3
5:1:4
when called as
List* new_list = deserialize("input.txt");
as expected. And a List is returned with the data on file...
The complete code
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
unsigned burst;
unsigned arrival;
unsigned priority;
} Info;
typedef struct st_node
{
Info* info;
struct st_node* next;
struct st_node* prev;
} Node;
typedef struct
{
Node* head;
Node* tail;
unsigned size;
} List;
int insert(Info* one_item, List* list);
List* create();
List* destroy(List*);
List* deserialize(const char* file)
{
FILE* in = fopen(file, "r");
if (in == NULL) return NULL;
Info info = {};
List* new_l = create(); // new list here
while (3 == fscanf(
in, "%d:%d:%d", &info.arrival,
&info.burst, &info.priority))
{
fprintf(
stderr, "%d:%d:%d\n", info.arrival, info.burst,
info.priority);
insert(&info, new_l); // insert data into list
};
fclose(in);
return new_l; // returns a list with the data on file
}
int main(void)
{
List* new_list = deserialize("input.txt");
new_list = destroy(new_list);
return 0;
}
int insert(Info* one_item, List* list) { return 0; }
List* create()
{
List* L = (List*)malloc(sizeof(List));
if (L == NULL) return NULL;
L->size = 0;
L->head = NULL;
L->tail = NULL;
return L;
}
List* destroy(List* list) { return NULL; }
Now what?
Now we have
List* deserialize(const char* file)
that can consume the data from a file like this
input.txt:
3:2:1
6:4:2
12:8:3
24:16:4
by using
List* new_list = deserialize("input.txt");
But deserialize() just prints the data on stderr
We want a linked list of the dataset.
I will write an example below, but step by step in order to cover other cases for other readers.
A linked list
I will add a sequence number to the nodes just to help in testing.
The linked list has nothing to do with our problem, or else we will need one implementation of linked list for every program in life. In fact would be great if the code for the list was in another source code file, in order to be used anywhere else.
this is the example for List
typedef struct st_node
{
int num;
Info* info;
struct st_node* next;
struct st_node* prev;
} Node;
typedef struct
{
size_t size;
Node* head;
Node* tail;
} List;
A list of nodes, nodes pointing to info.
info is from now on
// info is the thing in the list
typedef struct
{
unsigned burst;
unsigned arrival;
unsigned priority;
unsigned seq; // sequence number for testing
} Info;
// this is a helper to format a single node listing
int show_i(Info*, const char*);
The code for show_i() is simple
int show_i(Info* info, const char* msg)
{
if (info == NULL) return -1;
if (msg != NULL) printf("%s", msg);
printf(
"#%4d: B:%4d A:%4d P:%4d\n", info->seq, info->burst,
info->arrival, info->priority);
return 0;
}
And the reason for this to exist is to provided some encapsulation on the way the nodes are printed.
And the functions we will use here are the obvious ones:
List* create_l();
List* destroy_l(List*);
int empty(List*);
int insert_n(Info*, List*);
int remove_n(List*);
int show_l(List*, const char*);
int size(List*);
This is a very simple example so we will assume a standard queue, FIFO (First In First Out) one, with items added at the end and removed from the front.
empty() returns 1 if the list is empty
size() returns the expected size
show_l() shows the list contents with an optional title message
the other functions work as expected.
A simple C implementation of the linked list
Functions have no more than 10 to 15 lines
List* destroy_l(List* L)
{
if (L == NULL) return NULL;
Node* p = L->head;
for (size_t i = 0; i < L->size; i += 1)
{ // remove one by one
Node* nx = p->next;
free(p->info); // free data
free(p); // free node
p = nx;
}; // for
free(L); // free list
return NULL; // to invalidate pointer
}
int empty(List* L)
{
if (L == NULL) return 0;
return (L->size == 0);
}
List* create_l()
{
List* nv = (List*)malloc(sizeof(List));
if (nv == NULL) return NULL;
nv->size = 0; // vazia
nv->head = NULL;
nv->tail = NULL;
return nv;
}
int insert_n(Info* info, List* L)
{ // inserts at the end of list
static unsigned seq = 1000;
if (L == NULL) return -1;
// new node here
Node* nv = (Node*)malloc(sizeof(Node));
// new data here: always copy
nv->info = (Info*)malloc(sizeof(Info));
*(nv->info) = *info;
nv->info->seq = seq++; // USN
nv->prev = L->tail;
nv->next = NULL;
// ajusta os ponteiros da lista
L->size += 1; // conta o novo
if (L->size == 1)
L->head = nv;
else { L->tail->next = nv; }
L->tail = nv;
return (int)L->size;
}
int remove_n(List* L)
{ // remove from start
if (L == NULL) return -1;
if (L->size == 0) return -2;
Node* p = L->head->next;
free(L->head->info); // data
free(L->head); // node
L->head = p;
L->size -= 1;
if (L->size == 0) L->tail = NULL;
return (int)L->size;
}
int show_l(List* L, const char* tit)
{
if (L == NULL) return -1;
if (tit != NULL) printf("%s", tit);
if (L->size == 0)
printf(" no elements\n");
else
printf(" %zd elements:\n", L->size);
if (L->head != NULL)
printf(" [First seq: %d", L->head->info->seq);
if (L->tail != NULL)
printf(" Last seq: %d]\n", L->tail->info->seq);
Node* p = L->head;
for (size_t i = 0; i < L->size; i += 1)
{
show_i(p->info, "\t");
p = p->next;
}
printf("\n");
return 0;
}
int size(List* L)
{
if (L == NULL) return 0;
return (int)L->size;
}
A test program for the list code
#include <stdio.h>
#include "v2-l.h"
int main(void)
{
Info info = {1, 1, 1, 1};
List* my_list = create_l();
show_l(my_list, "empty list...\n");
my_list = destroy_l(my_list);
my_list = create_l();
// test size
const int test_size = 3;
printf("[Testing with %d elements]\n\n\n", test_size);
for (int i = 0; i < test_size; i += 1)
{
info.priority = i; // just for testing
insert_n(&info, my_list);
};
char message[] = "NNNNNN elements inserted\n";
sprintf(message, "%d elements inserted\n", test_size);
show_l(my_list, message);
int res = 0;
while (res >= 0)
{
printf("\tabout to remove 1st element:\n");
res = remove_n(my_list);
printf(
"\
\tremove_l() returned %d\n\
\tsize() returned %d\n\
\tempty() returned %d\n",
res, size(my_list), empty(my_list));
show_l(my_list, "\n ==> List now:\n");
if (res < 0) break;
}; // while()
show_l(my_list, "On exit\n");
my_list = destroy_l(my_list);
return 0;
}
The idea: creates a list with test_size elements and then remove one by one until error, calling the functions. Then the list is destroyed.
output from test
empty list...
no elements
[Testing with 3 elements]
3 elements inserted
3 elements:
[First seq: 1000 Last seq: 1002]
#1000: B: 1 A: 1 P: 0
#1001: B: 1 A: 1 P: 1
#1002: B: 1 A: 1 P: 2
about to remove 1st element:
remove_l() returned 2
size() returned 2
empty() returned 0
==> List now:
2 elements:
[First seq: 1001 Last seq: 1002]
#1001: B: 1 A: 1 P: 1
#1002: B: 1 A: 1 P: 2
about to remove 1st element:
remove_l() returned 1
size() returned 1
empty() returned 0
==> List now:
1 elements:
[First seq: 1002 Last seq: 1002]
#1002: B: 1 A: 1 P: 2
about to remove 1st element:
remove_l() returned 0
size() returned 0
empty() returned 1
==> List now:
no elements
about to remove 1st element:
remove_l() returned -2
size() returned 0
empty() returned 1
==> List now:
no elements
On exit
no elements
Using the list on the original program
// here goes the program target
List* deserialize(const char* file);
int serialize(List* list, const char* file);
double pri_avg(List*);
The next obvious step is to use the 1st program and consume the file, but this time writing the data into a linked list, and then calling serialize() to create a new file with the data in the list.
Sure, both files must have the same data and the program will test itself.
As you asked, #jonathan pascal, the function pri_avg() computes an useless priority average, just to show how to compute something using the data from all nodes in the list.
Note that this is the same logic as in showing the list contents in show_l(). This is called a filter and in languages like C we can just pass a function address to a function that loops over the code, and use the same code to do anything with the dataset. In C++ is, for example, a for_each() function that does just this. All these functions here has the same logic.
Example implementation of the 3 functions
List* deserialize(const char* file)
{
FILE* in = fopen(file, "r");
if (in == NULL) return NULL;
Info info = {0};
List* new_l = create_l(); // new list here
while (3 == fscanf(
in, "%d:%d:%d", &info.burst,
&info.arrival, &info.priority))
{
// fprintf(
// stderr, "%d:%d:%d\n", info.arrival,
// info.burst, info.priority);
insert_n(&info, new_l); // insert data into list
};
fclose(in);
return new_l; // returns a list with the data on file
};
int serialize(List* L, const char* file)
{
if (L == NULL) return -1;
if (file == NULL)
{
printf("Missing file name\n");
return -2;
}
if (L->size == 0)
{
printf("Dataset is empty\n");
return -3;
}
FILE* out = fopen(file, "w");
if (out == NULL) return -3;
fprintf(
stderr,
"serialize(): writing %d elements into \"%s\"\n",
size(L), file);
Node* p = L->head;
for (size_t i = 0; i < L->size; i += 1)
{
fprintf(
out, "%d:%d:%d\n", p->info->burst,
p->info->arrival, p->info->priority);
p = p->next;
}
fprintf(out, "\n");
fclose(out);
fprintf(stderr, "\"%s\" closed\n", file);
return 0;
}
// get the priority average from the list
double pri_avg(List* L)
{
if (L == NULL) return -1;
if (L->size == 0) return 0.; // easy
double avg = 0.;
Node* p = L->head;
for (size_t i = 0; i < L->size; i += 1)
{ // here we have node data, one
// at a time
avg = avg + p->info->priority;
p = p->next;
};
return (double)avg / size(L);
}
Testing the 3 functions
#include <stdio.h>
#include "v2-l.h"
int main(void)
{
const char* in_file = "input.txt";
printf(
"deserialize(): building list from \"%s\"\n",
in_file);
List* my_list = deserialize(in_file);
show_l(my_list, " ==> As read from file...\n");
printf("average priority is %6.2f\n", pri_avg(my_list));
const char* out_file = "another.txt";
int res = serialize(my_list, out_file);
printf(
"serialize(): dumping list into \"%s\" "
"returned %d\n",
out_file, res);
my_list = destroy_l(my_list);
return 0;
}
And we have full circle over the problem: a CSV file is read from disk, a linked list is built, some values are computed, the list is written to disk in another file.
test output
deserialize(): building list from "input.txt"
==> As read from file...
4 elements:
[First seq: 1000 Last seq: 1003]
#1000: B: 3 A: 2 P: 1
#1001: B: 6 A: 4 P: 2
#1002: B: 12 A: 8 P: 3
#1003: B: 24 A: 16 P: 4
average priority is 2.50
serialize(): writing 4 elements into "another.txt"
"another.txt" closed
serialize(): dumping list into "another.txt" returned 0
The format string %d does not match the input :101 ,since : cannot be part of an integer. So scanf("%d") consumes nothing and the : is left in the input stream. You could use: while(fscanf(file, "%4d:", &val) == 1). If you are reading the last value on a line, the : will not match, but in this case you don't care. You might want to use fscanf(file, "%4d:%4d:%4d", ...) == 3 if you want to check the format of the input (ie, always exactly 3 inputs per line, so you can reject lines like 1:2:3:4:5:6:7). YMMV

Memory access violations when trying to read from structs inside of other structs

I am having trouble figuring out how to do this correctly. I have a linked list of nodes then those nodes have pointers put into an array contained in that node. These nodes make up a sort of one-way graph between the nodes. I must then traverse the nodes randomly until the node "Home" is reached.
The main issue I'm having is assigning the graph nodes into the list nodes. I want the function to take in the head of the list, the names of the nodes and the weight (cost to travel between nodes). I'm not sure how to do this correctly and I don't know what I did but I think there's an infinite loop somehow. Any help is greatly appreciated.
The input file is structured as such:
Applebees
GroundRound
BlueMoose
DrunkenNoodle
Home
STOP
Applebees BlueMoose 10
Applebees DrunkenNoodle 13
GroundRound Applebees 2
GroundRound DrunkenNoodle 7
GroundRound Home 52
STOP STOP 0
GroundRound
Ignore the print statements in graphInsert() those are me trying to debug the loops.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
struct graphNode {
char name[100]; // Establishment name
int arcCnt; // Number of outgoing arc from this node
int weights[10]; // Weights of each outgoing arc from this node
struct graphNode* arcs[10]; // Holds other graph nodes that are connected to this node (this node is source)
};
struct listNode {
char name[100]; // Establishment name
struct listNode* next;
struct graphNode* graph; // Pointer into graph
};
void listInsert(struct listNode **head, char name[100]) {
// setup new nodes
struct graphNode* newGraph = (struct graphNode*)malloc(sizeof(struct graphNode));
for (int i = 0; i < 100; i++) {
newGraph->name[i] = name[i];
}
for (int i = 0; i < 10; i++) {
newGraph->arcs[i] = NULL;
}
newGraph->arcCnt = 0;
struct listNode* newNode = (struct listNode*)malloc(sizeof(struct listNode));
for (int i = 0; i < 100; i++) {
newNode->name[i] = name[i];
}
newNode->next = NULL;
newNode->graph = newGraph;
// check if head is NULL
if (*head == NULL) {
*head = newNode;
return;
}
// if the list is populated then add the node to the end
struct listNode* current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
void graphInsert(struct listNode** head, char src[100], char dst[100], int weight) {
struct listNode* srcNode = *head;
printf("CALL:");
while (srcNode->next != NULL) { // loop through list to find src
printf("%s %s", srcNode->name, src);
if (strcmp(srcNode->name, src) == 0) { // when it finds the name, find the dst update the graph node data
printf("FOUND");
struct listNode* dstNode = *head;
while (dstNode->next != NULL) { // this loop is to find the pointer to the dst node
printf(" %s %s", dstNode->name, dst);
if (strcmp(dstNode->name, src) == 0) { // when it finds name finally update all the info
printf("FOUND");
// assign the new arc to the right spot based on arcCnt (how many arcs there are), then return to exit the loops
srcNode->graph->arcs[srcNode->graph->arcCnt] = dstNode->graph;
srcNode->graph->weights[srcNode->graph->arcCnt] = weight;
srcNode->graph->arcCnt++;
return;
}
dstNode = dstNode->next;
}
}
srcNode = srcNode->next;
}
}
int main(){
srand(2021);
// setup variables
struct listNode* head = NULL;
struct graphNode* sourceNode = NULL;
FILE* data = fopen("./hw10.data", "r");
int i = 0;
int section = 1; // flag to read the file correctly
// this loop reads the file
while (1) {
char name[100];
char name2[100];
int weight = 0;
if (section == 1) { // reads the first section
fscanf(data, "%100s", name);
if (strcmp(name, "STOP") == 0) { // if end of section then increment section counter
section++;
} else { // if its not the end of the section then add the name to the linked list
listInsert(&head, name);
}
} else if (section == 2) { // reads the first section and builds the graph
fscanf(data, "%100s %100s %d", name, name2, &weight);
if (strcmp(name, "STOP") == 0) { // if end of section then increment section counter
section++;
} else {
//graphInsert(&head, name, name2, weight);
}
} else if (section == 3) { // this section only reads one line and gets the
char tmp[100];
fscanf(data, "%100s", tmp);
struct listNode* current = head;
while (current->next != NULL) { // loop through to find the right node for the name
if (strcmp(current->name, tmp) == 0) { // if names are equal update the node
sourceNode = current->graph;
break;
}
current = current->next;
}
}
if (feof(data)) break;
i++;
}
// debug print data
printf("\n");
struct listNode* current = head;
while (current != NULL) {
printf("%s\n", current->name);
current = current->next;
}
printf("\n");
// starting node
printf("%s ", sourceNode->name);
// now walk through the graph from sourceNode until we reach the node "Home"
int totalWeight = 0;
i = 0;
while (i < 100) {
char* tmp = sourceNode->name;
if (strcmp(tmp, "Home") == 0) { // if were home then exit program
// ending node and cost
printf("%s %d", sourceNode->name, totalWeight);
return 0;
} else { // if were not home then keep looping
int index = (rand() % sourceNode->arcCnt); // Generates random number between 0 and sourceNode->arcCnt
sourceNode = sourceNode->arcs[index];
//printf("Going to: %s, Index: %d", sourceNode->name, totalWeight);
}
i++;
}
return 0;
}

Why does it save only one element instead of the whole list? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 months ago.
Improve this question
I'm making a program where the user is supposed add a pack of pasta as the last element of a list, delete the first element of the list or visualize the whole list.
However, when I try to add new elements and visualize the list, it only shows the last element that I've introduced and only saves that element. The program is supposed to save the list in a txt file.
If there are some parts that are unclear, I apologize as English is not my first language and I do not program in English.
#include <stdio.h>
#include <stdlib.h>
/* struct to represent a pack of pasta */
struct Pasta {
char type[20];
char brand[20];
int time;
int raffInt;
};
typedef struct Pasta PASTA;
/* struct to represent a list */
struct Nodo {
PASTA p;
struct Nodo *next;
};
typedef struct Nodo *NODO;
/******************************************************************************
********************* ADD THE LAST ELEMENT OF THE LIST ***********************
******************************************************************************/
/* function that read a pack of pasta */
PASTA leggiPasta() {
PASTA pasta;
/* insert the type */
printf("What type of pasta?\n");
scanf("%s", &pasta.type);
/* insert the brand */
printf("Which brand?\n");
scanf("%s", &pasta.brand);
/* insert the time to be cooked */
printf("Time to be cooked?\n");
scanf("%d", &pasta.time);
/* determine if it is whole or refined*/
do {
printf("Is it whole (PRESS 1) or refined (PRESS 2)?\n");
scanf("%d", &pasta.raffInt);
/* if the value is not valid */
if(pasta.raffInt != 1 && pasta.raffInt != 2)
printf("Not valid\n");
} while(pasta.raffInt != 1 && pasta.raffInt != 2);
return pasta;
}
/* function to insert a pack of pasta at the bottom of the list */
NODO insert(NODO list) {
NODO new;
nuovo = malloc(sizeof(struct Nodo));
/* fill the parts of the pack */
nuovo -> p = leggiPasta();
printf("\n");
new -> next = NULL;
while (list -> next != NULL)
list = list -> next;
/* now list contains the address of the last element of the list */
list -> next = new;
return new;
}
/******************************************************************************
*********************************** PRINT ************************************
******************************************************************************/
/* function to print a pack of pasta */
void printPasta(PASTA p) {
/* print the type */
printf("Type: %s\n", p.typo);
/* print the brand */
printf("Brand: %s\n", p.brand);
/* print the time */
printf("Time to be cooked: %d min\n", p.time);
/* whole or refined */
if(p.raffInt == 1)
printf("Whole\n");
else
printf("Refined\n");
}
/* function to print a list */
void print(NODO list) {
NODO nodo = list;
/* if the list is empty, you don't have to do anything */
if(nodo != NULL) {
printf("\nHere's the list:\n");
while (nodo != NULL) {
printPasta(nodo -> p);
nodo = nodo -> next;
}
printf("\n\n");
}
else
printf("Nothing to print\n\n");
}
/******************************************************************************
************************** DELETE THE FIRST ELEMENT **************************
******************************************************************************/
/* function to delete the first element of the list */
NODO delete(NODO list) {
NODO current;
/* if the list is empty, you don't have to do anything */
if(list == NULL)
current = NULL;
else {
current = list -> next;
free(list);
printf("Deleted\n\n");
}
return current;
}
/******************************************************************************
************************************ FILE ************************************
******************************************************************************/
/* function for the acquisition of a list from a file */
NODO acquisition() {
FILE *fp = fopen("pasta.txt", "r"); //to read a txt file
NODO head = NULL; //head of the list
NODO current;
NODO previous;
PASTA pasta; //a pack of pasta
int read; //if it was read or not
/* if the file is empty, do nothing */
if(fp != NULL) {
ead r = fread(&pasta, sizeof(PASTA), 1, fp);
if (read) { //it was read
/* read the first one */
head = malloc(sizeof(struct Nodo));
head -> p = pasta;
/* keep track of the last one */
previous = head;
/* read the rest of them */
do {
/* read a new one */
read = fread(&pasta, sizeof(PASTA), 1, fp);
if (read) { //it was read
current = malloc(sizeof(struct Nodo));
current -> p = pasta;
/* connect it to the previous one */
previous -> next = current;
/* the new one becomes the precedent */
previous = current;
}
else
previous -> next = NULL;
} while(letto);
printf("List retrieved\n\n");
}
else
printf("List empty\n\n");
fclose(fp);
}
else
printf("Couldn't open it\n\n");
return head;
}
/* function to save a list in a file */
void save(NODO list) {
FILE *fp = fopen("pasta.txt", "w"); //to write a txt file
/* if it's empty do nothing */
if(fp != NULL) {
while (list != NULL) { //go ahead while it has elements
fwrite(&(list -> p), sizeof(struct Nodo), 1, fp);
lista = list -> next; //proceed
}
fclose(fp);
printf("Saved successfully\n\n");
}
else
printf("Couldn't save\n\n");
}
/* main function */
int main() {
NODO list = acquisition(); //create the list
int answer = -1; //to interact with the user
while (answer != 0) {
/* choose the operation */
printf("What do you want to do?\n");
printf("1 -> Insert a new pack of past\n");
printf("2 -> Delete the first element of the list\n");
printf("3 -> Visualise the list\n");
printf("0 -> Finish the program\n");
scanf("%d", &answer);
/* insert */
if(answer == 1) {
list = insert(list);
}
/* delete */
else if(answer == 2) {
list = delete(list);
}
/* visualise */
else if(answer == 3) {
print(list);
}
/* finish the program */
else if (answer == 0) {
printf("Finished, goodbye\n\n");
}
/* wrong number */
else if (answer != 0) {
printf("It has no meaning, \n\n");
}
}
save(list);
}
There are multiple problems in your code:
there were some translation errors: it is recommended to use English for all identifiers in your code to make it easier to collaborate with other programmers. I am not a native speaker either, but this habit proved very effective for me for the last 40 years.
hiding pointers behind typedefs is confusing and error prone. Use typedef struct Node Node; and use Node *.
the file pasta.txt is actually a binary file as you write the contents of the struct Pasta as stored in memory directly to it. You should use a different name and open it as binary with "rb" and "wb".
using a textual format instead of binary is much preferred for portability, readability, extensibility.
function acquisition() should not make a special case of the first element read.
the function insert() crashes is the list is empty. You should test for this and return nuovo if list is a null pointer.
the function insert() should return the list, not the last element added unless the list was initially empty. this is causing the problem stated.
do not use & in front of arrays passed to scanf() and do pass the maximum number of bytes to read:
scanf("%19s", pasta.typo);
when writing to the file, you should use the size of struct Pasta instead of struct Nodo. To avoid this silly mistake, use sizeof(list->p).
Here is a modified version you can study:
#include <stdio.h>
#include <stdlib.h>
/* struct to represent a pack of pasta */
typedef struct Pasta Pasta;
struct Pasta {
char type[20];
char brand[20];
int time;
int raffInt;
};
/* struct to represent a list */
typedef struct Node Node;
struct Node {
Pasta p;
Node *next;
};
/* function that read a pack of pasta */
Pasta leggiPasta(void) {
Pasta pasta;
/* insert the type */
printf("What type of pasta?\n");
scanf("%19s", pasta.type);
/* insert the brand */
printf("Which brand?\n");
scanf("%19s", pasta.brand);
/* insert the time to be cooked */
printf("Time to be cooked?\n");
scanf("%d", &pasta.time);
/* determine if it is whole or refined*/
for (;;) {
printf("Is it whole (PRESS 1) or refined (PRESS 2)?\n");
scanf("%d", &pasta.raffInt);
/* if the value is not valid */
if (pasta.raffInt == 1 || pasta.raffInt == 2)
break;
printf("Not valid\n");
}
printf("\n");
return pasta;
}
/* function to insert a pack of pasta at the bottom of the list */
Node *insert(Node *list) {
Node *new_node = calloc(sizeof(*new_node), 1);
/* fill the parts of the pack */
new_node->p = leggiPasta();
new_node->next = NULL;
if (list == NULL) {
list = new_node;
} else {
Node *tail = list;
while (tail->next != NULL)
tail = tail->next;
/* now tail contains the address of the last element of the list */
tail->next = new_node;
}
return list;
}
/* function to print a pack of pasta */
void printPasta(Pasta p) {
/* print the type */
printf("Type: %s\n", p.type);
/* print the brand */
printf("Brand: %s\n", p.brand);
/* print the time */
printf("Time to be cooked: %d min\n", p.time);
/* whole or refined */
if (p.raffInt == 1)
printf("Whole\n");
else
printf("Refined\n");
}
/* function to print a list */
void print(Node *list) {
Node *node = list;
/* if the list is empty, you don't have to do anything */
if (node != NULL) {
printf("\nHere's the list:\n");
while (node != NULL) {
printPasta(node->p);
node = node->next;
}
printf("\n\n");
} else {
printf("Nothing to print\n\n");
}
}
/* function to delete the first element of the list */
Node *delete(Node *list) {
Node *current;
/* if the list is empty, you don't have to do anything */
if (list == NULL) {
current = NULL;
} else {
current = list->next;
free(list);
printf("Deleted\n\n");
}
return current;
}
/* function for the acquisition of a list from a file */
Node *acquisition(void) {
FILE *fp = fopen("pasta.txt", "r"); //to read a txt file
Node *head = NULL; //head of the list
Node *tail = NULL;
Node *current;
Pasta pasta; //a pack of pasta
int count = 0;
/* if the file is empty, do nothing */
if (fp != NULL) {
char buf[100];
while (fgets(buf, sizeof buf, fp)) {
if (sscanf(buf, "%19[^,],%19[^,],%d,%d",
pasta.type, pasta.brand,
&pasta.time, &pasta.raffInt) == 4)
{
count++;
/* allocate a new node */
current = calloc(sizeof(*current), 1);
current->p = pasta;
current->next = NULL;
if (tail == NULL) {
tail = head = current;
} else {
tail = tail->next = current;
}
} else {
fprintf(stderr, "invalid format: %s", buf);
}
}
fclose(fp);
if (count) {
printf("List retrieved: %d elements\n\n", count);
} else {
printf("List empty\n\n");
}
} else {
printf("Couldn't open file\n\n");
}
return head;
}
/* function to save a list in a file */
int save(Node *list) {
FILE *fp = fopen("pasta.txt", "w"); //to write a txt file
if (fp != NULL) {
while (list != NULL) { //go ahead while it has elements
fprintf(fp, "%s,%s,%d,%d\n",
list->p.type, list->p.brand,
list->p.time, list->p.raffInt);
list = list->next; //proceed
}
fclose(fp);
printf("Saved successfully\n\n");
return 0;
} else {
printf("Couldn't save\n\n");
return 1;
}
}
/* main function */
int main() {
Node *list = acquisition(); //create the list
int answer; //to interact with the user
for (;;) {
/* choose the operation */
printf("What do you want to do?\n");
printf("1 -> Insert a new pack of past\n");
printf("2 -> Delete the first element of the list\n");
printf("3 -> Visualise the list\n");
printf("0 -> Finish the program\n");
if (scanf("%d", &answer) != 1)
break;
if (answer == 1) {
/* insert */
list = insert(list);
} else
if (answer == 2) {
/* delete */
list = delete(list);
} else
if (answer == 3) {
/* visualise */
print(list);
} else
if (answer == 0) {
/* finish the program */
printf("Finished, goodbye\n\n");
break;
} else {
/* wrong number */
printf("It has no meaning\n\n");
}
}
return save(list);
}

C list of a list

im having a problem, im trying to make a list of a list where inicioC refers to the first node of clients, and every node of clients will have a list of rentals, referred as inicioA. The thing is, i dont know how to save the first pointer of the rentals, like, the first node of clients will only be saved one time, but wont the first node of every rental be different?
this are the structs:
typedef struct _aluguer
{
int id, estado, diaI, mesI, anoI, diaE, mesE, anoE;
struct _aluguer *prox;
}aluguer, *pAluguer;
typedef struct _registo
{
int nif,nalu;
char nome[100];
struct _registo *prox;
pAluguer *inicioA;
}registo, *pRegisto;
and this is the code I use to extract the info from a file into the list of lists
pRegisto iniC(pRegisto inicioC, pAluguer inicioA)
{
FILE *c;
int j, nif, nalu, l=0;
char nome[100];
c = fopen("clientes.txt", "r"); // abrir ficheiro
if(c == NULL)
{
printf("Erro ao abrir ficheiro %s", "clientes.txt");
exit(0);
}
while(fscanf(c, "%d %d %s", &nif, &nalu, nome) == 3) //format of info
{
pRegisto novoC = malloc(sizeof(registo));
if(novoC == NULL)
{
printf("erro alocacao memoria\n");
return inicioC;
}
novoC -> prox = NULL;
pAluguer inicioA = NULL;
pRegisto aux = inicioC;
pRegisto p = NULL;
novoC->nif=nif;
novoC->nalu=nalu;
strcpy(novoC->nome, nome);
while(aux != NULL)
{
p = aux;
aux = aux->prox;
}
if( aux == inicioC)
{
inicioC=novoC;
}
else
{
p->prox = novoC;
}
for(j=0; j<novoC->nalu; j++) // repeat is equal to the number of rentals
{
l++;
pAluguer novoA = malloc(sizeof(aluguer));
if(novoA == NULL)
{
printf("erro alocacao memoria\n");
return inicioC;
}
novoA -> prox = NULL;
pAluguer aux = inicioA;
pAluguer p = NULL;
fscanf(c, "%d %d", &(novoA->id), &(novoA->estado));
if(novoA->estado == 0)
{
fscanf(c, " %d %d %d", &(novoA->diaI), &(novoA->mesI), &(novoA->anoI));
}
else
{
fscanf(c, " %d %d %d %d %d %d", &(novoA->diaI), &(novoA->mesI), &(novoA->anoI), &(novoA->diaE), &(novoA->mesE), &(novoA->anoE));
}
while(aux != NULL)
{
p = aux;
aux = aux->prox;
}
if( aux == inicioA)
{
inicioA=novoA;
}
else
{
p->prox = novoA;
}
}
}
fclose(c);
return inicioC;
}
Arraylist (Array of pointers in C) is good choice for implementing list of list but as you are forced to do in this way, I am showing a Simple method how you can develop list of list in C.
It is very simple,suppose you have a list of 3 numbers: 1,2,3 i.e list_1,list of 2 numbers: 5,6 i.e list_2.Now these list_1 and list_2 can be linked in a similar way as the numbers in list linked above.Look at this scenario
list_1:1->2->3->Null
list_2:5->6->Null
list_of_list : list_1->list_2->Null i.e. (1->2->3->Null) -> (5->6->Null) -> Null
Here is a Sample program to insert list of ints in Last:
#include <stdio.h>
#include <stdlib.h>
// for list of Intergers
struct node{
int Data;
struct node *next;
};
// this is for list of nodes i.e list of lists
struct list{
struct node *start;
struct list *listnext;
};
// insert integers in list
void insertNode(struct node **head ,int data){
struct node *temp,*current;
temp=malloc(sizeof(struct node));
temp->Data=data;
temp->next=NULL;
if((*head)==NULL){
(*head)=temp;
}
else{
current=(*head);
while(current->next!=NULL){
current=current->next;
}
current->next=temp;
}
}
// insert lists of integers in a list
void insertList(struct list **Listhead,struct node *head){
struct list *temp,*current;
temp=malloc(sizeof(struct list));
temp->start=head;
temp->listnext=NULL;
if((*Listhead)==NULL){
(*Listhead)=temp;
}
else{
current=(*Listhead);
while(current->listnext!=NULL){
current=current->listnext;
}
current->listnext=temp;
}
}
// Show all the list with their data
void show(struct list *Listhead){
int i=1;
struct list *current;
struct node *currentlist;
current=Listhead;
while(current!=NULL){
currentlist=current->start;
printf("List %d: ",i);
while(currentlist!=NULL){
printf("%d ",currentlist->Data);
currentlist=currentlist->next;
}
i++;
printf("\n");
current=current->listnext;
}
}
int main(){
struct node *head1=NULL,*head2=NULL,*head3=NULL; // 3 lists of integers
struct list *Listhead=NULL; // Listhead will be the head of lists of list
insertNode(&head1,20); // inserting in first list
insertNode(&head1,13);
insertNode(&head1,22);
insertNode(&head1,18);
insertNode(&head2,42); // inserting in second list
insertNode(&head2,15);
insertNode(&head3,12); // inserting in third list
insertNode(&head3,14);
insertNode(&head3,28);
insertList(&Listhead,head1); // inserting lists in list
insertList(&Listhead,head2);
insertList(&Listhead,head3);
show(Listhead);
}
Output for this Program:
List 1: 20 13 22 18
List 2: 42 15
List 3: 12 14 28
I hope you got the point.

Bubble Sort in linked lists C

any idea why does my program crash after showing the right result? (i.e. i insert 6 2 4 3 he returns 2 3 4 6 but the console crashes right after!)
The main idea is to sort a linked list after the user giving the integers. I tried to solve it like if it was a bubble sort but for some reason it's not 100% operational. sorry for the portuguese comments!
#define ITEM_TYPE int
typedef struct lnode* List;
typedef struct lnode{
ITEM_TYPE info;
List next;
}List_node;
void ordenalista(List lista){
int contador = 0, i;
/* lista é uma lista recebida */
List head = lista; /* termos sempre disponível o início da lista*/
List actual = NULL; /*lista vazia, ou nó */
List temp = NULL;
if(head == NULL || head->next == NULL){ /* caso de lista vazia ou so com 1 elemento*/
printf("A lista esta vazia ou tem apenas um elemento");
return 0;
}
while(head != NULL){ /* contar quantos elementos tem a lista*/
contador++;
head = head->next;
printf("%d \n", contador);
}
for(i=0; i<contador; i++){ /* percorrer todos os elementos da lista*/
while(head->next != NULL){ /* enquanto não chegarmos ao final da lista*/
if(head->info > head->next->info){ /* se o valor do atual for maior que o valor do seguinte*/
temp = head->next;
head->next = head->next->next; /* não precisamos de usar actual->data, apenas precisamos de mudar os ponteiros*/
temp->next = head;
}
}
}
}
void ex213(){
int numero;
List lista;
lista = create_list();
while((scanf("%d",&numero)) == 1){ /* lê da esquerda para a direita. SCANF DÁ 1 SE INSERIR INTEIRO, 0 CASO CONTRÁRIO */
insertwithoutorder(lista, numero);
}
ordenalista(lista);
printlist(lista);
}
void insertwithoutorder(List lista, ITEM_TYPE it){
List no;
List ant, inutil;
no = (List)malloc(sizeof(List_node));
if (no != NULL) {
no->info = it;
searchwithoutorder(lista, it, &ant, &inutil);
/*while(ant->next != NULL){
ant = ant->next;
}*/
no->next = NULL;
ant->next = no;
}
}
void searchwithoutorder(List lista, ITEM_TYPE chave, List *ant, List*actual){
*ant = lista; *actual = lista->next;
while ((*actual) != NULL){
*ant = *actual;
*actual = (*actual)->next;
}
if ((*actual) != NULL && (*actual)->info != chave)
*actual = NULL; /* Se elemento não encontrado*/
}
void printlist(List lista){
List l = lista->next; /* Salta o header */
while (l){
printf("%d ", l->info);
l=l->next;
}
}
int main(){
ex213();
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define ITEM_TYPE int
typedef struct lnode* List;
typedef struct lnode{
ITEM_TYPE info;
List next;
} List_node;
List create_list(void){
//top node unused
return calloc(1, sizeof(List_node));//note : might NULL != 0
}
List lastNode(List lista){
while (lista->next != NULL){
lista = lista->next;
}
return lista;
}
void insertwithoutorder(List lista, ITEM_TYPE it){
List no, ant;
no = create_list();
if (no != NULL) {
no->info = it;
no->next = NULL;
ant = lastNode(lista);
ant->next = no;
} else {
printf("failed to create a new node.\n");
}
}
void ordenalista(List lista){
List head = lista;
List actual, neighbor, sentinel = NULL;
if(head->next == NULL){
printf("A lista esta vazia\n");
return ;
}
while(head->next != sentinel){
actual = head->next;
neighbor= actual->next;
while(neighbor != sentinel){
if(actual->info > neighbor->info){
ITEM_TYPE temp = actual->info;
actual->info = neighbor->info;
neighbor->info = temp;
}
actual = neighbor;
neighbor= neighbor->next;
}
sentinel = actual;
}
}
void printlist(List lista){
List l = lista->next;
while (l){
printf("%d ", l->info);
l=l->next;
}
puts("");
}
void ex213(void){
int numero;
List lista = create_list();
while((scanf("%d", &numero)) == 1){
insertwithoutorder(lista, numero);
}
//printlist(lista);
ordenalista(lista);
printlist(lista);
//deallocate ?
}
int main(void){
ex213();
return 0;
}
The crash must be occurring in the function (now) named printlist(), as your program does nothing else after that function returns.
I don't see anything inherently wrong with printlist(), but it does depend on the list being in a valid state. In particular, my best guess at why the program fails where it does would be that the next pointer of the last list element contains a junk value instead of the expected NULL. You could verify that by running the program in a debugger.
How, then, might the list be corrupted?
Well, your insertion function looks ok. The searchwithoutorder() function on which it relies doesn't actually do what its name says, but it does do what insertwithoutorder() needs it to do.
That leaves the sort function, ordenalista(), and here I'm a bit flumoxed. I don't see how the version you posted could do any sorting at all. You have a while loop like so: while(head != NULL){...}, whithout any break or goto inside, so when control passes beyond this loop it must be that head == NULL. Then, without modifying the value of head, you go into a loop nest like this:
for(i=0; i<contador; i++) { /* percorrer todos os elementos da lista*/
while(head->next != NULL) { /* enquanto não chegarmos ao final da lista*/
...
}
}
But head is NULL at that point, so dereferecing it produces undefined behavior. If that behavior were not itself a crash, then correctly guessing and dereferencing the pointer you meant is an extremely unlikely alternative. Moreover, you do not modify head in the body of the loop, so it remains NULL. There are other problems with this loop, too.
As if all that weren't enough, there is also no good way for your sort function to change which element is at the head of the list -- at least none that would be effective for the caller.
So basically, I don't believe you have accurately described the problem. It must be either that the failure behavior you observed is different from what you described, or that the code you presented does not correspond to the program whose misbehavior you described.
When asking the user for data, it is useful to let the user know what you are asking for and how to handle/terminate any requests for input. A blinking cursor on a blank line tells the user nothing. (even when it is testing for you, it can help prevent an inadvertent keystroke of the wrong type). For example your ex213 function leaves a blinking cursor on a blank line leaving the user wondering "Is the program hung?" "Did it encounter a race condition?" etc.. When asking the user for linked-list data, a simple additional line or two of guidance can really help. Example:
void ex213 (void)
{
int numero;
List lista = create_list ();
printf ("\nEnter a number to add to the list [CTRL+D] when done:\n\n");
while (printf (" data: ") && (scanf ("%d", &numero)) == 1) {
insertwithoutorder (lista, numero);
}
ordenalista (lista);
printf ("\n\nThe ordered linked-list is:\n\n");
printlist (lista);
printf ("\n");
//deallocate ?
}
Output
$ ./bin/ll_single_sort
Enter a number to add to the list [CTRL+D] when done:
data: 2
data: 8
data: 20
data: 6
data: 9
data: 1
data:
The ordered linked-list is:
1 2 6 8 9 20
Adding that to the answer provided by BLUEPIXY provides the results you were looking for.

Resources