Problem with structs in c - 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;
}

Related

Output of values of a struct via a function with a pointer as a parameter

I have two structures. A pointer is assigned to one.
Now I would like to output data previously entered via scanf via a function (outputAddress) with a pointer as a parameter.
It works with the variables via the pointer. But how do I do that with the values from the other structure? How can I output this in the function?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct structPerson
{
char name[30];
char forename[50];
int age;
};
struct structAddress
{
int zip;
char location[35];
char street[40];
int hNumber;
struct structPerson *ptrPerson;
};
void outputAddress(struct structPerson *ptrPerson)
{
printf("\n\nOutput Address: \n");
printf("ptrPerson->name: %s", ptrPerson->name);
printf("\nptrPerson->forename: %s", ptrPerson->forename);
return;
}
int main()
{
struct structPerson person1;
struct structAddress address1;
address1.ptrPerson = &person1;
printf("Location: ");
scanf("%s", &address1.location);
printf("Zip: ");
scanf("%d", &address1.zip);
printf("\nName: ");
scanf("%s", &address1.ptrPerson->name);
printf("Forename: ");
scanf("%s", &address1.ptrPerson->forename);
printf("\nOutput: %d %s %s\n", address1.zip, address1.location, address1.ptrPerson->name);
// strcpy( address1.location, "");
// printf("structAddress1: %d %s\n", address1.zip, address1.location);
outputAddress(&person1);
return 0;
}
In your data model structAddress is associated with a person via the personPtr field. As a result, Address is a main data struct. If I understand your intention correctly, you want to print info about the person and then his/her address.
For this you need to do a couple of changes. Firstly, you should pass the Address struct to the print function, because it has all information available, including the pointer to the person. Secondly, you should access your person information using the pointer: ptrAddress->ptrPerson-><field>. Here is an example.
void outputAddress(struct structAddress *ptrAddress)
{
printf("\n\nOutput Address: \n");
// use ptrAddress->ptrPreson to accesss person information
printf("ptrPerson->name: %s", ptrAddress->ptrPerson->name);
printf("\nptrPerson->forename: %s", ptrAddress->ptrPerson->forename);
// use ptrAddress-> to access address fields.
printf("\nptrAddress->zip: %d", ptrAddress->zip);
...
return;
}
int main() {
...
outputAddress(&address1); // << use address1 here.
...
}
Your datamodel is probably broken anyway. The address struct has a pointer to a person, but it often makes more sense to have it the other way around.

How can I build a function that stores data in a structure when taken from a file (pointer)?

In an assignment I'm working on, I need to read data from a file and then convert that data into a form that can be stored in a structure. The structure stores information on the person the line in the file represents. The issue that I'm having is that I cannot find a way to build a function that will allow me to take this data and store it in the structure. This is the relevant code to getting the file:
FILE* ifp;
char file_name[150], early_type[5], name_holder[LENGTH];
double early_registration, indi_registration, team_registration, amount_holder;
int num_early_regist, age_holder, type_holder;
// get file name and set it up as a pointer
printf("Please enter the name of your file.\n");
scanf("%s", file_name);
ifp = fopen(file_name, "r");
The code then goes to scanning the file for the data:
fscanf(ifp, "%s %s %d %d %lf", early_type, name_holder, &age_holder, &type_holder, &amount_holder);
// if the line shows an individual registering early
if (strcmp(early_type, "INDV")==0){
person_early(struct person* person, &name_holder, &age_holder, &type_holder, &amount_holder);
}
Finally, this is the prototype of the function that I am building:
void person_early(struct person* person, char* name[LENGTH], int* age, int* event_type, double* donation_amount);
The issue that I'm having is that I'm not sure how to put the data into this structure:
struct person {
char name[LENGTH];
int number;
int age;
int event;
float money;
float time;
};
Should I build a function to store this data, as there are several people to log from the file? Do I need to be using pass by value or pass by reference? Thanks for any help.
Edit:
The full function that I have written is this:
void person_early(struct person* person, char* name[LENGTH], int* age, int* event_type, double* donation_amount) {
// the name of the variable should be the name that is taken from the file
struct person (*name[LENGTH]);
(*name).name = *name_holder;
(*name).age = *age_holder;
(*name).event = *type_holder;
(*name).money = *donation_amount;
return;
}
regarding:
(*name).name = *name_holder;
This is not what you want. The passed in struct pointer person is the receiver of all the data. suggest:
void person_early( struct person* person, char name[], int age, int event_type, double donation_amount)
{
strcpy( person->name, name );
person->age = age;
person->event = event_type;
person->money = donation_amount;
}
Note: no return needed on a void function, unless exiting before the end of the function

