filling array of pointers from file in c - c

I want to read data which is written in fprintf(fp,"%s %s %s\n", p->name,p->surname,p->tc); format. I created struct patients **p in with
struct patients **create_array(struct patients **ptr,int length){
int i;
ptr=(struct patients **)malloc(length*sizeof(struct patients));
return ptr;
}
function above create array of pointers and give it to main. Main calls read_file() function to read data from file which is written in known format. But my data is not filled when i try to print them in main it prints meaningless things. I thought problem in reading data that's why i put only reading function. What is my problem? All suggestons are welcome.
#include<stdio.h>
struct patients
{
int importance;
char name[10], surname[10], tc[11];
};
FILE *file_opening(char x[])
{
return (fopen(x,"w+"));
}
writing_file (FILE *fp, struct patients *p)
{
fprintf(fp,"%s %s %s\n", p->name,p->surname,p->tc);
}
struct patients **read_file (FILE *fp,struct patients **p)
{
int i=-1;
do{
i++;
}while(fscanf(fp,"%s %s %s",p[i]->name,p[i]->surname,p[i]->tc) !=EOF);
return p;
}
void show_all_patients(struct patients **p, int start_index, int length){
int i;
for(i=start_index;i<length;i++)
printf("%s %s %s",p[i]->name,p[i]->surname,p[i]->tc);
}
struct patients **create_array(int length){
return (struct patients **)malloc(length*sizeof(struct patients));
}
int menu(void){
int choice;
printf("1)take patient\n2)show all patients\n3)exit");
scanf("%d",&choice);
return choice;
}
main(){
int i=0,j,choice,cured_patient=0,length=1;
FILE *fp;
struct patients **ptr;
char file_name[40]="patient_list.txt";
ptr=create_array(length);
fp=file_opening(file_name);
ptr=read_file(fp,ptr);
do{
choice=menu();
if(choice==1){
printf("%s %s %s\n",ptr[i]->name,ptr[i]->surname,ptr[i]->tc);
i++;
}
else if(choice==2){
show_all_patients(ptr,i,length);
}
}while(choice!=3);
for(j=i;j<length;j++)
writing_file(fp,ptr[j]);
fclose(fp);
}

Problems with the code:
There is no return value of writing_file. Add void as the return type.
void writing_file (FILE *fp, struct patients *p)
{
fprintf(fp,"%s %s %s\n", p->name,p->surname,p->tc);
}
You need #include <stdlib.h>.
Without that the return value of malloc is assumed to be an int, which can result in strange problems.
Syntax errors:
Given your definition of ptr, the lines
ptr=create_array(length);
and
ptr=read_file(fp,ptr);
are syntactically invalid. I get the following errors with gcc:
soc.c: In function ‘main’:
soc.c:58:7: error: assignment to expression with array type
ptr=create_array(length);
^
soc.c:60:7: error: assignment to expression with array type
ptr=read_file(fp,ptr);
If your compiler does not report errors on those two lines, it's time to use a different compiler.
Reading and writing to the same file
You are using the same FILE* to read from and write to. It's not clear whether you meant to do that or it was an error on your part.
When you open the file using:
return (fopen(x,"w+"));
the contents of the file are truncated. See http://en.cppreference.com/w/c/io/fopen for more info. Pay special attention to the table under Parameters. It says:
"w+" | write extended | Create a file for read/write | destroy contents | create new
If you want to just read the data from the file, use
return (fopen(x,"r"));
If you want to read the data from the file and write back the data to it, read it first using the above mode, close the file, then reopen it using:
return (fopen(x,"w"));
Handling the array of patients
I think you should use:
FILE* fp = NULL;
int length=10;
struct patients *ptr = NULL;
ptr=create_array(length);
fp=file_opening(file_name);
read_file(fp, ptr, length);
Adjust the rest of your code appropriately.
Add code to deallocate memory
Every call to malloc should have a corresponding call to free. I would add
void delete_array(struct patients *ptr)
{
free(ptr);
}
and call it from main before the end of the function.

Things that I would change.
Return value and input arguments of create_array.
The function can also be simplified to:
struct patients* create_array(int length)
{
return malloc(length*sizeof(struct patients));
}
Return value and arguments to read_file
struct patients* read_file (FILE *fp ,struct patients *p)
{
int i=-1;
do
{
i++;
} while(fscanf(fp, "%s %s %s",p[i].name, p[i].surname, p[i].tc) != EOF);
return p;
}
Make sure that you provide the maximum number of characters to be read. Otherwise, you might end up reading more than the array are capable of holding.
Change
} while(fscanf(fp, "%s %s %s",p[i].name, p[i].surname, p[i].tc) != EOF);
to (given the size of the arrays in your struct)
} while(fscanf(fp, "%9s %9s %10s",p[i].name, p[i].surname, p[i].tc) != EOF);

Related

C problem with passing pointer to struct to function

