Problem while reading structure from binary file - c

As I was trying to write code which is supposed to sort some structures in a file by a specific field (key), I noticed that my function won't read the key correctly. I don't have any idea what I am doing wrong. The code is not complete.
The constr function is supposed to read one structure at a time from the binary file, then only save the varsta array. However, if I try to see what value I obtained, the values are not the ones I gave.
This is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
char nume[20];
char prenume[20];
float varsta;
} PERS;
typedef struct
{
float key;
int nr;
}INDEX;
int constr(FILE *f, INDEX tabl[])
{
int n;
n = ftell(f) / sizeof(PERS);
int i, depl = 0;
PERS p;
for (i = 0; i < n; i++)
{
fseek(f, depl, 0);
fread(&p, sizeof(p), 1, f);
tabl[i].key = p.varsta;
tabl[i].nr = i;
depl += sizeof(PERS);
}
return n;
}
int main()
{
FILE *f;
PERS pers[3];
if ((f = fopen("fis.txt", "wb+")) == NULL)
{
printf("Not ok");
exit(1);
}
int i;
for (i = 0; i < 3; i++)
{
scanf("%s%s%f", &pers[i].nume, &pers[i].prenume, &pers[i].varsta);
fwrite(&pers[i], sizeof(PERS), 1, f);
}
INDEX tabl[3];
int n = constr(f, tabl);
printf("%d", tabl[2].key); //only to check if the key is correct
fclose(f);
}

The key field is a float, but you are trying to print an integer.
Change the penultimate line in your code to
printf("%.2f\n", tabl[2].key);

Related

Unsure of how to store integers from a file to a struct in c

I created two structs to store values in.
struct pair {
int x_pos;
int y_pos;
};
struct coordinates_header {
int length;
struct pair data[1000];
};
typedef struct coordinates_header coordinates;
coordinates *coords;
I then try to store data from a file using
char line[max_read];
int x, y;
FILE *in_file = fopen(filename, "r");
int i = 0;
coordinates *new = (coordinates *)coords;
while (fgets(line,max_read,in_file) != NULL) {
sscanf(line,"%d %d", &x, &y);
new -> data[i].x_pos = x;
new -> data[i].y_pos = y;
i++;
}
new -> length = i;
Then I try to print out the values
int print_struct(void *coords) {
coordinates *new = (coordinates *)coords;
for (int i = 0; i < new -> length; i++) {
printf("%d, %d\n", new->data[i].x_pos, new->data[i].y_pos);
}
return 0;
}
And then I get a segmentation fault
I was wondering if someone could point out where the error is. I have no experience with void but require the flexibility for the structure in some functions I'm going to use.
The file read will have the form
100 30
50 200
.. ..
I believe their are some mistakes in your code:
Instead of using coordinates *coords;, which is just a dangling pointer not pointing anywhere in memory, you should just declare a structure member coordinates coords.
Their is no need for void* pointers in your code. You would be better off using coordinates *coords to access the address of the structure member coordinates coords, instead of void *coords.
You are not checking the return value of FILE *in_file, which could return NULL if not opened properly.
It is always good to check the result of sscanf(), just incase two x and y coordinates were not found on a line.
With these recommendations, you can write your code like this:
#include <stdio.h>
#include <stdlib.h>
#define NUMCOORDS 1000
#define MAXREAD 100
typedef struct {
int x_pos;
int y_pos;
} coords_t;
typedef struct {
coords_t coords[NUMCOORDS];
int length;
} coordinates_t;
void print_struct(coordinates_t *coordinates);
int main(void) {
coordinates_t coordinates;
char line[MAXREAD];
FILE *in_file;
int i = 0;
in_file = fopen("coords.txt", "r");
if (in_file == NULL) {
fprintf(stderr, "Error reading file.\n");
exit(EXIT_FAILURE);
}
while (fgets(line, MAXREAD, in_file) != NULL) {
if (sscanf(line, "%d %d", &coordinates.coords[i].x_pos,
&coordinates.coords[i].y_pos) != 2) {
fprintf(stderr, "two coordinates(x, y) not found.\n");
exit(EXIT_FAILURE);
}
i++;
}
coordinates.length = i;
print_struct(&coordinates);
fclose(in_file);
return 0;
}
void print_struct(coordinates_t *coordinates) {
int i;
for (i = 0; i < coordinates->length; i++) {
printf("%d, %d\n", coordinates->coords[i].x_pos, coordinates->coords[i].y_pos);
}
}

Dynamically allocating array of struct from file C

