How can i read a list with fread? - c

Is this possible, what's wrong here!?
I need this to read the list of "items" that belongs inside one node of "Orcamento", and also the list of "decisores".
int lerDadosO(DLLIST3 *orcamentos) {
int nOrcamentos = 0, i = 0;
ORCAMENTO Orcamento;
FILE *ficheiro = fopen("dadosO.bin", "rb");
if(ficheiro != NULL) {
fseek(ficheiro, 0L, SEEK_END);
nOrcamentos = ftell(ficheiro) / sizeof(ORCAMENTO);
rewind(ficheiro);
while (i != nOrcamentos) {
Orcamento.itens = createI();
Orcamento.decisores = createU();
fread(&Orcamento, sizeof(ORCAMENTO), 1, ficheiro);
// viewI(Orcamento.itens, listarItem);
if(insertendO(orcamentos, Orcamento) != 0) {
printf("Ocorreu um Erro!");
return 0;
}
i++;
}
fclose(ficheiro);
}
else {
printf("Não existe nenhum ficheiro binário!");
}
return nOrcamentos;
}

I'm not sure how you have implemented your list system, this may be accomplished by first reading data to a buffer, than transforming that into a "list"
struct record {
int field0
int field1;
};
int main(void) {
// variables
FILE *stream; // reading data
struct record data[length]; // writing data
struct mylisttype *list; // result
...
// read `length` `struct record`s from `stream`
fread(data, sizeof(struct record), length, stream);
listfrombuffer(buffer, list);
...
}

Related

Reading from a file all elements within it in C

So I need to write a function that reads all the elements inside a bit file. The point is that I don't know how many elements there could be inside, but I know what type of elements are. So I tried to write this function:
void loadData(Parallelogram **array) {
FILE *data; long size;
//int numberOfElements = 0;
int numberOfObjects = 0;
if ((data = fopen(name, "rb"))!=NULL) {
fseek(data, 0, SEEK_END);
size = ftell(data);
fseek(data, 0, SEEK_SET);
if (size<(long)sizeof(Parallelogram)) {
printf("The file is empty try to open another file maybe");
} else {
Parallelogram *tempArray;
numberOfObjects = size/sizeof(Parallelogram);
tempArray = realloc(*array, numberOfObjects*sizeof(Parallelogram));
if (tempArray==NULL) {
printf("There was an error reallocating memory");
} else { *array = tempArray; }
fread(*array, sizeof(Parallelogram), numberOfObjects, data);
}
}
fclose(data);
}
The elements are struct objects of type Parallelogram, storing a few floats.
The commented out part was me trying another method form another question but not understanding the real mechanism. Anyways when I call the function the array is empty. What am I getting wrong?
EDIT: As requested this is the main function where I call the function loadData()
int main() {
Parallelogram *paraArray = NULL;
loadData(&paraArray);
}
EDIT: complete function more or less like the OP's.
You may do something like:
void loadData(Parallelogram **array, size_t * n) {
FILE *data;
if ((data = fopen("file.bin", "rb"))!=NULL) {
Parallelogram buffer[100]; // may be malloc'd
size_t chunk_size = 100;
size_t read_size = 0;
size_t number_of_objects = 0;
Parallelogram *aux = NULL;
*array = NULL;
while ((read_size = fread(buffer, sizeof *buffer, chunk_size, data)) > 0) {
aux = realloc(*array, (number_of_objects + read_size) * sizeof *buffer);
if (aux == NULL) {
// ERROR
free(*array);
// clean, break/exit
}
*array = aux;
memcpy(*array + number_of_objects, buffer, read_size*sizeof *buffer);
number_of_objects += read_size;
}
// check file for errors (ferror()) before exit
fclose(data);
*n = number_of_objects;
}
}

My Simple List only prints the last element of a .txt file

