making program read certain parts of the file - c

I've a file which contains names and grades of students, and I'd like to write a program which can sort their grades (like midterm 1,midterm 2) according to user choice. I wrote as far as the choice part and opening the file, yet I don't know how to make program read only certain part of the file (like only Midterm 1 grades for example) and sort them only. Here's what I've wrote so far;
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int number;
char name[30];
char surname[30];
int midterm1,midterm2,midterm3;
} Student;
int main()
{
int choice,studentnumber,midterm1,midterm2,midterm3;
char surname;
FILE *cfPtr;
struct student *name;
name = malloc( 10 * sizeof(Student));
if ((cfPtr = fopen("grades.txt", "r")) == NULL)
printf("File cannot be opened.\n");
else {
const int STUDENTSMAX = 100;
Student students[STUDENTSMAX];
int i = 0;
while (!feof(cfPtr))
{
fscanf(cfPtr, "%d%s%s%d%d%d", &students[i].number, &students[i].name,&students[i].surname, &students[i].midterm1, &students[i].midterm2, &students[i].midterm3);
printf("%4d%15s%15s%10d%10d%10d\n", students[i].number, students[i].name,students[i].surname, students[i].midterm1, students[i].midterm2, students[i].midterm3);
i++;
}
printf("What would you like to do? \n"
"1- Sort according to midterm 1\n"
"2- Sort according to midterm 2\n"
"3- Sort according to midterm 3\n"
"4- Exit\n");
scanf("%d",&choice);
while (choice != 4);{
switch (choice) {
case 1:
qsort(students,10,sizeof(int),comp);
for (i=0; i<9; i++)
printf("%4d%15s%15s%10d%10d%10d\n", students[i].number, students[i].name,students[i].surname, students[i].midterm1);
fclose(cfPtr);
}
system("PAUSE");
return 0;
}

Given what might be a somewhat free form text file (based on the shown code), it probably makes sense just to read the entire file (somewhat like you are already doing) and only use the parts that you need. If the text file has a very specific format with fixed offsets, you could seek to certain locations in the file and read a specific column value, then seek to the next offset and read the column value from the next row. But that is probably more trouble than it is worth and would not be much more efficient (if at all).
Having said that, to sort the results, you probably need the entire file anyway. For example, if you just read and sort the "midterm 1" value, then the result would just be sorted grades without any associated name and student number. So without knowing more about the goal, you might consider creating a struct that can hold a single row (student number, name, surname, midterm1, etc.). Then create an array of those and read each row into an element of the array. If you know how many rows exist up front, you can allocate the array in one chunk, otherwise you might need to reallocate it as you go to grow it.
Once you have read the entire array, you could sort based on the desired value (e.g., with qsort.
Having mentioned that, there a few problems/issues with the existing shown code:
The second printf has fewer format specifiers (%s) than parameters.
The third printf with the "What would you like to do" question is missing the closing paren.
The fprintf is incorrect; it should have a file handle as the first parameter. I suspect, though, that it was maybe meant to be printf?
The final while loop has an extraneous semicolon (;) following its closing paren, which means that it has an empty body rather than the apparently intended printf and switch statement.
The switch statement is a bit odd as written. I assume that is the "unfinished" part. But including the fclose in it seems strange. It should probably be at the end of the main else.
Using system("PAUSE"); is maybe not the best choice. Perhaps using getch would make more sense to pause for input.
Edit Here is some additional information in response to your comment asking for more details. This sounds like homework to me, so it doesn't seem right just to give the answer. But here is one way to do it:
Define a struct with the 6 items that are in the file (basically put in the 6 variables that you currently have defined as local variables).
Declare a local variable (e.g., grades) as a pointer to struct that you defined.
Use malloc to allocate memory and assign it to the pointer just mentioned. The amount of memory is perhaps the trickiest part of this whole thing. The size parameter to malloc will be something like numRecs * sizeof( yourstruct ). The question is what numRecs should be. If this is an assignment and you were told how many records there would be (a maximum), then just use that. If, though, it is "unknown", then there are a couple of ways of dealing with that. One is to just guess at a number (e.g., 100) and then while reading them in a loop use realloc if you exceed 100. The other alternative (probably less efficient) would be to use two loops - read through them once without storing them but just count them and then allocate the known size and read them again. I would use the realloc version.
Replace the use of the local variables with the array (that was malloced). For example, instead of studentnumber you would use grades[arraypos].studentnumber. While you read them in, keep a counter of how many there are. You can then use qsort to sort the array.
Edit 2
Your struct definition looks correct except that the FILE *cfPtr; member should not be in it. It should still be a local variable.
For ease of use, you can define the struct as typedef struct { ... } Student;. That way you can just use Student instead of struct Student in the code. Note that I capitalized the name (personal preference in naming to make it not look like a variable name).
For the malloc, you are close. But as written, it is allocating space for a single record. You would need something like this: name = malloc( 50 * sizeof( struct student )); (or malloc( 50 * sizeof( Student )); if you change it to use the typedef. That assumes there would not be 50 or fewer records to read from the file.

Related

How to reference a pointer to structure inside another structure in C

I have an assignment in C that basically asks for some sort of interface/database for a supposed animal shelter, and we were given these 2 structures:
typedef struct age
{
int years, months;
}age;
typedef struct pet
{
int id;
char* sex;
char* breed;
age* pet_age;
}pet;
The interface has to have several functions, like adding a new pet (in our case dogs specifically), removing based on ID, searching for all pets of the same breed and changing the name of a breed entirely, and it all has to be done dynamically using a pet* array as well as the malloc and realloc functions. The entries have to be written in a file and also read from it, but that's something I'll figure out after I figure out how to handle the functions regarding my dynamic array first.
To get to the point, I am having trouble understanding how to scan/reference an instance's pet_age. I've tried it a myriad different ways but I don't understand what's wrong, really. The program crashes/exits after I scan the months element.
Here is the insertion function I have implemented thus far. While not correct, the main source file still compiles.
void addPet(pet *p){
if(i=1){ //First time activation check.
p=malloc(k*sizeof(p));
if(!p){
printf("\nUnable to allocate memory...");
exit(0);
}
}
p[i].sex = malloc(sizeof(char)*1);
p[i].breed = malloc(sizeof(char)*20);
p[i].pet_age =malloc(sizeof(int)*2);
p[i].id = i; //Autogenerated ID
printf("\n%d\n", p[i].id);
printf("Insert pet's breed:"); //Scan breed
scanf("%s", p[i].breed);
printf("Insert pet's sex:"); //Scan sex
scanf("%s", p[i].sex);
printf("Insert pet's age in years:"); //Scan years
scanf("%d", p[i].pet_age->years);
printf("\n%d\n", p[i].pet_age->years);
printf("Insert pet's age in months:"); //Scan months
scanf("%d", p[i].pet_age->months);
printf("\n%d\n", p[i].pet_age->months);
i++; //Incrementing counter
if(i==k){
k+=10;
p=realloc(p, k*sizeof *p); //Size check
}
}
For now there is a basic initialization in the event that this is the first insertion. Then I allocate memory for each element of the structure (to the best of my understanding), and scan every element with a scanf (I pasted some printf checks to see what was actually scanned). Then at the end I increment the i counter, followed by a size check to allocate 10 more places for the array in the event that i==k.
For the sake of continuity, here is my main function as well (basic menu and all):
int i=1; //Counter
int k=10; //Default max entries
int main(int argc, char *argv[]) {
FILE *fp;
int choice;
pet *petarray;
//Menu that lists every option.
while(1){ //Endless loop that ends only if you choose to exit through the 5th option.
printf("\n\n Menu:");
printf("\n=========");
printf("\n1. Insert information for a new pet.");
printf("\n2. Delete a pet record based on pet's ID.");
printf("\n3. Search a pet record based on pet's breed.");
printf("\n4. Update pet's breed name.");
printf("\n5. Exit.\n\n");
scanf("%d", &choice);
switch(choice)
{
case 1:
addPet(petarray);
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
printf("Exiting program...");
exit(0);
}
}
return 0;
}
Apologies if this seems amateur, I'm quite the rookie and still learning. Thanks in advance.
It compiles, but don't you get a long list of warnings? If you don't, you should turn on warnings.
But let's have a look.
void addPet(pet *p)
{
if (i = 1)
You are not comparing (global!) i to 1 here. You are assigning to it. This if statement can only take the true path because of that. When you assign to i, the result of the assignment is the value you assign, so you are testing if (1) here. You want to take this path only if i is 1, I guess, so you should use if (i == 1).
{ //First time activation check.
p = malloc(k * sizeof(p));
Well, it is every time, but we have fixed that now. What do you want p to be, here? An array of k pets? That is not what you are allocating memory for. You are allocating space for k times sizeof(p) and since p is a pet *p, that means you are allocating space for k pointers to pets. Not pets. That, of course, is a problem since p is a pointer to pet and not a pet **. You have most likely allocated too little memory here.
This, unfortunately, is usually not something you will get a warning about. You can give malloc() any size, and it will give you that amount of memory. If you asked for the wrong amount, you get the wrong amount. I think you wanted malloc(k * sizeof *p) here. That allocates space for k of the kind of objects p points to, and that means you can use p as an array of k of that type. You do it the right way when you realloc() later, so this is probably just a quick mistake, but it can easily destroy everything at runtime.
p[i].sex = malloc(sizeof(char) * 1);
p[i].breed = malloc(sizeof(char) * 20);
Two issues here. First, are you sure that p has an entry i? If you fixed the allocation above, then the p you allocated the first time has room for k pets, but this could be any p we have called the function with, so we don't know about this one at all. There is absolutely no guarantee that it is valid to access p[i]. Your reliance on the two global variables will generally make this very dodgy; you simply cannot assume that the function is called with the specific pointer you allocated memory for a bit earlier.
Second, for the string allocation, there are a few red flags as well. sizeof(char) is always 1, so you don't need it. It isn't wrong, really, it just looks odd. And are you absolutely sure that you are allocating enough memory? For p[i].sex I find it highly unlikely. You are getting space for exactly one char. If you only want one char, then that is fine, but you you should probably declare sex a char instead of a char *. If you plan to put a string in p[i].sex, then it will have to be the empty string and nothing longer, because you have only room for the '\0' terminal in a buffer of length 1.
With
p[i].pet_age = malloc(sizeof(int) * 2);
it might technically work, but I don't think the standard guarantees it. You are allocating space for a struct age, and that struct holds two int. They will align the right way, so there shouldn't be any padding, and therefore it should work, but it is flaky as hell.
If you want to allocate space for a struct, then do that. malloc(sizeof(struct age)) gets the job done. Even better, gets the type from the variable you are allocating space for:
p[i].pet_age = malloc(sizeof *(p[i].pet_age));
If p[i].pet_age is a struct age *, then *(p[i].pet_age) is a struct age, and it is the size of that we want.
Then we read in the data.
printf("Insert pet's breed:"); //Scan breed
scanf("%s", p[i].breed);
Here we can have a buffer overflow.
printf("Insert pet's sex:"); //Scan sex
scanf("%s", p[i].sex);
Here we are guaranteed one, because we need to write the terminal zero into sex after we put the data there.
printf("Insert pet's age in years:"); //Scan years
scanf("%d", p[i].pet_age->years);
printf("\n%d\n", p[i].pet_age->years);
printf("Insert pet's age in months:"); //Scan months
scanf("%d", p[i].pet_age->months);
printf("\n%d\n", p[i].pet_age->months);
Since scanf needs to store the data it reads somewhere, it needs a pointer to where it should put it. You are providing integers. (Your compiler definitely should have warned you here). You should use &p[i].pet_age->years to store an integer in p[i].pet_age->years, and the same for months.
Then we get to what I think is probably the worst error in the code.
if (i == k)
{
k += 10;
p = realloc(p, k * sizeof *p); //Size check
}
I'm not going to comment on the global variables again, but rather the local variable. This realloc potentially destroys the memory that p pointed at. I don't care that it can return NULL and you don't check; I doubt that this is happening in your program, but someone called addPet with a pointer, and they have no way of knowing if that pointer is valid again after calling. They have to consider it lost. It won't be freed if addPet() doesn't free it (and it doesn't), and they cannot safely do it themselves. The new memory you allocate doesn't get back to the caller in any way. Assigning to the local variable in addPet() doesn't affect any caller's variable. This realloc() is dangerous. The caller will absolutely lose the existing memory and has no way of obtaining the new memory.
Any of these issues can be the cause of your current problem; the others can be the cause of future problems.

Dynamic fscanf into an array

I am trying to place some text into a structure part of my array is a array which takes part of the text.
For example my structure is:
struct animal
{
char animal_Type[11];
int age;
int numberOfLegs;
int walksPerDay;
char favoriteFood[];
};
I will then have input such as:
dog,2,4,2,biscuits,wet
cat,5,4,0,biscuits,wet,dry,whiskers
bird,1,2,0,birdseed,biscuits,bread,oats,worms,insects,crackers
I have a working solution that places all the values up to walks per day into the structure, however I want to be able to place the food items into Favorite food. I have a dynamic array for this, but i'm not sure how to read remaining text into the favoriteFood array.
The code used is:
fp = open("animals.txt","r");
struct animal *animal = malloc(sizeof(sturct animal)*3);
int i = 0;
if(fp != NULL) {
while(i < 3) {
fscanf(fp,"%s %d %d %d %s",
animal[i].animal_Type,
animal[i].age,
animal[i].numberOfLegs,
animal[i].walksPerDay,
animal[i].favoriteFood); // need to be able to enter the string of food into here
i++
}
How would I go about doing this?
First of, your struct doesn't match what you've said in the comments.
char favoriteFood[];
The above is an array of char, so couldn't possibly hold a list of favourite foods except if it were one string. And since the size of the array is unspecified, you'd not be able to fill it like you have been either. Instead what you actually want is
char **favoriteFood;
unsigned int favoriteFoodSize;
That will let you create an expanding list of strings to fit whatever data you need to accommodate.
As for reading it in, the best way would be to read the entire line in using fgets and then use something like strtok to break the line up by your separator character. First define a very large string to hold the entire line and a char * to hold each field.
char buffer[1024];
char *token;
And then to the main loop would be something like this:
while(fgets(buffer,1024,fp)) {
token=strtok(buffer,",");
strcpy(beasts[i].animal_Type,token);
token=strtok(NULL,",");
beasts[i].age = atoi(token);
/* etc... */
}
You'd need to check whether token is ever NULL to cope with the possibility of short lines and handle it accordingly. And also make sure that the string copied into animal_Type isn't longer than 10 characters...or alternative make it a char * so you can have any size of string.
For the favoriteFood, you'll need to use realloc to increase the size of it to accommodate each new food added and keep going through the string until you run out of tokens.
token=strtok(NULL,",");
if(token) {
beasts[i].favoriteFood=malloc(sizeof(char *));
beasts[i].favoriteFood[0]=strdup(token); // Need to index using 0 as favoriteFoodSize won't have a value yet
beasts[i].favoriteFoodSize=1;
token=strtok(NULL,",");
while(token) {
beasts[i].favoriteFood=realloc(beasts[i].favoriteFood,(beasts[i].favoriteFoodSize+1)*sizeof(char *));
beasts[i].favoriteFood[beasts[i].favoriteFoodSize]=strdup(token);
beasts[i].favoriteFoodSize++;
token=strtok(NULL,",");
}
}
The last food will have a \n in it as fgets keeps it in the buffer it reads, so you could use that to tell if you've finished processing all the foods (you will also need to remove it from the last food). Or if you don't have it, you know the line was longer and you'll need to read more in. But that seems unlikely based on your sample data.
And since you're doing lots of memory allocation, you should ensure that you check the values returned to make sure you've not run out of memory.

Loading structure from txt file to dynamic array

I have trouble with saving and loading data from .txt file to dynamic array.
My whole program is based on switch statement.
I will only paste here case which is responsible for allocating memory for array and calling function to fill it with structure. And functions for saving and loading data.
Code looks like this
case 1:
system("cls");
printf("Enter amount of students you want to put in data base\n");
scanf("%d",&number_of_students);
student=(data*)malloc(number_of_students*sizeof(data));
adding_students_to_base( number_of_students); // its a simple functions based on for loop. I don't think that posting it here is necessary
break;
and functions:
void saving_base_to_file(int amount_of_students)
{
FILE *file;
system("cls");
printf("Saving base to file!\n");
file=fopen("database.txt","wb");
fprintf(file,"%d",amount_of_students); // function also saves amount of students in base
fwrite(student,sizeof( data),amount_of_students,file);
fclose(file);
_getch();
system("cls");
}
void loading_base_from_file()
{
FILE *file;
system("cls");
printf("Reading base from file\n");
file=fopen("database.txt","rb");
if (file!= NULL) {
fscanf(file,"%d",&number_of_students);
fread(&student,sizeof( data),number_of_students,file); //number_of_students is global variable
student=(data*)malloc(number_of_students*sizeof(data));
fclose(file);
}
else
{
printf("File does not exist!.\r\n");
printf("File have to be named ""database.txt"" !!!\n");
}
_getch();
system("cls");
}
(Function saving_base_to_file takes number_of_students as input argument.)
Problem appears when i want to use my "loading_base_from_file" function
For example, when i want to save one student with student_id "123456" named "Greg" "Tesla", file contains this:
database.txt. Function saving_base_to_file also saves amount of students in base. But when i start my program again (or do it in one program run) and try do load data from file, my function "print_base" prints this:
result
I think that there is a problem with "putting" data into array, but i don't know what exactly is wrong.
Could you tell me why is this happening and how to fix it?
Your use of student indicates that it's a pointer. That means when you use the address-of operator & on the variable you get the pointer to where the variable is stored, not a pointer to the memory you allocate. The type of &student is data ** not data *.
That alone will lead to undefined behavior as you write over data somewhere in memory where it should not be, but is not the only problem. The other problem is that you allocate memory for student after you read the data from the file, making student point somewhere else completely and also making you lose the data you just read.
First allocate memory, then read into student (and not &student).
There is yet another problem too, and that is you mix text data and binary data. The initial number you read as the number of records in the file will not be correct when you read it, if the first element in the structure contains a value that can be parsed as a textual digit.
You need to fwrite the number, and fread it back.

prob either from writing or reading to/from binary file in c

if you need any info further from what i ve posted below please let me know so i can update the post.
What i save to the file is the fields of the struct below. Because the file has no registrations in the beginning i have to initialize it by setting the flag to 0.
struct pedia
{
int code;
char descr[50];
int TM;
int pos;
int flag;
};
I open a file at/from which i can both write/read using
if((fp=fopen(name,"wb+"))==NULL)
user gives the maximum number of registrations that can be saved in the file
later i send the pointer fp in a function to initialize the file like this
void initialization2(FILE *f,int size)
{
int i;
struct pedia *ptr;
ptr=(struct pedia *)malloc(sizeof(struct pedia));
for(i=0;i<size;i++)
{
ptr->code=i;
strcpy(ptr->descr," ");
ptr->TM=-1;
ptr->pos=-1;
ptr->flag=0;
fwrite(ptr,sizeof(struct pedia),1,f);
}
}
my problem is right here
if(field.flag==0)
the statement in the if is never true
My guess is that i do something wrong when i initialize the file content or when i m reading it.Any help?
void fileupdate(FILE *f,int filesize)
{
struct pedia field;
int k,key;
char opt[3];
while(1)
{
puts("\nUPDATE\n");
puts("\nType the # of the registration you want to update\n\nkey:");
scanf("%d",&key);
getchar();
if(key>0 && key<=filesize)
{
fseek(f,sizeof(struct pedia)*key,0);
fread(&field.code,sizeof(int),1,f);
fread(&field.descr,sizeof(char)*50,1,f);
fread(&field.TM,sizeof(int),1,f);
fread(&field.pos,sizeof(int),1,f);
fread(&field.flag,sizeof(int),1,f);
if(field.flag==0)
{
.....
}
}
else
puts("\nplease type a key between 0 and the number of the file registrations\n\n");
}
}
There are couple of problems in your code:
You can't read struct fields one by one because there may be (an usually there is) padding added between struct fields. This means that if you have two fields in your struct - char (say, 1 byte large) an int, say 4 byte large, it's very likely that your struct will be 8 bytes large with 3 "empty" bytes between the char and an int. The padding is added because of alignment issues which are out of scope of this post. In order to fix this, you should read whole struct at once, just like you write it at once. Note, however, that since padding may be different on different architectures/C implementations, in this case you won't be able to freely move your files from machine to machine and expect your program to work. The other option, more portable, is to write the struct field by field. But also then, you have to consider what happens if you try exchanging you file with two machines, one with 4 byte int and one with 8 byte (quite unusual but possible). Yeah, C is actually hard to get it right.
Your key value validation is wrong. key should be allowed to be equal 0 since this is where first record will be stored. It should never be larger than (filesize/sizeof(struct pedia))-1, though.
Last argument of lseek should be one of SEEK_SET, SEEK_END, or SEEK_CUR, not 0 as you have no guarantee that other C implementation will use the same number to represent SEEK_SET. The truth is, we can't really know what 0 means in case of your C implementation an since you don't check return value of the call, we can't even know if 0 is valid value there.
Not to mention lack of error handling.. and that one actually comes in handy when your code is misbehaving.
Your reading and writing are out of sync, probably because there is padding in the structure, which is not being accounted for when you read individual structure elements. The individual structure elements are read, advancing the file position only by the size of the actual data, rather than by the size of the data+padding. Read the entire structure from the file in one read operation, just the complement of what you do to write the data.

C - Build dynamically allocated array of pointers to structures filled with input from file

I need to build an array of pointers to dynamically allocated structures (DBrecord) and fill that array with input from another file. Not sure how to approach this.
The data file will have the number of entries first, followed by entries in a specific order.
numOfEntries
lastName firstName studentID year gpa expGradYear
example:
1
Doe John 12345678 senior 3.14159 2015
Here's the code I have so far:
class.h
typedef enum {firstYear, sophomore, junior, senior, grad} class;
main.c
#include <stdio.h>
#include <stdlib.h>
#include "class.h"
int main(){
//DBrecord is name for structure
struct DBrecord{
int DBrecordID; //ID for each entry, range 0-319
char *last; //student last name
char *first; //student first name
char studentID[8]; //student ID
int age; //student age
class year; //year in school
float gpa; //GPA
int expGradYear; //expected graduation year
};
int numEntries; //total number of entries, first num in data file
struct DBrecord **ptrToDB;
//scan first int in data file and assign to numEntries
scanf("%d", &numEntries);
//allocate memory for structures, each is 36 bytes
*ptrToDB = malloc (sizeof(struct DBrecord) * numEntries);
//free allocated memory
free(ptrToDB);
//build an array of pointers to dynamically allocated structures
//fill that array with input from data file
//build 7 arrays of pointers to DBrecords, one for each field except DB ID
//sort each a different way
//note the 7 arrays are pointers, no copying
//print each of the 7 sorted arrays
return 0;
}
I can give you some snippets on how to look at this problem.
First - I would avoid using class name for any variable, because in many object-oriented programming languages (including C++) it is a keyword and can't be a name of variable.
Structure DBrecord
It might be a good idea to use typedef. Then you could declare a struct variable without using "struct DBrecord", just "DBrecord". But that's optional. This is how it would look:
typedef struct {
int DBrecordID; // ID for each entry
char *lastName;
char *firstName;
char studentID[8];
...
} DBrecord;
Loading from file
In this homework you have the number of records at the beginning of the file, so you don't need to take "extra" care about it. Just load it.
Let's assume the file is like this:
2
Doe John 12345678 senior 3.14159 2015
Carl Boss 32315484 junior 2.71 2013
Therefore the first thing you do with your file is to open it.
Portable way of working with files is by using FILE pointer. Let me show it (stdio.h must be included):
FILE *filePtr; // Define pointer to file
if((filePtr = fopen("records.txt", "r")) == NULL) // If couldn't open the file
{
printf("Error: Couldn't open records.txt file.\n"); // Printf error message
exit(1); // Exit the program
}
Then you can read from your file by line using fgets() to read by lines or fgetc() to read by characters. This is how you can read number of records (remember that it's on the first line and we've just opened the file - we are at the beginning of the file):
char buffer[100]; // Define the buffer
fgets(buffer, 100 /* size of buffer */, filePtr);
Now buffer contains the first line (without \n character) - number of records. Continue with converting the num's characters into integer (here stdlib.h also has to be included):
int numOfRecords = atoi(buffer);
Allocating enough DBrecords
Now you know the number of records, you can allocate enough space for them. We will use array of pointers.
DBrecord **recs;
recs = (DBrecord **) malloc(sizeof(DBrecord *) * numOfRecords);
Now we have created array of pointers, so now we need to allocate every individual pointer as a DBrecord. Using cycle:
int i;
for(i = 0; i < numOfRecords; i++)
{
recs[i] = (DBRecord *) malloc(sizeof(DBrecord));
}
Now you can acces array elements (= individual records) like this:
recs[0]->lastname /* two possibilities */
*(recs[0]).lastname
an so on.
Filling array with values from file
Now you know everything to get the homework done. This way you fill the array:
int i;
for(i = 0; i < numOfRecords; i++)
{
// Content of cycle reads one line of a file and parses the values into recs[i]->type...
/* I give you small advice - you can use fgetc(filePtr); to obtain character by character from the file. As a 'deliminer' character you use space, when you hit newline, then the for cycle continues.
You know the order of stored values in the file, so it shouldn't be hard for you.
If you don't get it, let me now in comments */
}
Is it somehow clearer now?
EDIT: File name as main's argument
There are usually two ways of 'passing' arguments (values) to a program. They are:
./program < records.txt // Here the file's name is passed to program on stdin
./program records.txt // Here the file's name is passed as value in `argv`.
If you can choose, I strongly recommend you the second one. Therefore you need to have main defined as this:
int main(int argc, char *argv[]) // this is important!
{
// code
return 0;
}
argc is integer which says, how much arguments were passed to the program. argv is array storing them. Remember, that the first argument is name of the program. Therefore if you need to check for it, do it:
if(argc != 2)
{
printf("Number of arguments is invalid\n");
exit(1); // exit program
}
Then you only put argv[1] into fopen function, instead of the string "records.txt".
EDIT 2: Reading file's name from stdin
Another approach must be done, if the name of the records file is passed to the program via ./program < records.txt, which means that "records.txt" (without quotes) will be passed (redirected) to program's standard input.
Therefore to handle that, you can do this:
char filename[50]; // buffer for file's name
scanf("%s", &filename); // reads standard input into 'filename' string until white character appears (new line, blank, tabulator).
Then you have your desired file's name in filename string.
Where to start, where to start.....
//allocate memory for structures, each is 36 bytes
mem = (double *)malloc(36*numEntries);
malloc should be malloc (sizeof (struct DBRecord) * numEntries);
don't cast the result of malloc
2a. you forgot stdlib.h
Why include class.h?
your array of pointers are not double, they are instead
struct DBRecord **ptrToDB;
*ptrToDB = malloc (sizeof (struct DBRecord) * numEntries);
This should get you started.
Next, free() should be the last thing you do before leaving your function (and yes, main is a function)
You'll have to insert some code for the next part, I can't do the homework for you.

Resources