Student Struct Troubles

I am learning structs and I am still little confused about them and what they do. The code I have is my attempt of it and I keep getting segmentation faults. My goal for the main is to ask the user to see how many students they want to add, and each information for name and score while calling a function. I also want to print the data array off to the user.
For the loadStudentData() function, I want to store the newName and NewScore into the newStudent Structure.
For printStudentData() I want to print data for a single student
Then for the printStudentArray() I want to call printStudentData() function on each member for the students array.
My code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STUDENT_NAME_LENGTH 20
typedef struct{
char* name;
int score;
}Student;
void loadStudentData(Student *newStudent,char* newName,int newScore);
int printStudentData(Student student);
void printStudentArray(Student* students, int numStudents);
/*
*
*/
int main(int argc, char** argv) {
int numberOfStudents;
Student *newStudent;
char* newName;
int newScore;
int student;
Student students[numberOfStudents];
printf("how many students: ");
scanf("%d", &numberOfStudents);
loadStudentData(newStudent, newName, newScore);
printStudentArray(students, numberOfStudents);
return (EXIT_SUCCESS);
}
void loadStudentData( Student *newStudent, char* newName, int newScore){
int i;
char *studentName = (char *) malloc(STUDENT_NAME_LENGTH * sizeof(char));
scanf("%s", studentName);
newStudent->name = studentName;
int nScore;
scanf("%d", &nScore);
newStudent[i].score = newScore;
}
int printStudentData(Student student){
int i;
printf("Student name\t%s\n",) ;
printf("Student score\t%d\n",);
}
void printStudentArray(Student* students, int numStudents){
int i;
for (i = 0; i < numStudents; i++) {
printf("Student name\t%s\n", students[i].name);
printf("Student score\t%d\n", students[i].score);
}
}
You call printStudentArray before you actually initialize the array of structures. That means all the data in the array will be indeterminate and using it in any way except to initialize it will lead to undefined behavior (which is a common cause of crashes).
More specifically, the problem is probably when you try to print the name, as the name pointer could point anywhere.
Point 1: Student students[numberOfStudents]; is invalid, as numberOfStudents is uninitialized.
Point 2: In your code, you're calling printStudentArray() before populating student itself.
This function tries to access the uninitialized memory at name variable which causes undefined behaviour.
Point 3: In your loadStudentData() function, you're using i uninitialized . Again UB.
That said,
Always check for success of malloc() before using the retuned pointer.
Please do not cast the return value of malloc() and family in C.
You seem to not allocate the structs you are creating. Be aware that when you declare a variable such as Student *newStudent; you first have to allocate it. Because thus far, you have only declared a variable that holds a pointer to a Student struct, but this pointer points to nowhere. So use the malloc function everywhere you expect a valid pointer:
newStudent = malloc(sizeof(newStudent));

filling array of pointers from file in 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);

C program football team structure with pointer elements and dynamic allocation