I have this code to print the content of a .txt file that includes the description, code-name, date and price of an unknown number of products (this is because it is supposed to work with any .txt file).
The problem is that my program only prints the last product of the .txt file. I don't know why that happens. Thanks in advance!
This is the program:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LDES 32
#define LCOD 16
struct fecha { int d, m, a; };
struct ventas {
char descripcion[LDES];
char codigo[LCOD];
struct fecha ultRep;
float venta;
};
struct nodo {
struct ventas d;
struct nodo *sig;
};
nodo*primero = NULL;
nodo*ultimo = NULL;
void leerTexto(void) {
nodo*nuevo = (nodo*)malloc(sizeof(nodo));
char desc[LDES];
char cod[LCOD];
FILE *pf = fopen("ventas.txt", "r");
if (pf) {
fgets(desc, LDES, pf);
while (!feof(pf)) {
strcpy(nuevo->d.descripcion, desc);
fgets(cod, LCOD, pf);
strcpy(nuevo->d.codigo, cod);
fscanf(pf, "%d/%d/%d", &nuevo->d.ultRep.d, &nuevo->d.ultRep.m, &nuevo->d.ultRep.a);
fgetc(pf);
fscanf(pf, "%f", &nuevo->d.venta);
fgetc(pf);
if (primero == NULL) {
primero = nuevo;
primero->sig = NULL;
ultimo = nuevo;
}
else {
ultimo->sig = nuevo;
nuevo->sig = NULL;
ultimo = nuevo;
}
fgets(desc, LDES, pf);
}
fclose(pf);
}
}
void mostrarLista(void) {
nodo* actual = (nodo*)malloc(sizeof(ventas));
actual = primero;
if (primero != NULL) {
while (actual != NULL) {
printf("%s\n", actual->d.descripcion);
printf("%s\n", actual->d.codigo);
printf("%d/%d/%d\n", actual->d.ultRep.d, actual->d.ultRep.m, actual->d.ultRep.a);
printf("%f\n", actual->d.venta);
actual = actual->sig;
}
}
}
int main(void) {
leerTexto();
mostrarLista();
return 0;
}
This is the .txt file:
Pizza
124g284j2
10/02/19
230.93
Hamburger
27842yh28
23/09/23
197.00
Carrot
283u1j23
31/12/17
89.98
Ice Cream
3613y23u2
12/11/34
234.98
In your C++ program, you have to put the node allocations inside the while loop. fgets(desc, LDES, pf) should also be inside the while loop.
Your filename probably has *.cpp extention, you are compiling in C++. You have to change the file extenstion to *.c, or you can set the compiler option to use C compiler.
The correct declaration in C is:
struct nodo* nuevo = malloc(sizeof(struct nodo));
You can put fgets call sequentially as they appear in input file. Use fscanf(pf, "%f\n"... to read the last character. Example:
if(pf)
{
while(fgets(desc, LDES, pf))
{
struct nodo* nuevo = malloc(sizeof(struct nodo));
strcpy(nuevo->d.descripcion, desc);
fgets(nuevo->d.codigo, LCOD, pf);
fscanf(pf, "%d/%d/%d\n",
&nuevo->d.ultRep.d, &nuevo->d.ultRep.m, &nuevo->d.ultRep.a);
fscanf(pf, "%f\n", &nuevo->d.venta);
if(primero == NULL)
{
primero = nuevo;
primero->sig = NULL;
ultimo = nuevo;
}
else
{
ultimo->sig = nuevo;
nuevo->sig = NULL;
ultimo = nuevo;
}
}
fclose(pf);
}
You can also add error check for fscanf. If fscanf is successful, it will return the number of items it reads. Example
if(3 != fscanf(pf, "%d/%d/%d\n",
&temp.ultRep.d, &temp.ultRep.m, &temp.ultRep.a))
break;
You have unnecessary allocation for node for in mostrarLista. It allocates memory for actual, but in the next line actual is set primero Now you have a memory leak, there is no way to free memory from malloc. You simply need
void mostrarLista(void)
{
struct nodo* actual = primero;
while(actual != NULL)
{
printf("%s", actual->d.descripcion);
printf("%s", actual->d.codigo);
printf("%d/%d/%d\n", actual->d.ultRep.d, actual->d.ultRep.m, actual->d.ultRep.a);
printf("%f\n\n", actual->d.venta);
actual = actual->sig;
}
}

Chain List, story of pointers

I have this following code:
void pushInList(t_chan **chan, char *name, char *nick_user)
{
t_chan *new_channel;
(void)nick_user;
if ((new_channel = malloc(sizeof(t_chan))) == NULL)
return ;
new_channel->name = name;
new_channel->prev = (*chan);
(*chan) = new_channel;
}
display_list(t_chan *chan, int fd)
{
int i;
i = 0;
while (chan != NULL)
{
printf("list : %s\n", chan->name);
chan = chan->prev;
}
}
int create_chanel(int fd, char *buffer, t_chan **chan)
{
char *tmp;
int i;
i = 0;
if ((tmp = get_param(fd, buffer, 2, "NICK")) == NULL)
return (EXIT_FAILURE);
while ((*chan) != NULL)
{
/* FUTUR CHECK OF EXISTING CHANEL*/
(*chan) = (*chan)->prev;
}
if ((*chan) == NULL)
pushInList(chan, tmp, "Kilian");
return (EXIT_SUCCESS);
}
int main()
{
t_chan *chan;
char *test;
chan = NULL;
test = strdup("JOIN Coucou");
create_chanel(4, test, &chan);
test = strdup("JOIN Google");
create_chanel(4, test, &chan);
printf("-------------------\nlast display :\n");
display_list(chan, 4);
}
I don't understand why my list is every time NULL. I passed a pointer but in my main the list don't keep its values.
Can you help me, I don't understand...
It's a chain list of channel, When a client send "Join Coucou", if the channel Coucou doesn't exist I create a new node.
Thank you in advance,
Cordialy

C - Bubble Sort Program binary file

I'm trying to make a Bubble Sort program in a binary file without using any arrays, instead of I will use fseek and fwrite functions.
Here is my code:
typedef struct{ //Films
short int year;
char title[LEN_NAME];
Genero_t gendre;
float rateIMDB;
}Ficha_t;
FILE * fd;
fd = fopen(name,"r+b");
Ficha_t aux1;
Ficha_t aux2;
int i,j,len;
if (fd != NULL)
{
rewind(fd);
fseek(fd, 0, SEEK_END);
len=ftell(fd);
rewind(fd);
for(i=0;i<len;i++);
{
for(j=0;j<len-1;j++)
{
fread(&aux1,sizeof(Ficha_t),1,fd);
fread(&aux2,sizeof(Ficha_t),1,fd);
if(strcmp(aux1.title,aux2.title)<0)
{
fseek(fd,-sizeof(Ficha_t)*2,SEEK_SET); //returning 2 positions for overwriting
fwrite(&aux2, sizeof(Ficha_t), 1, fd);
fwrite(&aux1, sizeof(Ficha_t), 1, fd);
fseek(fd,-sizeof(Ficha_t),SEEK_SET); //returning 1 position for checking again with the next film
}
}
}
}
It's not working since it's displaying the same 2 films, Where am I wrong? What could I do?
As mentioned in the comments, you want:
len=ftell(fd) / sizeof(Ficha_t);
to get the number of records in the file.
If you are trying to seek with offsets to the current location, use SEEK_CUR, not SEEK_SET.
I would add a bunch of printfs for ftell(fd) / sizeof(Ficha_t) so you can see that it's doing everything correctly. Also, you could be checking the return values of functions you are calling (they were probably returning errors as you tried to seek before the beginning and read/write there)
Specific code example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
void fbubble_sort(const char *filename, size_t rec_size, bool (*needSwap)(const void *, const void *)){
FILE *fp = fopen(filename, "r+b");
if(!fp){
perror("fopen, r+");
exit(EXIT_FAILURE);
}
void *first = malloc(rec_size);
void *second = malloc(rec_size);
if(!first || !second){
perror("malloc");
exit(EXIT_FAILURE);
}
enum { NO_SWAP = -1};
long last_swap_pos;
do {
rewind(fp);
long pos_1 = 0;//first record position
last_swap_pos = NO_SWAP;
if(0==fread(first, rec_size, 1, fp))
break;
while((pos_1 <= last_swap_pos || last_swap_pos == NO_SWAP) && 1==fread(second, rec_size, 1, fp) ){
if(needSwap(first, second)){
fseek(fp, pos_1, SEEK_SET);
fwrite(second, rec_size, 1, fp);
fwrite(first, rec_size, 1, fp);
fflush(fp);
last_swap_pos = pos_1;
} else {
//exchange buffer
void *temp = first;
first = second;
second = temp;
}
pos_1 += rec_size;
}
}while(last_swap_pos != NO_SWAP);
free(first);free(second);
fclose(fp);
}
#define DATA_FILE "test.dat"
#define GREATERi(type, member)\
bool greater_i(const void *first, const void *second){\
return ((type*)first)->member > ((type*)second)->member;\
}\
/**/
#define GREATERs(type, member)\
bool greater_s(const void *first, const void *second){\
return strcmp((type*)first)->member, ((type*)second)->member) > 0;\
}\
/**/
#define LESSi(type, member)\
bool less(const void *first, const void *second){\
return ((type*)first)->member < ((type*)second)->member;\
}\
/**/
typedef struct {
unsigned v;
} Record;
GREATERi(Record, v)
int main(void){
void make_test_data(void);
void print_test_data(void);
make_test_data();
print_test_data();
fbubble_sort(DATA_FILE, sizeof(Record), greater_i);
print_test_data();
}
void make_test_data(void){
FILE *fp = fopen(DATA_FILE, "wb");
if(!fp){
perror("fopen, w");
exit(EXIT_FAILURE);
}
Record rec;
for(int i = 0; i < 100; ++i){
rec.v = rand() % 100;
fwrite(&rec, sizeof(rec), 1, fp);
}
fclose(fp);
}
void print_test_data(void){
FILE *fp = fopen(DATA_FILE, "rb");
if(!fp){
perror("fopen, r");
exit(EXIT_FAILURE);
}
Record rec;
int cnt = 0;
while(fread(&rec, sizeof(rec), 1, fp)){
if(cnt)
putchar(' ');
printf("%2u", rec.v);
if(++cnt == 10){
putchar('\n');
cnt = 0;
}
}
putchar('\n');
fclose(fp);
}