I have a program that i am trying to write that will open a file named hw3.data, this file will contain a string, a float, an int, and a string on each line. Example: someword 5.4 200000 someword
I do not know the size of the file or the size of the strings within the file. I need to dynamically allocate at array of struct to store the info. I am fairly new to C and have looked over other various questions and articles however none of them really helped me grasp how to solve this.
I figured the best way to go about solving this was to first statically declare a structure. Read the file for the length and then take the information from the static struct and then dynamically allocate.
Here is my code thus far:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
//Static Array of Struct
struct record{
char name[100];
float hp;
int size;
char color[30];
};
//getData from file
int getData(FILE*, struct record[], int currSize){
fp = fopen("hw3.data","r");
if (fp !=NULL){
printf("file Open");
while(3==fscanf(fp, "[^,],%f,%d,[^,]", records[i].name &records[i].hp, &records[i].size, records[i].color)){
currSizef++;
}
} else {
printf("failed");
}
return 0;
}
//First sorting function to sort by FLOAT value
//Second sorting function to sort by INT value
int main()
{
int currSizef=0;
struct record *records;
FILE* fp = NULL;
int choice;
//menu
do
{
printf("\t\tMenu\n");
printf("Options:\n");
printf("Input a number to select option:\n");
printf("1-Sort floats high to low\n 2-Sort floats low to high\n");
printf("3-Sort intergers high to low\n 4-Sort intergers low to high\n");
printf("5-Exit\n");
scanf("%d", &choice);
switch (choice)
{
case 1: /*Print high to low floats*/
break;
case 2: /*print low to high floats*/
break;
case 3: /*print high to low ints*/
break;
case 4: /*print low to high ints*/
break;
}
}while(choice !=5);
return 0;
}
You can try loading the data to a temporary record and use realloc to dynamically extend the data size.
NOTE: if NULL is passed to realloc then realloc will behave like the malloc function for the speciļ¬ed size.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//Static Array of Struct
typedef struct record{
char name[100];
float hp;
int size;
char color[30];
}RECORD;
void record_copy(RECORD *dest, RECORD* src) {
strcpy(dest->name,src->name);
dest->hp = src->hp;
dest->size = src->size;
strcpy(dest->color,src->color);
}
//LoadData from file
RECORD* LoadData(FILE* fp,int *size){
int i = 0;
RECORD temp;
RECORD *data= NULL,*tempptr = NULL;
while( fscanf(fp, "%[^,],%f,%d,%[^,],", temp.name,&temp.hp,&temp.size,temp.color)==4 ) {
if( (tempptr = (RECORD*) realloc( data, sizeof(RECORD) * (i+1) )) )
data = tempptr;
else
return (NULL);
record_copy(&data[i],&temp);
i++;
}
*size = i;
return (data);
}
void record_sort(RECORD *data, int size) {
int i,j;
RECORD temp;
for (i = 0 ; i < ( size - 1 ); ++i)
for (j = 0 ; j < (size - i - 1); ++j )
if( data[j].hp > data[j+1].hp ) {
record_copy(&temp,&data[i]);
record_copy(&data[i],&data[i+1]);
record_copy(&data[i+1],&temp);
}
}
int main() {
FILE *fp = fopen("<fileName>","r");
RECORD *data = NULL;
int i;
int size;
if( fp != NULL ) {
data = LoadData(fp,&size);
}
record_sort(data,size);
for(i = 0;i<size;i++) {
printf("%s:%f:%d:%s\n",data[i].name,data[i].hp,data[i].size,data[i].color);
}
free(data);
return 0;
}
with respect to sorting you can use any sorting algorithm to sort your record. I have given an example for that.

Write and read struct with dynamic arrays and gsl_vectors in C

