How can I read struct elements from file? - c

Hi I have the following structure:
struct points{
int round[11];
int sum;
};
struct student{
char studid[7];
char *s_name;
char *f_name;
struct points p_points;
};
I am creating an array of structures, each representing an individual student. When I exit my program I will save that array to a file using the following function:
int save_file(struct student *array, int size, const char *filename){
struct student *object=malloc(size*sizeof(struct student));
for(int i=0;i<size;i++){
object[i].f_name=malloc(strlen(array[0].etunimi)+1);
object[i].s_name=malloc(strlen(array[0].sukunimi+1));
strcpy(object[i].f_name,array[0].etunimi);
strcpy(object[i].s_name,array[0].sukunimi);
strcpy(object[i].studid,array[0].opnro);
object[i].points=array[0].points;
}
FILE * file= fopen(filename, "wb");
if (file != NULL) {
fwrite(object, size*sizeof(struct student), 1, file);
fclose(file);
}
for(int x=0;x<size;x++){
free(object[x].etunimi);
free(object[x].sukunimi);
}
free(object);
return 1;
}
When I want to modify the record and load the file I am facing a problem. I don't know how to allocate memory for object[i].f_name and object[i].s_name and I don't know the size of the array in the file. My function looks like this now:
int read_file(const char *filename){
struct student *object2=malloc(sizeof(struct student));
FILE * file= fopen("output", "rb");
if (file != NULL) {
fread(object2, sizeof(struct student), 1, file);
fclose(file);
}
print_situation(object2,1);
return 1;
}
How can I check the size of the array in the file and get the lengths of f_name and s_name from the file in order to allocate the memory properly?

Related

Read/Write to file using void pointers in C

As part of a college assignment, I'm trying to do a simple C app, using Win32 for GUI programming and writing my own dynamic linked list for storing data. Since i could use it for other things later, I'm trying to write a generic list, with "built in" functions for reading and writing data to a file. Now here's my problem
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct tagA{
int t_int;
float t_float;
char t_char;
char t_vchar[30];
} A;
typedef struct tagB{
void *data;
struct tagB *prox;
} B;
int main(){
A dA = {1, 1.5, 'a', "teste123"};
B dB = {&dA, NULL};
dB.data = &dA;
B dB2 = {0};
FILE *fp;
fp = fopen("Data.txt", "w");
size_t dSize = sizeof(dA);
printf("Struct size: %d", dSize);
if(fp == NULL){
printf("nope");
}else{
fwrite(&dB.data, dSize, 1, fp);
}
fclose(fp);
fp = fopen("Data.txt", "r");
dB2.data = malloc(dSize);
fread(&dB2.data, dSize, 1, fp);
printf("\n\n%s", ((A*)dB2.data)->t_vchar);
}
This is the code I'm trying to work out.
The writing works just fine, and I just have to make it to a separate function that receives the pointer to the data struct and its size.
But the reading is off... Once read and printed to the console, the t_int shows a really large number, the t_float has nothing, and so the char and string...
Also, I know its not the best written, most efficient and safe code, but it's just a prototype, something that came into my mind...
Your problem is you are writing the address of &dB.data with fwrite instead of dB.data itself (it is already a pointer). For example:
fwrite(dB.data, dSize, 1, fp);
will resolve your problem (with the like corresponding change to fread).
void *data;
It's not useful to declare data as void*. Declare it as A *data; instead.
fwrite(&dB.data, dSize, 1, fp);
...
fread(&dB2.data, dSize, 1, fp);
dB2.data is a pointer, just use dB2.data. See example below. For better readability you can declare ptr_data instead of data
typedef struct tagA {
int t_int;
float t_float;
char t_char;
char t_vchar[30];
} A;
typedef struct tagB {
A *data;
struct tagB *prox;
} B;
int main() {
A dA = { 1, 1.5, 'a', "teste123" };
B dB = { 0 };
dB.data = &dA;
B dB2 = { 0 };
FILE *fp;
fp = fopen("Data.txt", "w");
size_t dSize = sizeof(dA);
printf("Struct size: %d", dSize);
if(fp == NULL) {
printf("nope");
}
else {
fwrite(dB.data, dSize, 1, fp);
}
fclose(fp);
fp = fopen("Data.txt", "r");
dB2.data = malloc(dSize);
fread(dB2.data, dSize, 1, fp);
printf("\n\n%s\n", dB2.data->t_vchar);
return 0;
}
Your error is at fwrite(), fread(). The first param of them is the pointer which points at the real data you want to write/read.
Since you want to read/write a struct A, the pointer must actually point at struct A, not struct A*.
Just replace
fwrite(&dB.data, dSize, 1, fp);
fread(&dB2.data, dSize, 1, fp);
with
fwrite(dB.data, dSize, 1, fp);
fread(dB2.data, dSize, 1, fp);

SegFault when switching from small test file to 31 mb file