fread and fwrite a linked list in C

Here is my struct:
struct Car{
char plateNum[10];
char returnDate[7];
int milage;
float income;
struct Car * next;
};
typedef struct Car Car;
I need to use fwrite and fread to store the value and load back in after. Is there an easy way?
To write a LL to a file
// Be sure to have opened the file in binary mode
Car *x = head;
// Walk the list and write each node.
// No need to write the next field - which happens to be the last one.
// v-----------------v size of data before the `next` field
while (x && fwrite(x, offsetof(Car, next), 1, out_stream) == 1) {
x = x->next;
}
To read records from a file into a LL and return the head node:
#include <stddef.h>
// Be sure to have opened the file in binary mode
Car *ReadCars(FILE *in_stream) {
Car Top;
Top.next = NULL; // code only uses the `next` field of Top
Car *previous = &Top;
Car x;
// While another record was successfully read ...
while (fread(&x, offsetof(Car, next), 1, in_stream) == 1) {
// Fill the next field
x.next = NULL;
// Allocate space and copy
previous->next = malloc(sizeof *(previous->next));
assert(previous->next);
*(previous->next) = x;
// Advance to the next
previous = previous->next;
}
return Top.next;
}
The following was written off the cuff by me and has not been tested, so it might need tweaking. Please also note; for the sake of time, I have not tested the return value of fwrite and fread or checked for read errors. YOU SHOULD DO THIS.
Writing the file
int length = lengthOfList(bar); // Assuming you've already created bar as a linked list of Cars
Car foo[length];
putLinkedListIntoArray(&bar, foo);
FILE* fh = NULL;
if((fh = fopen("filename", "wb")) == NULL) {
// Error and die
}
fwrite(&length, sizeof(int), 1, fh);
fwrite(bar, sizeof(Car), length, fh);
fclose(fh);
Reading the file
FILE* fh = NULL;
if((fh = fopen("filename", "rb")) == NULL) {
// Error and die
}
int length;
fread(&length, sizeof(int), 1, fh);
Car foo[length];
fread(foo, sizeof(Car), length, fh);
fclose(fh);
relinkCarList(foo, length);
Functions
int lengthOfList(Car* start) {
int length;
for(length = 0; start->next != NULL; length++) {
start = start->next;
}
return length;
}
void putLinkedListIntoArray(Car* start, Car* array) {
for(int i = 0; start->next != NULL; i++) {
array[i] = *start;
start = start->next;
}
}
void relinkCarList(Car* array, int length) {
for(int i = 0; i < length; i++) {
if(i < length - 1) {
array[i].next = array[i + 1].next;
}
}
}

Resources