I have an structure similar to:
typedef struct FOO {
int m,n;
int * am;
gsl_vector * bn;
} foo;
To allocate this structures I do:
foo * bar;
bar=foo_alloc ( 10, 10 );
Where
foo * foo_alloc ( int m, int n ) {
foo * f = (foo*)malloc(sizeof(foo));
f->m=m;
f->n=n;
f->am=(int*)calloc(m,sizeof(int));
f->bn=gsl_vector_calloc(n);
return f;
}
I wish to write bar in a binary file and then read it again... How can I do this?
Thanks!
EDIT:
To be more specific, I tried with
fwrite(&bar,sizeof(*bar),1,file)
but sizeof(*bar) didn't work and by Google search I found that sizeof don't work with this kind of structures with dynamic arrays inside.
Is there a way to obtain the size of bar?
If not, I supouse I have to place an fwrite for each element, but in this case I don't know how to obtain the size of gsl_vector since this is also another structure with a dynamic array inside.
sizeof(*bar) is correct. It's &bar that's wrong. Since bar is a pointer, you shouldn't use the address-of operator.
Also, you've only attempted to write the struct and haven't written the dynamically-allocated array data. Actually, writing the struct is pointless since the addresses will not be valid when the data is read back. You should just write the sizes (m and n) and the array data. When you read it back you need to malloc/calloc the struct and array space again.
Here's a runnable example. I've replaced your gsl_vectors with double to make it easier for other people to run.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int m, n;
int *am;
double *bn;
} Foo;
void foo_write(Foo *f, FILE *file) {
fwrite(&(f->m), sizeof(f->m), 1, file);
fwrite(&(f->n), sizeof(f->n), 1, file);
fwrite(f->am, sizeof(*(f->am)), f->m, file);
fwrite(f->bn, sizeof(*(f->bn)), f->n, file);
}
Foo *foo_read(FILE *file) {
Foo *f = malloc(sizeof(*f));
fread(&(f->m), sizeof(f->m), 1, file);
fread(&(f->n), sizeof(f->n), 1, file);
f->am = malloc(f->m * sizeof(*(f->am)));
f->bn = malloc(f->n * sizeof(*(f->bn)));
fread(f->am, sizeof(*(f->am)), f->m, file);
fread(f->bn, sizeof(*(f->bn)), f->n, file);
return f;
}
Foo *foo_alloc(int m, int n) {
Foo *f = malloc(sizeof(*f));
f->m = m;
f->n = n;
f->am = calloc(f->m, sizeof(*(f->am)));
f->bn = calloc(f->n, sizeof(*(f->bn)));
return f;
}
void foo_print(Foo *f) {
int i;
printf("%d, %d\n", f->m, f->n);
for (i = 0; i < f->m; ++i)
printf("%d ", f->am[i]);
putchar('\n');
for (i = 0; i < f->n; ++i)
printf("%.1f ", f->bn[i]);
}
void foo_free(Foo *f) {
free(f->am);
free(f->bn);
free(f);
}
int main() {
FILE *file;
Foo *bar;
int i;
bar = foo_alloc(5, 10);
for (i = 0; i < bar->m; ++i)
bar->am[i] = i;
for (i = 0; i < bar->n; ++i)
bar->bn[i] = i;
file = fopen("foo.bin", "wb");
foo_write(bar, file);
fclose(file);
foo_free(bar);
file = fopen("foo.bin", "rb");
bar = foo_read(file);
fclose(file);
foo_print(bar);
return 0;
}
You may be able to write and read the gsl_vectors like this (assuming the vectors are independent, i.e., that they don't share data blocks):
void foo_write(Foo *f, FILE *file) {
size_t i;
fwrite(&(f->m), sizeof(f->m), 1, file);
fwrite(&(f->n), sizeof(f->n), 1, file);
fwrite(f->am, sizeof(*(f->am)), f->m, file);
for (i = 0; i < f->n; ++i)
gsl_vector_fwrite(file, &(f->bn[i]));
}
Foo *foo_read(FILE *file) {
size_t i;
Foo *f = malloc(sizeof(*f));
fread(&(f->m), sizeof(f->m), 1, file);
fread(&(f->n), sizeof(f->n), 1, file);
f->am = malloc(f->m * sizeof(*(f->am)));
f->bn = malloc(f->n * sizeof(*(f->bn)));
fread(f->am, sizeof(*(f->am)), f->m, file);
for (i = 0; i < f->n; ++i)
gsl_vector_fread(file, &(f->bn[i]));
return f;
}

getting fscanf to store in structs in C

I have an assignment where I need to get Values of RLC circuits from a file and calculate the resonant frequency however my issue is when I use the fscanf function it reads only the first line of the file and the rest comes out as zeros .
#include <stdio.h>
data
int h;
typedef struct cct
{
int code[50];
float R[50];
float L[50];
float C[50];
} CCT;
int read(CCT cct[], int n_p, FILE* fp){
char temp;
if(fp==NULL){
printf("Error\n");
return -1;
}
fscanf(fp,"%d,%f,%e,%e\n", cct[n_p].code, cct[n_p].R,cct[n_p].L, &cct[n_p].C);
}
int main()
{
FILE* fp = fopen("U://datafile.txt", "rt");
int i = 0;
CCT cct[50];
int size;
while (!feof(fp)) {
read(cct, i, fp);
i++;
}
size = i;
for (i = 0; i < size; ++i)
printf("%d,%0.2f,%0.2f,%0.2f\n", cct[i].code[i], cct[i].R[i],
cct[i].L[i], cct[i].C[i]);
scanf("%d",&h);
fclose(fp);
}
and this is the data file
1,4.36,2.23e-2,4.65e-8
2,4.57,2.01e-2,5.00e-8
3,3.99,2.46e-2,4.82e-8
4,4.09,2.60e-2,4.70e-8
I would appreciate if someone could point put why it only gets the first line. Thanks
CCT is composed of multiple arrays (you have arrays of arrays, which is wrong for the exercise, but that's not the point) and you always write to the element zero of the arrays. For example, cct[n_p].code in fscanf() is the address of the array, which is identical to the address of cct[n_p].code[0]. Then you print code[i] in the output loop, which is blank except for i == 0.
fscanf(fp,"%d,%f,%e,%e", cct[n_p].code, cct[n_p].R,cct[n_p].L, cct[n_p].C);
...
printf("%d,%0.2f,%0.2f,%0.2f\n", cct[i].code[0], cct[i].R[0], cct[i].L[0], cct[i].C[0]);
Something like the following, perhaps
#include <stdio.h>
typedef struct cct {
int code;
float R;
float L;
float C;
} CCT;
int h;
int read(CCT cct[], int n_p, FILE* fp){
char temp;
if(fp==NULL){
printf("Error\n");
return -1;
}
fscanf(fp,"%d,%f,%e,%e\n", &cct[n_p].code, &cct[n_p].R, &cct[n_p].L, &cct[n_p].C);
}
int main(){
FILE* fp = fopen("U://datafile.txt", "rt");
int i = 0;
CCT cct[50];
int size;
while (!feof(fp)) {
read(cct, i, fp);
i++;
}
size = i;
for (i = 0; i < size; ++i)
printf("%d,%0.2f,%0.2f,%0.2f\n", cct[i].code, cct[i].R, cct[i].L, cct[i].C);
scanf("%d",&h);
fclose(fp);
}

Using a char array as input to module to scan a file in C

I am trying to use the getStats function twice - once for each input file. I am supposed to be using a char array called statFile[]to pass as the argument to the prototype to select which file it is to work with. Currently I know how to use one file at a time (by explicit naming the file in the prototype) to make it work, but do not understand how to use it for both inputs. Thanks in advance!
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define AUBURN "auburn2013.txt" //input data files
#define ALABAMA "alabama2013.txt" //input data files
#define NUMGAMES 13
int getStats( char statFile[], int compPass[], int attPass[], int numYds[], int numTD[] );
void analysis( int compPass[], int attPass[], int numYds[], int numTD[], double aveYds[], double pectCmp[], int tdPts[], int numGames[]);
int main(void)
{
int compPass[NUMGAMES],
attPass[NUMGAMES],
numYds[NUMGAMES],
numTD[NUMGAMES];
double bamaStats,
auburnStats,
setAuburn,
setBama;
FILE *au = fopen("auburn2013.txt","r");
FILE *al = fopen("alabama2013.txt","r");
if (al == NULL)
printf("Error Opening File\n");
else if (au == NULL)
printf("Error Opening File\n");
bamaStats = getStats(ALABAMA, compPass, attPass, numYds, numTD);
return 0;
}
int getStats( char statFile[], int compPass[], int attPass[], int numYds[], int numTD[] )
{
int i,
p,
k = sizeof(compPass[NUMGAMES]);
FILE *al = fopen("alabama2013.txt","r");
while (fscanf(al ,"%d %d %d %d", &compPass[i], &attPass[i], &numYds[i], &numTD[i]) !=EOF)
{
i++;
}
printf("Number of Games with data: %d\n", i);
for(p=0; p<8 ; p++)
{
printf("%d %d %d %d\n", compPass[p], attPass[p], numYds[p], numTD[p]);
}
return 0;
}
You are already passing in the stat file name, so need to change:
FILE *al = fopen("alabama2013.txt","r");
to
FILE *al = fopen(statFile,"r");
You can do that like this:
#include <stdio.h>
#include <assert.h>
void print_fname(char **farray, int fnum)
{
int i;
assert(farray != NULL);
for (i = 0; i < fnum; ++i) {
assert(farray[i] != NULL);
printf("file name %d: %s\n", i + 1, farray[i]);
}
}
int main()
{
char *farray[] = {"file1", "file2"};
print_fname(farray, 2);
return 0;
}
Hope can help.

Resources