I have a problem passing structure pointer to a function with fscanf().
Here's my struct:
typedef struct {
int health;
int y;
int z;
} save;
in main I have:
save save = { 0 }; //init with zeros
loadgame(&save);
health = save.health;
and my function loadgame() looks like that:
bool loadgame(save* save) {
FILE* fptr;
fptr = fopen("savegame.txt", "r");
if (fptr == NULL)
return 0;
fscanf(fptr, "health= %d", save->health);
return 1;
};
my savegame.txt file has line:
health= 5
and my function doesn't change save->health, after finish of this function my health equals zero.
I tried to do my function like that and it also has the same solution in function loadgame() I changed
fscanf(fptr, "health= %d", save-health);
to
fscanf(fptr, "health= %d", &(save-health));
fscanf(fptr, "health= %d", save->health); -> fscanf(fptr, "health= %d", &save->health);
Here you have working verison to play with https://godbolt.org/z/5CuZwR
As in my example always check the result of the scanf
Looks like your fscanf is passing the value of save->health instead of it's address.
You need to do
fscanf(fptr, "health= %d", &save->health);
Since -> has precedence over & this will give you the address of the health member.
fscanf needs a pointer so it knows where to save the value.
Other than that your code has a bunch of other small issues.
I have addressed those in the comments below:
#include <stdio.h>
#include <stdbool.h>
typedef struct {
int health;
int y;
int z;
}save_tp;
//using the same name for a typedef and a variable is a bad idea;
//typedef struct{...} foo; foo foo; prevents you from declaring other varibles of type foo
//as the foo variable overshadows the foo typedef name;
//better give types a distinct name
bool loadgame(save_tp* save){
FILE* fptr;
fptr = fopen("savegame.txt", "r");
if (fptr == NULL)
return false;
bool r = (1==fscanf(fptr, "health= %d", &save->health)); //needs an address + may fail
fclose(fptr); //need to close the file or you'd be leaking a file handle
return r;
} //shouldn't have a semicolon here
int main(void)
{
save_tp save={0};
if (!loadgame(&save)) perror("nok");
else printf("ok, health=%d\n", save.health);
}

Learning to process files. Trying to think of a method for maintaining file pointer position

I am working on a program to store data from a text file within a structure. The goal is to perform the file processing completely within the function outside of the main. The function opens and closes the file, and when it is called by the main function it is to populate the particular structure array element is supposed to be performed upon. The test file I am using is just a text file containing 3 lines:
Gates M 60
Jobs M 55
Jane F 45
These should be populated into an array of structures when called by the function. However, when I call the function it only populates the same first line to all array elements, I believe because the file pointer resets everytime I call the function. How can I remedy this? My code is below!
#include <stdio.h>
struct Individual
{
char LastName[30];
char gender;
unsigned int age;
};
int function(struct Individual *person)
{
FILE *cfPtr;
char holder[100];
cfPtr = fopen("C:\\Users\\Nick\\Desktop\\myfile","r");
fscanf(cfPtr, "%10s %c %3d", &person->LastName, &person->gender, &person->age);
fclose(cfPtr);
}
int main(void)
{
struct Individual person[3];
function(&person[0]);
function(&person[1]);
printf("%s %c %d", person[0].LastName, person[0].gender, person[0].age);
printf("%s %c %d", person[1].LastName, person[1].gender, person[1].age);
return 0;
}
FILE already tracks position for you; you don't need to do it yourself. The problem is that you keep re-opening the file, which resets the location back to the beginning of the file each time.
Open it once, read multiple times, then close it. Make your function take a FILE * parameter.
#include <stdio.h>
struct Individual
{
char LastName[30];
char gender;
unsigned int age;
};
int function(FILE *cfPtr, struct Individual *person)
{
fscanf(cfPtr, "%10s %c %3d", &person->LastName, &person->gender, &person->age);
// TODO: Check for failure
// TODO: Return appropriate value
}
int main(void)
{
struct Individual person[3];
FILE *cfPtr;
cfPtr = fopen("C:\\Users\\Nick\\Desktop\\myfile","r");
// TODO: Check for failure
function(cfPtr, &person[0]);
function(cfPtr, &person[1]);
fclose(cfPtr);
printf("%s %c %d", person[0].LastName, person[0].gender, person[0].age);
printf("%s %c %d", person[1].LastName, person[1].gender, person[1].age);
return 0;
}

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.

Error while trying to read from file C

I have a file and i need to read data from it. I have to read 2 int and 1 c string.
This is my struct
typedef struct seats
{
int number, reserved;
char * name;
} seats;
This is my main
FILE *data;
seats input;
data = fopen("data.txt", "r+");
while(fscanf(data,"%s %d %d", input.name, &input.number, &input.reserved) != EOF)
{
printf("%s %d %d", input.name, input.number, input.reserved);
}
Every time when i compile and run this software it crashes for some reason. Is there any solution?
You haven't assigned any value to input.name, but you pass its garbage value to fscanf. You need to assign a variable a value before you attempt to use that value.
Change your struct to something like this:
typedef struct seats{
int number, reserved;
char name[1000];
} seats;
and put a fflush(stdin), after printf(...)

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