I have a question about passing function to another function which both have structure as arguments. First I created two structures:
typedef struct
{
char name[25],surname[25];int number;
}PLAYER;
typedef struct
{
char nameofteam[25];int numberofplayers;char *players;
}TEAM;
Then I defined a function to read elements of one player:
void readplayer(PLAYER *);
void readplayer(PLAYER *pi)
{
printf("name:");scanf("%s",pi->name);
printf("surname:");scanf("%s",pi->surname);
printf("number of player:");scanf("%d",&pi->number);
}
My question is how to create function which prototype is void readteam(TEAM*) which will read data for one team, but using function readplayer and call it in main()? Here is what I have tried:
#include<stdio.h>
#include<stdlib.h>
typedef struct
{
char name[25],surname[25];int number;
}PLAYER;
typedef struct
{
char nameofteam[25];int numberofplayers;char *players;
}TEAM;
void readplayer(PLAYER *pi)
{
printf("name:");scanf("%s",pi->name);
printf("surname:");scanf("%s",pi->surname);
printf("number of player:");scanf("%d",&pi->number);
}
void readteam(TEAM *pt)
{
char players[101];int i;
printf("name of team:");scanf("%s",pt->nameofteam);
printf("number of players in team:");scanf("%d",&pt->numberofplayers);
printf("players:");scanf("%s",players);
pt->players=(char *)calloc(length(players)+1,sizeof(char));
copy(pt->players,players);
for(i=0;i<pt->numberofplayers;i++)
{
printf("%d.",i+1);
readplayer(pt+i);
}
}
void erase(TEAM *);
void erase(TEAM *pt)
{
free(pt->players);
}
int length(char *s)
{
int d=-1;
while(s[++d]);
return d;
}
void copy(char *s1,char *s2)
{
while(*s1++ = *s2++);
}
int main()
{
int i,n;
TEAM *p;
do
{
printf("n=");scanf("%d",&n);
}
while(n<1);
p=(TEAM *)malloc(n * sizeof(TEAM));
for(i=0;i<n;i++)
{
printf("%d.",i+1);readteam(p+i);
}
free(p);
}
This gives me an error at the last input (in compiling, not debugging). Must be because of inappropriate use of dynamic allocation. I didn't use <string.h library. Obviously, only the readteam function has to be in main().
Thanks for the answers.
You are confused on how to store the playsrs. You have created a PLAYER struct, but you never use it. Instead, you insist that players must be a single string.
But it should work like this: You have n teams. Ecah team has m players. All team info is stored in your ´TEAMstruct. All player info is stored in yourPLAYERstruct. Because a team is made up of players, there should be aPLAYER` entry in your struct:
typedef struct {
char name[25];
char surname[25];
int number;
} PLAYER;
typedef struct {
char nameofteam[25];
int numberofplayers;
PLAYER *players;
} TEAM;
Then, when you read players, you read the bare team info in readteam. But you don't read anything about individual players there, because you delegate that to readplayer. Of course, the pointer you pass to that function must be that for a player, not one for a team:
void readplayer(PLAYER * pi)
{
printf("name:");
scanf("%s", pi->name);
printf("surname:");
scanf("%s", pi->surname);
printf("number of player:");
scanf("%d", &pi->number);
}
void readteam(TEAM * pt)
{
int i;
printf("name of team:");
scanf("%s", pt->nameofteam);
printf("number of players in team:");
scanf("%d", &pt->numberofplayers);
pt->players = calloc(pt->numberofplayers, sizeof(*pt->players));
for (i = 0; i < pt->numberofplayers; i++) {
printf("Player %d:\n", i + 1);
readplayer(pt->players + i);
}
}
Your cast to (char *) hides the warning about incompatible types. You should cast only when you know what you're doing. In this simple program, you don't need casts.
In your original code, there are warnings about "implicit declarations". These concern your copy and length functions. (By the way, what's wrong with strlen and strcpy?) You should move these functions to the top so that they are declared before they are called. ALternatively, provide prototypes at the beginning of your code or in a header file, which you #include at the top. (But now that you read into PLAYER structs, these functions are no longer needed.)

Resources