Right after scanning the second element, the program crashes. It is not able to go to the scanning of the third element(i.e. grade). Need help, in figuring out what I am wrong wrong.
#include<stdio.h>
#include<stdlib.h>
#define NUM 2
typedef struct STUDENT
{
int ID;
char *name;
char *grade;
};
int main ()
{
int i;
struct STUDENT *s;
s = (struct STUDENT*)malloc(NUM*sizeof(struct STUDENT*));
printf("Enter Student's ID, Name and Grade:\n");
for(i=0;i<NUM;i++)
{
printf("Enter ID:\n");
scanf("%d", &(s+i)->ID);
printf("Enter Student Name:\n");
scanf("%s", (s+i)->name);
printf("Enter Grade:\n");
scanf("%s", (s+i)->grade);
printf("\n");
}
printf("\nInformation of the student's are:\n");
for(i=0;i<NUM;i++)
{
printf("Student ID = %d\n", (s+i)->ID);
printf("Student Name = %s\n", &(s+i)->name);
printf("Student grade = %c\n", &(s+i)->grade);
printf("\n");
}
return 0;
}
You do not allocate memory for grade and name in struct STUDENT. Trying to read input and write it to them produces undefined behavior.
Add the necessary mallocs, for example with a given maximum length STR_MAX:
s[i].name = malloc(STR_MAX);
s[i].grade = malloc(STR_MAX);
See the other answers for further errors.
malloc(NUM*sizeof(struct STUDENT*));
should be
malloc(NUM*sizeof(struct STUDENT));
also, the name and grade are not buffers but pointers. You may need a buffer (char array) or allocate memory for it dynamically.
typedef struct STUDENT
{
int ID;
char *name;
char *grade;
};
Here name and grade character type pointer. so when you malloc structure you also have to malloc name and grade too
struct STUDENT *s; should be declared like this:
STUDENT *s;
No need to cast void * from malloc. Change this line s = (struct STUDENT*)malloc(NUM*sizeof(struct STUDENT*)); to this:
s = malloc(NUM * sizeof(*s));
Instead of this scanf("%d", &(s+i)->ID);, the following may be easier to understand:
scanf("%d", &s[i].ID);
Same here:
printf("Student ID = %d\n", s[i].ID);
Most importantly, what Nabla said.
Related
Fields of Student: name, lastName, studentId, mid1Grade, mid2Grade, finalGrade, average
Fields of Course: courseName, courseCode, myStudentArray (array of Student structures),currentStudentCount
Functions:
void createNewStudent(struct Course *myCourse);
void setGradeOfStudent(struct Course *myCourse);
void findAndDisplayAverage(struct Course *myCourse);
struct Student * findStudentByID(int id, struct Course *myCourse);
void displayAverageOfAllStudents(struct Course *myCourse);
void displayAverageOfStudentsInInterval(struct Course *myCourse
ok so I have written the first function but there is an error which I dont understand. First of all the first function and what it does:
createNewStudent: Prompt the user to enter name, last name and id of the new student.Values entered by the user are assigned to the fields of the student residing in themyStudentArray of course variable pointed by myCourse. currentStudentCount will be updated so that it designates the slot allocated for the student inserted next.
and my implementation:
#include <string.h>
#include <stdio.h>
struct Student {
char name[50];
char lastname[50];
int id;
int mid1;
int mid2;
int final;
double average;
};
struct Course {
char courseName[50];
char courseCode[50];
struct Student myStudentArray[5];
int currentstudentcount;
};
void createNewStudent(struct Course * myCourse);
void setGradeOfStudent(struct Course * myCourse);
void findAndDisplayAverage(struct Course * myCourse);
struct Student * findStudentByID(int id, struct Course * myCourse);
void displayAverageOfAllStudents(struct Course * myCourse);
void displayAverageOfStudentsInInterval(struct Course * myCourse);
int main() {
struct Student * stud;
int input = 0;
scanf("%d", & input);
if (input == 1) {
createNewStudent(struct Course * myCourse);
}
}
return 0;
}
void createNewStudent(struct Course * myCourse) {
struct Student s1;
printf("Enter name: ");
scanf("%[^\n]%*c", s1.name);
printf("Enter Surname: ");
scanf("%[^\n]%*c", s1.lastname);
printf("Enter id: ");
scanf("%d", & s1.id);
}
When you call the function with the if(input == 1) it gives
error: expected expression before ‘struct’
but I dont understand this beacuse *myCourse is just a pointer to the Course struct isn't it ????
If I can understand this ı will be able to the the next functions I think
Is the function correct ?? I dont know why this doesnt work
Ok I tried to use the struct Student myStudentArray[5]; to get name, lastname,id like so (structs are the same)
void createNewStudent(struct Course *myCourse);
void setGradeOfStudent(struct Course *myCourse);
int main(){
struct Course *myCourse;
int input=0;
scanf("%d",&input);
if(input == 1){
createNewStudent(myCourse);
}
return 0;
}
void createNewStudent(struct Course *myCourse){
myCourse->currentstudentcount=0;
printf("Enter name: ");
scanf("%[^\n]%*c"
,myCourse->myStudentArray[myCourse->currentstudentcount].name);
printf("Enter Surname: ");
scanf ("%[^\n]%*c",
myCourse->myStudentArray[myCourse->currentstudentcount].name);
myCourse->currentstudentcount++;
}
I Keep getting
may be used uninitialized in this may be used uninitialized in this function [-Wmaybe-uninitialized]
and
Segmentation errors
void createNewStudent(struct Course * myCourse)
If you want to create new student, you should use the student struct as the parameter of this function instead of using struct Course.
void createNewStudent(struct Student *s1)
Then, this function becomes as:
void createNewStudent(struct Student *s1) {
printf("Enter name: ");
scanf("%49s", s1->name);
printf("Enter Surname: ");
scanf("%49s", s1->lastname);
printf("Enter id: ");
scanf("%d", & s1->id);
}
If you want to test, in main function, you can declare the value stud or the pointer to struct Student.
For example:
int main() {
struct Student stud;
int input = 0;
scanf("%d", & input);
if (input == 1) {
createNewStudent(&stud);
printf("name: %s\n Surname: %s\n id = %d\n", stud.name, stud.lastname, stud.id);
}
return 0;
}
The complete program for test:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
struct Student {
char name[50];
char lastname[50];
int id;
int mid1;
int mid2;
int final;
double average;
};
struct Course {
char courseName[50];
char courseCode[50];
struct Student myStudentArray[5];
int currentstudentcount;
};
void createNewStudent(struct Student *s1);
int main() {
struct Student stud;
int input = 0;
scanf("%d", & input);
if (input == 1) {
createNewStudent(&stud);
printf("name: %s\nSurname: %s\nid = %d\n", stud.name, stud.lastname, stud.id);
}
return 0;
}
void createNewStudent(struct Student *s1) {
printf("Enter name: ");
scanf("%49s", s1->name);
printf("Enter Surname: ");
scanf("%49s", s1->lastname);
printf("Enter id: ");
scanf("%d", & s1->id);
}
The output:
#./test
1
Enter name: abc
Enter Surname: def
Enter id: 100
name: abc
Surname: def
id = 100
Update for your question in the comment:
If you want to store student info in an array, you can change the code to:
struct Student myStudentArray[5];
int input = 0;
scanf("%d", & input);
if (input == 1) {
for (int i = 0; i < 5; i++) {
createNewStudent(&myStudentArray[i]);
}
for (int i = 0; i < 5; i++) {
printf("name: %s\nSurname: %s\nid = %d\n", myStudentArray[i].name, myStudentArray[i].lastname, myStudentArray[i].id);
}
}
For Course structure you can create one function as the function createNewStudent but for struct Course to create the new course. After creating new 5 students (for example the code above), you can copy the myStudentArray to new_course.myStudentArray. Then now you have the info of 5 students in new_course. When you copy value from an array to another, you can use memcpy or using one loop to copy each element from one array to another one. Do not use something like myStudentArray = new_course.myStudentArray for the array.
You are making a declaration as a parameter of the createNewStudent() function. In C, functions require expressions as parameters, which is why you got the error message "expected expression...".
So, just create the struct pointer before you call the function:
if (input == 1) {
struct Course *myCourse = malloc(sizeof(struct Course));
createNewStudent(myCourse);
}
Notice the use of malloc(), which returns a pointer to a place in memory of sufficient size to hold that particular Course struct. When dealing with pointers to structs, you need to allocate memory for the structs that will ultimately be pointed to, in order to avoid dereferencing unallocated regions of memory.
In your function CerateNewStudent, the proper way to address the variables into which to place the data read by scanf should be:
myCourse->myStudentArray[myCourse->currentstudentcount].name
as the variable to read name into. Use this syntax for all data items to read. After that, increment the counter:
myCourse->currentstudentcount++;
Note: what is missing in all your functions (and in the assignment?) is a way to create a course. The students created are all added to courses. First a course should be created and then students can be added to it.
Hi I'm inputting a structure of a family with children with those two structures:
typedef struct person {
int id;
char* firstName;
int age;
}person;
typedef struct family {
char* lastName;
person father, mother;
person* children;
int numChildren;
}family;
EDIT: this is the edited function and it still crashes :
int initializeHouse(family **pdata)
{
char temp[SIZE];
int size, i, j;
printf("enter the number of families\n");
scanf("%d", &size);
*pdata = (family*)malloc(sizeof( family)*size);
for (i = 0; i<size; i++)
{
printf("Please enter the last name\n");
scanf("%s", temp);
(*pdata)[i].lastName = (char*)malloc(sizeof(char)* (strlen(temp) + 1));
strcpy(pdata[i]->lastName, temp);
printf("Enter the fathers first name\n");
scanf("%s", temp);
initPerson(temp, &pdata[i]->father.firstName);
printf("enter the fathers ID\n");
scanf("%d", &pdata[i]->father.id);
printf("Enter the fathers age\n");
scanf("%d", &pdata[i]->father.age);
printf("Enter the mothers first name\n");
scanf("%s", temp);
initPerson(temp, &pdata[i]->mother.firstName);
printf("enter the mothers ID\n");
scanf("%d", &pdata[i]->mother.id);
printf("Enter the mothers age\n");
scanf("%d", &pdata[i]->mother.age);
printf("enter the number of children");
scanf("%d", &pdata[i]->numChildren);
(*pdata)[i].children= (person*)malloc(sizeof(person)*(pdata[i]->numChildren));
for (j = 0; j<pdata[i]->numChildren; j++)
{
printf("enter the kids name\n");
scanf("%s", temp);
initPerson(temp, &pdata[i]->children[j].firstName);
printf("enter the kids ID\n");
scanf("%d", &pdata[i]->children[j].id);
printf("Enter the kids age\n");
scanf("%d", &pdata[i]->children[j].age);
}
}
return size;
}
void initPerson(char* str, char** fam)
{
*fam = (char*)malloc(sizeof(char)*(strlen(str) + 1));
strcpy(*fam, str);
}
EDIT: I changed the code and it still doesn't work, and it requires me to write some description so here it is ..
int main() {
int size;
family *a = NULL;
size=initializeHouse(&a);
}
declares a pointer to a family structure. When you pass it's address
size = initializeHouse(&a);
the function gets it as a family**
Okay, we're all on the same page to this point. When you allocate the target of that pointer
*pdata = malloc(sizeof(family) * size);
then *pdata points to an allocated array of structs, not pointers to those structs. Each struct is accessed by (*pdata)[i], which means -> dereference the double pointer pdata to get the address of the first element in the array, then access the array element with a subscript.
So your assignment should be
(*pdata)[i].lastName = malloc(sizeof(char)* (strlen(temp) + 1));
You use the dot . operator to access the members, because the result of the subscript access is a struct, not a pointer to a struct.
This little example using (*pdata)[i]. doesn't crash.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 40
typedef struct person {
int id;
char* firstName;
int age;
}person;
typedef struct family {
char* lastName;
person father, mother;
person* children;
int numChildren;
}family;
int initializeHouse(family **pdata)
{
char temp[SIZE];
int size, i, j;
printf("enter the number of families\n");
scanf("%d", &size);
*pdata = malloc(sizeof(family)*size);
for (i = 0; i<size; i++)
{
printf("Please enter the last name\n");
scanf("%39s", temp);
(*pdata)[i].lastName = malloc(sizeof(char)* (strlen(temp) + 1));
strcpy ( (*pdata)[i].lastName, temp);
}
return size;
}
int main ( void) {
int size;
family *a;
size=initializeHouse(&a);
}
It's important that you understand the memory layout.
family *fam;
family **pdata = &fam;
*pdata = (family*)malloc(sizeof(family)*size);
You have essentialy this: fam is a uninitialized pointer of type family.
pdata is a double pointer initialized with the address of fam. The malloc
call allocates space for size family-objects. By doing *pdata = malloc(...)
you are initializing fam.
This is the basic memory layout you have. base is the address returned by
malloc. slf is the size of struct family object, fpl is the size of a
pointer to a struct family object.
base = address returned by malloc
sfl = sizeof(struct family)
fpl = sizeof(struct family*)
base + 0 base + slf base + 2 * slf
+-----------------+------------------+------------------+
|struct family | struct family | struct family |
+-----------------+------------------+------------------+
base + 0 base + fpl base + 2*fpl base + 3*fpl base + 4*fpl
+------------+------------+------------+------------+-----------+
| pdata[0] | pdata[1] | pdata[2] | pdata[3] | pdata[4] |
+------------+------------+------------+------------+-----------+
The first row shows the memory in terms on struct family objects, the second
row shows you the same memory in terms on pointers (to struct family object).
This is very important distinction, because pdata[i] returns you a
pointer, not the object.
Remember pdata is a double pointer, pdata[i] is the equivalent to pdata + i,
that is the ith pointer begining at base.
Because the size of an struct family is defintitely different that the size of
a pointer, you see that the block don't align, that means
base + slf != base + fpl.
In the first iteration you are lucky, because pdata[0] and (*pdata)[0] are
the same. But pdata[1] and *(pdata)[1] are not the same. So doing
pdata[1]->lastname (instead of (*pdata)[1].lastname) you are accessing at a
wrong location in you allocated memory.
The easiest way to fix you code would be to change the pdata[i] in (*pdata)[i] as shown
in user3121023's answer.
edit
I see that user3121023 has retracted his answer. Basically it did:
printf("enter the fathers ID\n");
scanf("%d", &((*pdata)[i].father.id));
in the loop.
Fixing the pointers may have solved your problem. But the program has a lot of duplicate code and rewriting as follows would help you test a small portion and debug the program easily.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100
typedef struct person {
int id;
char *firstName;
int age;
} person;
typedef struct family {
char *lastName;
person father, mother;
person *children;
int numChildren;
} family;
void input_string(const char *prompt, char **where) {
char temp[SIZE];
printf("%s\n", prompt);
scanf("%s", temp);
*where = malloc(sizeof(char) * (strlen(temp) + 1));
strcpy(*where, temp);
}
void input_int(const char *prompt, int *where) {
printf("%s\n", prompt);
scanf("%d", where);
}
void input_person(const char *name, person *person) {
char prompt[SIZE];
sprintf(prompt, "Enter the %s's first name", name);
input_string(prompt, &person->firstName);
sprintf(prompt, "Enter the %s's ID", name);
input_int(prompt, &person->id);
sprintf(prompt, "Enter the %s's age", name);
input_int(prompt, &person->age);
}
void input_family(family *fam) {
input_string("Please enter the last name", &fam->lastName);
input_person("father", &fam->father);
input_person("mother", &fam->mother);
input_int("Please enter the number of children", &fam->numChildren);
fam->children = malloc(sizeof(person) * (fam->numChildren));
for (int i = 0; i < fam->numChildren; i++) {
input_person("kid", &(fam->children)[i]);
}
}
int initializeHouse(family **families) {
int size;
input_int("Please enter the number of families", &size);
*families = malloc(sizeof(family) * size);
for (int i = 0; i < size; i++) {
input_family(&(*families)[i]);
}
return size;
}
int main() {
int size = 0;
family *a;
size = initializeHouse(&a);
printf("Successfully inputted %d families", size);
return 0;
}
When I run the program and give values to the id, name, surname it gives them all the value of the last student. For instance if the last students name is Anna then all the other names of the array are Anna. With the grades it works well! I tried and without the 'constructor' function and happenden the same thing.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student{ /*struct for student info*/
char *id;
char *name;
char *surname;
int grade;
};
struct Student* Student_new(char* id, char* name, char* surname, int grade);
/*fuction: Student 'constructor'*/
int main(int argc, char *argv[]) {
int no; /*number of students*/
printf("Welcome! \n\nNumber of students: ");
scanf("%d", &no);
struct Student *studentArray[no]; /*arary of struct students*/
int i; /*counter*/
for(i=0; i<no; i++){
char id[10], name[10], surname[10];
int grade;
printf("\n\nStudent(%d)\n", i+1);
printf("id: ");
scanf("%s", id);
printf("name: ");
scanf("%s", name);
printf("surname: ");
scanf("%s", surname);
printf("grade: ");
scanf("%d", &grade);
studentArray[i] = Student_new(id, name, surname, grade); /*using Student
'constructor' to initialize the array*/
}
for(i=0; i<no; i++){
printf("%s %s %s %d \n", studentArray[i]->id, studentArray[i]-
>name, studentArray[i]->surname, studentArray[i]->grade);
}
return 0;
}
struct Student* Student_new(char* id, char* name, char* surname, int grade)
{
struct Student* st = malloc(sizeof(struct Student));
st->id = id;
st->name = name;
st->surname = surname;
st->grade = grade;
return st;
}
PLEASE HELP!!
The issue is that the loop variables go out of scope after each iteration, and you're left with dangling pointers in the Student instances. What you're seeing is the result of undefined behavior.
What's probably happening is that the same char array is being passed into every student instance. Then you modify the same char array, overwriting the previous values.
You'll need to make copies of the strings. Remember to create a function like Student_free where you free the dynamically allocated copies.
struct Student* Student_new(char* id, char* name, char* surname, int grade)
{
struct Student* st = malloc(sizeof(struct Student));
st->id = strndup(id, 10);
st->name = strndup(name, 10);
st->surname = strndup(surname, 10);
st->grade = grade;
return st;
}
You should reserve memory for the string attributes. As a hint, use a struct similar to:
#define MAX_LEN 32
struct Student{ /*struct for student info*/
char id[MAX_LEN];
char name[MAX_LEN];
char surname[MAX_LEN];
int grade;
};
Define MAX_LEN to something that is reasonable for you, and check that the entered values aren't any longer. Also make sure to strcpy the input values to the struct variables.
The student structure only holds pointers to char arrays.
Now the actual space in memory for the strings is allocated in your for cycle an its lifetime is limited by the scope of the for cycle, accessing it afterwards is undefined behaviour. In your case the space where the strings are has not been reused and overridden yet, so coincidentally you are able to get the last value stored (cases like this can also raise segmentation fault).
You should have a look on some basic tutorial about pointers and c memory model. Allocating the arrays in the struct is a good solution (nucleon's answer). Also the scanf function can overflow you should limit the number of retrieved characters to match the size of allocated array.
I'm having trouble getting a struct pointer to take user input through fgets inside a function in a c program; I'm not sure what I'm doing wrong. The getInput() function is where the crash is occurring. I'm first trying to assign memory to the where the name is going to be stored with
*stu->name = (char*)malloc(N_LENGTH);
then getting input from the user with
fgets(*stu->name, N_LENGTH, stdin);
The program crashes during the first line and also the second line.
Sorry if I'm breaking any rules as this is my first time on the site.
Code:
#include <stdio.h>
#include <stdlib.h>
#define UNIT 100
#define HOUSE 1000
#define THRESH 12
#define DISCOUNT 10
#define NUM_PERSONS 5
#define N_LENGTH 30
struct student
{
char *name;
char campus;
int userUnit;
};
void getInput(struct student *stu);
int amountCalc(struct student *stu);
void printOutput(struct student stu, int total);
int main()
{
int total[NUM_PERSONS];
int averageTotal=0;
struct student tempStudent;
struct student students[NUM_PERSONS];
struct student *sPtr = &tempStudent;
int i;
for (i=0; i < NUM_PERSONS; i++)
{
getInput(sPtr);
students[i]=tempStudent;
total[i]=amountCalc(sPtr);
averageTotal+=total[i];
};
for (i=0; i < NUM_PERSONS; i++)
{
printOutput(students[i], total[i]);
};
printf("\nThe average tuition cost for these %d students is $%.2f.\n",
NUM_PERSONS, averageTotal/(NUM_PERSONS*1.0));
return 0;
}
void getInput(struct student *stu)
{
fflush(stdin);
printf("Enter student name: ");
*stu->name = (char*)malloc(N_LENGTH);
fgets(*stu->name, N_LENGTH, stdin);
printf("Enter y if student lives on campus, n otherwise: ");
scanf(" %s", &stu->campus);
printf("Enter current unit count: ");
scanf(" %d", &stu->userUnit);
printf("\n");
}
int amountCalc(struct student *stu)
{
int total;
total=(stu->userUnit)*UNIT;
if (stu->userUnit>THRESH) {
total-=((stu->userUnit)-12)*DISCOUNT;
};
if (stu->campus=='y') {
total+=HOUSE;
};
return total;
}
void printOutput(struct student stu, int total)
{
printf("\nStudent name: %s\n", stu.name);
printf("Amount due: $%d\n\n", total);
}
Your allocation is wrong. True allocation is like this ;
void getInput(struct student *stu)
{
fflush(stdin);
printf("Enter student name: ");
stu->name = (char*)malloc(N_LENGTH);
fgets(stu->name, N_LENGTH, stdin);
printf("Enter y if student lives on campus, n otherwise: ");
scanf(" %s", &stu->campus);
printf("Enter current unit count: ");
scanf(" %d", &stu->userUnit);
printf("\n");
}
When you compile it, you can see as a warning. You should take care of all warnings. And casting malloc to (char *) is also unnecessary.
Don't use fflush(stdin). See this question. I don't know if that causes the error but it is not defined in the C-standard so maybe your platform doesn't handle it!
The wrong allocation of memory is also a problem, look at #Hakkı Işık 's answer.
I have the following code. In the struct definition, I try to ask user to enter employee's first and last name. But when I run this exe, it exit after the title is entered. Any suggestions?
#include<stdio.h>
#include<string.h>
#define NUMEMPS 10
struct Employee {
char *firstname;
char *lastname;
char *title;
int salary;
};
int main()
{
struct Employee* stuff = malloc(NUMEMPS* sizeof *stuff);
int n,i;
for (n=0; n<NUMEMPS;n++)
{
printf("Please enter number %d Employee's Last name:", n);
fflush(stdout);
gets(stuff[n].lastname);
if (strlen(stuff[n].lastname) == 0)
break;
printf("Please enter number %d Employee's first name:", n);
fflush(stdout);
gets(stuff[n].firstname);
printf("Please enter number %d Employee's title:", n);
fflush(stdout);
gets(stuff[n].title);
printf("Please enter number %d Employee's salary:", n);
fflush(stdout);
scanf("%d", &stuff[n].salary);
getchar();
}
for (i = 0;i<n;i++)
{
printf("{%s,%s,%s,%d}\n",
stuff[i].lastname,
stuff[i].firstname,
stuff[i].title,
stuff[i].salary);
}
return 0;
}
The three char* members of the structure are pointers, so no space is allocated to hold any data.
With the current struct you'd have to do three more allocs for the data:
struct Employee* stuff = malloc(NUMEMPS* sizeof *stuff);
stuff->firstname = malloc(101);
stuff->lastname = malloc(101);
stuff->title = malloc(101);
What you probably want is something like:
struct Employee {
char firstname[101];
char lastname[101];
char title[101];
int salary;
};
Also, though as an aside, you must check your malloc calls for a NULL return.
This code:
struct Employee {
char *firstname;
char *lastname;
char *title;
int salary;
};
...
struct Employee* stuff = malloc(NUMEMPS* sizeof *stuff);
only allocates enough room to store a single struct Employee, that is: three pointers and an integer. There's no storage for the character strings pointed to.
Instead, consider malloc()ing each of the constituent character data and assigning to stuff->firstname (et al), or modify the declaration of struct Employee to include character arrays.