Below is my (incomplete) code for a merge sort project. This worked fine for the parts I have implemented until I switched from the 128 line test file to the 31 mb file that is supposed to be sorted. Now getting a segfault and I'm not sure what to do in order to solve this.
Removed some lines I believe are inconsequential because "mostly code".
struct Record {
char key[KEYSIZE+1];
char data[DATASIZE+1];
};
int threadCount;
int tiers;
static struct ThdArg {
int thdNum; // Thread number 0,1,2,3
struct Record * lowRec; // First record of group or first index of record
struct Record * hiRec; // Last record of group or last index of record
};
int lines;
int tiers;
void *threadFunc(void *var)
{
struct ThdArg temp2 = *((struct ThdArg*)var);
qsort((temp2.lowRec), lines/threadCount, sizeof(struct Record), comparator);
for(int k=0;k<tiers;k++)
if(temp2.thdNum%(int)(pow(2,k+1))==0)
{
qsort((temp2.lowRec), lines/(threadCount/(int)pow(2,k+1)), sizeof(struct Record),comparator);
}
}
int main(int argc, char **argv[])
{
if (argc!=2)
{
printf("Please enter a file name");
return 0;
}
threadCount =8;
tiers =(int)log2((double)threadCount);
pthread_t threads[threadCount];
FILE *recordFile=fopen(argv[1], "r");
char ch;
fseek(recordFile, 0, SEEK_END);
lines = ftell(recordFile);
fseek(recordFile, 0, SEEK_SET);
lines=lines/64;
struct Record recArr[lines];
char buffer[9];
char buffer2[57];
for(int j=0;j<lines;j++)
{
fgets(buffer, 9, recordFile);
for(int i=0;i<8;i++)
{
recArr[j].key[i]=buffer[i];
}
recArr[j].key[8]='\0';
fgets(buffer2, 57, recordFile);
for(int i=0;i<56;i++)
{
recArr[j].data[i]=buffer2[i];
}
recArr[j].data[57]='\0';
}
struct ThdArg temp[threadCount];
for(int i=0;i<threadCount;i++)
{
temp[i].thdNum = i;
temp[i].lowRec=&recArr[(lines/threadCount)*i];
temp[i].hiRec=&recArr[(lines/threadCount)*(i+1)-1];
pthread_create(&threads[i],NULL, threadFunc, (void *)&temp[i]);
}
for(int i=0;i<threadCount;i++)
{
pthread_join(threads[i], NULL);
}
}
The following line:
struct Record recArr[lines];
allocates memory on the stack. Its size is restricted.
If you read a file which can be be very big use malloc:
#include <stdlib.h>
typedef struct {
char key[KEYSIZE +1];
char data[DATASIZE +1];
}Record;
...
recArr = malloc(sizeof(Record) * lines);
...
free(recArr);
You can use the pointer like an array. (In fact, they are the same)

Array of struct from binary file

I have to write a function that will read an array of structures of type Product with data from a binary file.This file contains the number of products - nr and a number of articles of type Product. What's wrong? Thank you in advance!
#define SIZE 30
typedef struc{
int id;
char[SIZE] name;
float price;
}Product;
void create(Product *p, FILE *fptr)
{
p = malloc(sizeof(Product));
fread(p, 1, sizeof(Product), fptr);
}
int main(int argc, char* argv[])
{
FILE *fptr = fopen(argv[1],"rb");
Product *p;
create(p, fptr);
return 0;
}
You have to modify it to something like this:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 30
typedef struct{
int id;
char name[SIZE];
float price;
}Product;
int readproducts(Product *p, FILE *fptr, int nr)
{
if(nr != fread(p, sizeof(Product), nr, fptr))
return -1;
return 0;
}
int main(int argc, char* argv[])
{
FILE *fptr = fopen(argv[1],"rb");
int nr = 0;
if(NULL == fptr) return -1;
// First read number of products from file
// Assuming this number is written as 4 byte integer - at the start of file
if(fread(&nr, 4, 1, fptr) != 1)
return -1;
// Now, read the products
Product *p = malloc(nr * sizeof(Product));
if(-1 == readproducts(p, fptr, nr))
return -1;
fclose(fptr);
return 0;
}
The way you had used malloc in your function was wrong, see here why.
PS. That said, binary writing/reading might not be portable across different computers.

Does a variable type struct need to be an array to store 100 elements?

I am new here so sorry for any misunderstanding.
I am learning Random Access File on C Language. And I am confused about the variable blankClient. It is not an array, but how could Deitel (the author) initialize 100 blanks record using blank Client.
I though it should be like: struct clientdata blankClient[100];
/*Creating a random-access file sequentially */
#include <stdio.h>
struct clientdata {
int acctNum; /*account number*/
char lastname[15]; /*account last name*/
char firstname[10]; /*account first name */
double balance; /*account balance*/
};
int main (void){
int i; /*counter used to count from 1-100 */
/*create clientData with default info */
struct clientdata blankClient = {0, "","", 0.0};
FILE *cfPtr; /*credit.dat file pointer */
if ((cfPtr =fopen("credit.dat", "wb")) == NULL) {
printf("File could not be opened. \n");
}
/*output 100 blank records to file */
else {
for (i=1; i<=100; i++) {
fwrite(&blankClient, sizeof( struct clientdata), 1, cfPtr);
}
fclose (cfPtr);
}
return 0;
}
The code is writing out the same source record 100 times. This is similar to how you can make a hundred clapping sounds with only two hands.

How could I read a binary file using fread?

typedef struct
{
char*title;
char* year;
char* length; //in minutes
} record;
void write(record* list[])
{
FILE* out=fopen("output.bin","a");
if(!out)
{
printf("error"); exit(1);
}else
{
int i;
for (i = 0; i < 1024; i++)
{
if(list[i]!=NULL)
fwrite(list[i], sizeof(record), 1, out);
}
fclose(out);
}
}
void read_back()
{
FILE* input=fopen("output.bin","r");
if(!input)
{
printf("error"); exit(1);
}else
{
record* temp[1024];
fread(temp,sizeof(record)*1024,1,input);
fclose(input);
}
}
How could I read the binary file using fread? Could anyone check if I did correct using fwrite? I want my read_back method to print the content in a struct (title, year etc).
record struct elements are defined as pointers. fread cannot assign those pointers implicitly. For every element in the record struct, the values should be read explicitly and related values should be assigned after memory allocation through malloc.
fwrite will only write memory addresses in this way into the memory, since what record struct has only pointers inside.
There are two options
Define static array definitions like below
typedef struct
{
char title[256];
char year[4];
char length[8]; //in minutes
} record;
or
write record structure elements one by one by with their references.

Resources