How could I read a binary file using fread? - c

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.

Related

How can I pass integers read from Text file into struct function?

I want to pass a txt file of integers into the smallest_xcoord struct. I am trying to get the convex hull. My issue is, I keep getting an error when trying. How can i pass integers read from text file into my struct function? I have not included my struct Point but that stores an int x; and int y; (for the convex hull points).
```
//GLOBAL Variable
static int integers[100000];
int load_integers(const char* filename)
{
//int integers[100000];
FILE *fp = NULL;
int value;
int i = -1;
if ((fp= fopen (filename, "r"))==NULL)
{
return -1;
}
while (fscanf (fp, "%u", &value)&& !feof(fp) && ++i <100000)
{
integers[i] = value;
}
fclose(fp);
return i+1;
}
struct Point smallest_xCoord (struct Point points, int numPoints)
{
struct Point points[];
struct Point minX_point = points[0];
int i;
for(i=1;i<numPoints;i++)
{
if ((points[i].x) < (minX_point.x))
{
minX_point = points[i];
}
else if (points[i].x == minX_point.x)
{
if (points[i].y < minX_point.y)
{
minX_point=points[i];
}
}
}
return minX_point;
}
int main(int argc, char *argv[])
{
int num_ints=0;
if (argc <2)
{
fprintf(stderr, "%s <file>\n",argv[0]);
return -1;
}
if ((num_ints = load_integers(argv[1])) <=0)
{
fprintf(stderr, "Error reading from file: %s\n",argv[1]);
return -1;
}
smallest_xCoord(integers, num_ints);
return 0;
}
```
smallest_xCoord(integers, num_ints);
First, you can't pass an integer data type to a "Point" data type parameter.
Second, you can't pass an array integer data type to a single Point parameter.
struct Point smallest_xCoord (struct Point points, int numPoints)
{
struct Point points[];
Third, you can't create a new variable inside of x_Coord with similar name to its parameter because you're re-declaring it.
If you want to pass in an array as a paramater, you gotta use a pointer (*) before its name. For the smallest_xCoord function to work, you need to specify which member of the Point struct you want to compare or assign it to. My suggestion to you is, you probably need to change that global int array variable to a global Point array variable and load it with value from your file which I assume, should contain values for x and y coordinates so that you can compare the loaded global Point array to the one you're providing. Then, change the parameter of smallest_xCoord to "struct Point *points" or "struct Point points[]" since you are passing an array to be compared.

Passing array of struct to function in C

Do I need a * in front of my struct array (in the function arguments) when passing the struct to a function by reference? The reason I am thinking we don't is because an array is essential going to pass the address in which the first object is located.
I feel like I just got lucky my code is working:
#include <stdio.h>
struct member {
char lastName[30];
char gender;
int age;
};
void readAndUpdate(struct member *people[]);
// begin main function
int main(void){
struct member *people[30];
readAndUpdate(people);
} // end main function
// begin function which reads a .dat file and propogates the array with the data in the .dat file
void readAndUpdate(struct member *people[]){
}
I worked on my code some more from the help of the commentors and I have the following which works properly. I accidentally created an array of pointers.
#include <stdio.h>
#define MAXPEOPLE 3
struct member {
char lastName[30];
char gender;
int age;
};
void readAndUpdate(struct member *person, size_t maxpeople);
void populateDatFile();
void displayMembers(struct member *person, size_t maxpeople);
// begin main function
int main(void){
struct member people[2];
populateDatFile(); // program will first populate the .dat file with the given specs
readAndUpdate(people, MAXPEOPLE);
printf("The data was read and input as follows:\n\n");
displayMembers(people, MAXPEOPLE);
} // end main function
// function which displays the entire array of struct members
void displayMembers(struct member *person, size_t maxpeople){
int i=0;
for (i=0;i<3;i++){
printf("%s ", person[i].lastName);
printf("%c ", person[i].gender);
printf("%d ", person[i].age);
printf("\n");
}
} // end displayMembers function
// function which loads the .dat file with hardcoded structs
void populateDatFile(){
struct member person1={"Gates", 'M', 60};
struct member person2={"Jobs", 'M', 55};
struct member person3={"Jane", 'F', 45};
FILE *file;
file = fopen("question3.dat","w");
if(file == NULL)
printf("question3.dat cannot be opened!\n");
else
printf("question3.dat was opened successfully.\n");
fprintf(file, "%s %c %d\n", person1.lastName, person1.gender, person1.age);
fprintf(file, "%s %c %d\n", person2.lastName, person2.gender, person2.age);
fprintf(file, "%s %c %d\n", person3.lastName, person3.gender, person3.age);
fclose(file);
} // end function populateDatFile
// begin function which reads a .dat file and propogates the array with the data in the .dat file
void readAndUpdate(struct member *person, size_t maxpeople){
int i=0;
FILE *file;
file = fopen("question3.dat","r");
if(file == NULL)
printf("question3.dat cannot be opened!\n");
else
printf("question3.dat was opened successfully.\n");
fscanf(file, "%s", &person->lastName);
fscanf(file, " %c", &person->gender);
fscanf(file, "%d", &person->age);
fscanf(file, "%s", &person[1].lastName);
fscanf(file, " %c", &person[1].gender);
fscanf(file, "%d", &person[1].age);
fscanf(file, "%s", &person[2].lastName);
fscanf(file, " %c", &person[2].gender);
fscanf(file, "%d", &person[2].age);
fclose(file);
} // end function readAndUpdate
The code you have is 'OK, but…'. And there are some quite significant "buts" to be worried about.
The first issue is whether what you wrote is what you intended to write. You've defined an array of pointers to structures, but not initialized it at all. You may have intended to define an array of structures rather than an array of pointers, which then alters the rest of the discussion. For the time being, I'm taking what you wrote as "it's OK — that's what I intended to write".
You pass the array to the function correctly. The function has no idea how big an array you passed, though. You should get into the habit of telling functions how big the array is.
You don't reference the array inside the function. That's not all bad; you haven't defined the memory that each of the pointers in the array is pointing to. You'll presumably dynamically allocate the items as you add them, and then reference them correctly using arrows -> and not dots .:
void readAndUpdate(size_t max, struct member *people[max])
{
for (size_t i = 0; i < max; i++)
{
people[i] = malloc(sizeof(*people[i]));
if (people[i] == NULL)
…handle error appropriately…
strcpy(people[i]->lastName, "Unknown");
people[i]->gender = 'N'; // Neuter — unknown
people[i]->age = 0; // Babies only
}
}
int main(void)
{
struct member *people[30] = { NULL };
readAndUpdate(30, people);
return 0;
}
If the number of entries isn't actually fixed, then the readAndUpdate() function should report how many were initialized.
I didn't intend to create an array of pointers.
OK; then the rules of the game change:
void readAndUpdate(size_t max, struct member people[max])
{
for (size_t i = 0; i < max; i++)
{
strcpy(people[i].lastName, "Unknown");
people[i].gender = 'N'; // Neuter — unknown
people[i].age = 0; // Babies only
}
}
int main(void)
{
struct member people[30] = { { "", 0, 0 } };
readAndUpdate(30, people);
return 0;
}
The structures are already allocated, and initialized to all bytes zero. The code in the function uses . instead of -> to reference members. The * goes from the variable and parameter definitions.

Getting core dumps when free() is used

I'm doing a school assignment and the driver was given to me along with the header file. My job is to complete the functions that read data from a text file and then search it for a name and return the email address. It's a huge exercise in using pointers and structures.
The program reads in a text file of names and email addresses then dynamically creates a structure array using malloc(). The struct Card is built of two char pointers and I find the length of the data using strlen(), malloc() memory for that size and assign the struct to the memory address given.
It all seems to work fine until the end after it has printed the name and email and is about to free() the memory. I get an Aborted (core dump) message every time. Don't know what the issue could be.
I've placed a printf() just before the free() to try and track down where the issue is but it appears to be happening either during the name/email printout or just after it happens because my printf() test point that is one line before the free() is never executed.
I'm assuming the driver program is okay and it has something to do with my functions.
Anyone care to take a stab at it?
//Main
#include <stdio.h>
#include <stdlib.h>
#include "lab9utils.h"
int main(int argc, char * argv[]) {
// Variable declarations.
struct Card * cards;
int size;
int k;
char * email;
// Make sure we have 2 extra command-line paramgers.
if (argc < 3) {
printf("Usage: ./lab9.exe <data_filename> <name_to_lookup>");
return 0;
}
// Get the cards and do the lookup.
cards = getCards(argv[1], &size);
email = lookup(cards, argv[2], size);
// Display the output message ("sorry!" or "name -> email").
if (email == NULL) {
printf("Sorry, that name was not in the list of cards.\n");
} else {
printf("%s -> %s\n", argv[2], email);
}
// Free the memory used by the structures.
k = 0;
printf("Test Point#1");
for (k = 0; k < size; k++) {
free(cards[k].name);
free(cards[k].email);
}
printf("Test Point#2");
free(cards);
return 0;
}
// Header
#ifndef LAB9UTILS_H
#define LAB9UTILS_H
struct Card {
char * name;
char * email;
};
struct Card * getCards(char * filename, int * size);
char * lookup(struct Card * cards, char * name, int size);
#endif
// Functions
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lab9utils.h"
struct Card * getCards(char * filename, int * size_return) {
int i,size;
char cTempName[51]={0};
char cTempEmail[51]={0};
size = 0;
// I/O Setup
FILE *fp;
fp = fopen(filename,"r");
// error checking
if(fp == NULL)
{
perror("Error in opening file");
return(NULL);
}
// Input Loop
while(!feof(fp))
{
fscanf(fp,"%s%s",cTempName,cTempEmail);
size++;
}
size=size-1;
fclose(fp);
struct Card * card = (struct Card *)malloc(*size_return * sizeof(struct Card));
fp = fopen( filename ,"r");
// error checking
if(fp == NULL)
{
perror("Error in opening file");
return(NULL);
}
for(i=0;i<size;i++)
{
fscanf(fp,"%s%s",cTempName,cTempEmail);
card[i].name=(char *)malloc((strlen(cTempName)+1));
card[i].email=(char *)malloc((strlen(cTempEmail)+1));
strcpy(card[i].name,cTempName);
strcpy(card[i].email,cTempEmail);
}
fclose(fp);
// loop to confirm data was read
for(i=0;i<size;i++)
{
printf("[ %d ] Name:%s email:%s Total size:%d\n",i,card[i].name,card[i].email,size);
}
*size_return = size;
return card;
}
char * lookup(struct Card * cards, char * name, int size) {
int i;
for(i=0;i<size;i++)
{
if (strcmp(cards[i].name,name)==0)
{
return cards[i].email;
}
}
return NULL;
}
The value of *size_return is garbage, because you are setting it to size only at the end of the function.
Change this:
struct Card * card = (struct Card *)malloc(*size_return * sizeof(struct Card));
To this:
struct Card * card = (struct Card *)malloc(size * sizeof(struct Card));

How to pass struct array into a function and correctly store value in it?

I would like to read a file that has the sample number, values and status(1.1, 23,0). I used a Struct to hold that information. I will pass the function struct array and the file location.
#include <stdio.h>
struct Data_point
{
long sampleNumber;
double value;
int status;
};
int filldata(struct Data_point *a, const char *filelocation)
{
FILE *f;
if((f=fopen(filelocation,"r"))==NULL)
{
printf("You cannot open");
}
fscanf(f, "%ld%lf%d", a.sampleNumber, a.value, a.status);
}
int main(void)
{
struct Data_point data[10];
filldata(data, "/home/alexchan/IntrotoC/rec11/dataPoints.txt");
return 0;
}
But, I got an error saying, "request for member not a structure"...
One problem is that the filldata() is taking a pointer argument. So you use -> to address members not ".". So a.sampleNumber should be a->sampleNumber for example.
Another issue is that filldata() is reading in a single struct, but you are passing it the pointer to the top of the array, which is synonymous with &(data[0]). So this function will just overwrite that first element if you call it repeatedly (which you didn't). If you call it in a loop you will need to pass it in pointers to the individual array members:
for(int i = 0; i < 10; ++i){
filldata(&(data[i]), "/home/alexchan/IntrotoC/rec11/dataPoints.txt");
}
You could actually use data + i as the first arg instead of &(data[i]) but I like the latter as I find it more readable.
struct Data_point *a is your function arugument and you are passing data which is a array. So basically you are trying to acess members from a array which is not a struct.
May be
for( int i=0; i<10;++i)
filldata(data[i],.....)
and
int filldata( struct Data_point a,...) //as you are using a.
fscanf requires a pointer-to-data for each passed argument. Use the AddressOf operator & to get a reference to each struct member:
int filldata(const char *filelocation, struct Data_point *a, int nElements)
{
int n = 0;
FILE *f = fopen(filelocation, "r");
if(f)
{
while (fscanf(f, "(%ld,%lf,%d)", &(a[n].sampleNumber), &(a[n].value), &(a[n].status)) == 3 && n < nElements)
n++;
fclose(f);
}
else { printf("Unable to open '%s'\n", filelocation); }
return n;
}
Now, this function is slightly different to yours. You need to tell it how long the array you're passing in as the "a" parameter is. It will return the number of successfully filled entries.
i.e
int main(int argc, char **argv)
{
struct Data_point data[10];
int n = filldata("C:\\Users\\254288b\\temp.txt", data, sizeof(data) / sizeof(struct Data_point));
printf("%d Data_point's were filled successfully.\n\n", n);
for(int i = 0; i < n; i++)
{
printf("Sample Number: %ld\n", data[i].sampleNumber);
printf("Value: %lf\n", data[i].value);
printf("Status: %d\n", data[i].status);
printf("----------------------------\n");
}
return 0;
}
Do note, my pattern for fscanf expects your file to be like:
(100,1.1,10)(200,2.2,20)(300,3.3,30)(400,4.4,40)
Each set is enclosed in parenthesis.

Problem with structs in c

Hi guys i've got a problem here with structs, the thing is, i've created a struct and then created a function that captures the employee details referenced from that struct. Now the problem comes when i try to call the function in the main. please give me some pointers as to how to call the function. the code is as follows:
typedef struct employeeType
{
char name;
int employeeNumber;
float salary;
float taxPercentage;
}EMPLOYEE;
void enterDetails(EMPLOYEE details)
{
FILE *file;
file = fopen("employees.txt","w");
if(file == NULL)
{
printf("File error!!!");
exit(0);
}
else
{
fprintf(file,"%s",details);
}
fclose(file);
}
void main()
{
enterDetails();
}
I don't know what parameters to pass to the function in the main
I've annotated your code with some other issues to consider
typedef struct employeeType
{
/* THIS IS ONLY ONE CHARACTER... SEEMS WRONG */
/* should be 'char name[someMaxSize]', or 'char *name' */
char name;
int employeeNumber;
float salary;
float taxPercentage;
}EMPLOYEE;
/* As pointed out by 'Cody Gray', this function is called 'enterDetails'
* does it really need to have a parameter at all, or should it be responsible
* for taking the details from the user? Is it an appropriately
* named method for the task it's actually performing
* (would saveDetails be better for example)?
*/
void enterDetails(EMPLOYEE details)
{
FILE *file;
file = fopen("employees.txt","w");
if(file == NULL)
{
printf("File error!!!");
exit(0);
}
else
{
/* THIS IS PASSING A STRUCTURE AS A STRING */
/* You probably want to write out the individual fields instead */
/* fprintf(file, "%s,%d", details.name, details.employeeNumber); etc */
fprintf(file,"%s",details);
}
fclose(file);
}
void main()
{
EMPLOYEE details;
/* populate details somehow then pass it in to the function*/
enterDetails(details);
}
You may also want to consider passing details into the function as a pointer, although that would change your function signature, it would mean that you're not pushing as much information onto the stack.
If you go with the pointer version then:
void enterDetails(EMPLOYEE details)
would become
void enterDetails(EMPLOYEE *details)
and the main would become:
void main()
{
EMPLOYEE details;
/* populate details somehow then pass it in to the function as pointer */
enterDetails(&details);
}
You would also need to change the way you use details within your function, but as I've already said, I believe your fprintf call is broken already.
You can pass the pointer of the struct
void main()
{
EMPLOYEE employee;
.....
enterDetails(&employee);
}
void enterDetails(EMPLOYEE *details)
{
}
You need to pass a reference, not a value... If you pass EMPLOYEE value as in the previous post, it will be copied, the copy will be modified, not the original
void enterDetails(EMPLOYEE* emp) {
// do stuffs
}
void main() {
EMPLOYEE emp;
enterDetails(&emp);
}
void main()
{
EMPLOYEE details;
// get the value of element of struct from scanf or from other way
printf("Enter Name : ");
scanf("%s", details.name); // same for others, change the format specifier according to their data type
enterDetails(details);
}
And struct should be like
typedef struct employeeType
{
char name[]; // should be an array or pointer, to store name
int employeeNumber;
float salary;
float taxPercentage;
}EMPLOYEE;
The first problem is that your structure isn't correct. You can't store the employee's name on the name field since it's only one byte. You have to make it an array (it's simpler on this case) or a pointer to allocated memory.
If you want to make it an array, then you should define the maximum size of the array. In our example we will just make it 100 bytes, it will be more than enough to store any name.
#define MAX_NAME 100
typedef struct employeeType
{
char name[MAX_NAME];
int employeeNumber;
float salary;
float taxPercentage;
}EMPLOYEE;
Second, you're function naming is confusing. enterDetails should just populate the structure you passed. Third, your enter Details should accept a pointer to the EMPLOYEE structure. If you want to pass any value to a function that's going to change it's content, then you can only do that using pointers (or references if you're using C++ but that's basically a pointer). So enterDetails should be,
void enterDetails(EMPLOYEE *details)
{
printf("\nEnter the employee's name ");
scanf("%s", details->name); // this isn't secure since it doesn't perform bound checking.
printf("\nEnter employee number ");
scanf("%d", &details->employeeNumber);
printf("\nEnter employee salary ");
scanf("%f", &details->salary);
printf("\nEnter tax percentage ");
scanf("%f", &details->taxPercentage);
}
And finally, if you want to store the contents of the structure to a file that you want humans to read, then you should format the contents of the structure and dump it onto a file.
int writeToFile(EMPLOYEE *details) /* accepting the structure will work as well but it's faster and efficient to pass the structure's pointer */
{
FILE *file;
file = fopen("employees.txt","w");
if(file == NULL) {
printf("File error!!!");
return 0;
}
fprintf(file, "\nEmployee Name: %s", details->name);
fprintf(file, "\nEmployee Number: %d", details->employeeNumber);
fprintf(file, "\nSalary: %f", details->salary);
fprintf(file, "\nTax Percentage: %f", details->taxPercentage);
fclose(file)
return 1;
}
And main
int main(void)
{
EMPLOYEE details;
enterDetails(&details); // passing the pointer here is a must
if (!writeToFile(&details)) { // passing the pointer since it's faster
printf("\nError writing to file");
return 1;
} else {
printf("\nSuccess!");
return 0;
}
}
And in your case, you don't need to pass any parameters to main. But if you want to know how to pass parameters, then here is a quick example.
int main(int argc, char **argv)
{
int i;
for (i = 0; i < argc; i++)
printf("\n%s", argv[i]);
return 0;
}

Resources