Allocating memory for a struct variable using a function - c

As part of a larger project, I am trying to write a function that will allocate enough memory for a struct variable and assign values to its member variables after scanning them from the keyboard. In other words, I am trying to create a sort of a constructor function. The reason for this is because I think that's the best way to create a database-like program in c, where all the student_t variables will be stored in a student_t* array called classroom.
#include <stdio.h>
#include <stdlib.h>
#define N 10
#define STRLIM 50
typedef struct student{
char* name;
int age;
}student_t;
student_t* init_student(student_t* s);
int i=0;//its the array counter
student_t* classroom[N];
int main(int argc, char const *argv[]){
while(i<N){
// classroom[i]=(student*)malloc(sizeof(student));
init_student(classroom[i]);
classroom[i]->age=i;
printf("The age of student #%d is : %d \n",i,classroom[i]->age);
printf("the name of student #%d is : %s",i,classroom[i]->name);
i++;
}
printf("the size of the classroom is : %ld",sizeof(classroom));
return 0;
}//end of main()
student_t* init_student(student_t* s){
s=(student_t*)malloc(sizeof(student_t));
s->name=(char*)malloc(sizeof(char)*STRLIM);
fflush(stdin);
fgets(s->name,STRLIM,stdin);
return s;
}
Gdb ouput shown in the attached image here.
Please check out my repo.
I am guessing something about my build and datatypes is off .Thanks in advance.

Related

Struct in a struct using typedef - C

How do I properly use one struct inside another struct using typedef in C?
This method doesn't work and I can't understand why:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
char *nume;
char *prenume;
data data;
} student;
typedef struct
{
int an,zi,luna;
} data;
int main()
{
student Andrei;
scanf("%s %s %d ",Andrei.nume,Andrei.prenume,&Andrei.b.an);
printf("%s %s %d ",Andrei.nume,Andrei.prenume,Andrei.data.an);
return 0;
}
There are actually a number of errors in your code!
First, you need to declare/define any struct object before you use that as a member of another struct.
Second, your nume and prenume members are declared as pointers to characters but they are not initialized to anything, nor is any memory allocated for those string.
Third, you have a 'typo' in your scanf line: Andrei.b.an should, presumably, be Andrei.data.an.
Finally (I think), because you have a trailing space in the format string for scanf, the function will need at least one 'extra' input field in order to complete.
Here is a potential 'fix', with comments added where I've made changes:
#include <stdio.h>
// <stdlib.h> // You don't use this - perhaps thinking of using "malloc" for "nume" and "prenume"??
typedef struct // This MUST be defined BEFORE it is used as a member in the following struct!
{
int an, zi, luna;
}data;
typedef struct
{
char nume[32]; // Here, we create fixed char arrays (strings) for "nume"...
char prenume[32]; // ... and "prenume". You can change the sizes, as you need!
data data;
} student;
int main()
{
student Andrei;
scanf("%s %s %d", Andrei.nume, Andrei.prenume, &Andrei.data.an); // Note: removed trailing space from format!
printf("%s %s %d", Andrei.nume, Andrei.prenume, Andrei.data.an);
return 0;
}

fopen does not work properly and I get segmentation fault when I use fclose

I am new c-programmer.I am writing a small student database. I have an array of structs I would like to write it to file. Till now the program works fine. I can print out the data saved in the array called db (abbreviation of database). In order to be able to write data, I opened a new c-file and I wrote a method writeData() that allows me to write data using FILE-object and fopen. Here are the methods of my database located in a header-file:
//header file
#ifndef DB_OPS
#define DB_OPS
#define SIZE 3typedef int bool;
typedef int bool;
#define true 1
#define false 0
struct student{
bool statusFlag;
char lastname[20];
char firstname[20];
int mNr;
char subject[30];
char nationality[20];
};
int createDb(int s);
struct student getData(char * lastname, char * firstname, int matNr, char * courseOfStudy, char * nationality);
void insert_student(struct student * st);
void update_student(int matNr);
bool delete_student(int matNr);
void display_result(bool res, bool operation);
bool search_student(int matNr);
void display_db();
void writeData();//method to write data
void readData();
void print();
#endif
then I defined the method writeData(). Here is the code:
//a c-file
#include <stdlib.h>
#include <stdio.h>
#include "db_ops.h"
void writeData(){
//when i use fopen, the data saved in db will be damaged
FILE * fpw;
fpw=fopen("database.txt","wb");
if(fpw==NULL){
printf("the file cannot be opened");
exit(1);
}
extern struct student *db;
int i;
for(i=0;i<SIZE;i++){
printf("%s, %s, %d, %s , %s\n",
(db+i)->lastname,(db+i)->firstname,(db+i)->mNr, (db+i)->subject, (db+i)->nationality);
}
fclose(fpw);//When I use fclose(),I get segmentation fault: free(): invalid next size
}
Till now I am not able to find a solution or an explanation for that Problem. When I use fopen, I cannot find my data saved in the array db anymore. I do know if my array db which is a pointer is pointing outside of the array. The second problem consists in using fclose, which generates a segmentation fault.Any suggestions?
Here is a piece of code located in a file where I initialized the array db:
// another c-file
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "db_ops.h"
struct student * db;
struct student * ptrDb;
static int insertCounter=1;
int size=0;
int createDb(int s){
size=s;
db= (struct student *)calloc(3,sizeof(struct student *));
if(db==NULL){
printf("dynamic allocation failed");
return EXIT_FAILURE;
}
ptrDb=db;
printf("database was created\n");
}
struct student getData(char * lastname, char * firstname, int matNr, char * subject, char * nationality){
struct student st;
int i;
if(insertCounter<=size){
//get data
st.statusFlag=1;//flag to show, whether the program gets data or not
//0-byte marks the end of the string
memcpy(st.lastname,lastname,strlen(lastname)+1);
memcpy(st.firstname,firstname,strlen(firstname)+1);
st.mNr=matNr;
memcpy(st.subject, subject,strlen(subject)+1);
memcpy(st.nationality,nationality,strlen(nationality)+1);
//printf("%s,%s,%d,%s,%s\n",st.lastname,st.firstname,st.mNr,st.subject,st.nationality);
return st;
}else if(insertCounter>size){
st.statusFlag=0;
return st;
}
}
//coping input by reference
void insert_student(struct student * st){
printf("statusFlag:%d\n",st->statusFlag);
if(st->statusFlag==1){
*ptrDb=*st;
insertCounter++;
ptrDb++;
}else{
printf("##########################################################\n");
printf("no insert is possible, The maximum size has been reached\n");
printf("##########################################################\n");
}
}
Why calloc(3,sizeof(struct student *)) is for struct pointer but not struct member? It seems has to be calloc(3,sizeof(struct student)) for 3 structure members.
It is not known whether student struct pointer and contents are correct. Try to fclose the file immediately after fopen. If there is no segmentation fault, then your problem is in pointer or memory allocation.

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));

Pointer to an array of structures

I'm currently trying to write a program for a student database assignment. After manually setting 3 elements of the structure array, the next 3 students' details are inputted by the user.
I am trying to write a function that finds the oldest age of the 6 students and returns it as a student_t entry at index max. I'm struggling with how to actually give the function the pointer that is pointing to the first element of the array stdt[6] and then using the pointer within the function. I also have no idea how I would go about returning to main the entry that has the highest age. If I'm trying to say that the value of an element of array of structures is equal to some other integer (max), doesn't that mean that max is now some other block of memory with an integer value and not linked to the array? So I'm not sure how I would return the entry that has the highest age after the function determines the max age.
This is all I've written so far:
#include <stdlib.h>
#include <stdio.h>
typedef struct {
char *name;
char *surname;
char *UUN;
char *department;
char gender;
int age;
}student_t;
student_t findOldest(student_t *studentarr, int len){
int i;
int x;
int max;
max=0;
for(i=0;i<len;i++){
(p+i).age=x;
if(x>max){
x=max;
}
}
}
int main() {
int i;
student_t stdt[6]={{"John","Bishop","s1234","Inf",'m',18},{"Lady","Cook","s2345","Eng",'f',21},{"James","Jackson","s33456","Eng",'m',17}};
student_t *p=&stdt[0];
for(i=3;i<6;i++) {
printf("First name: \n");
scanf("%s",stdt[i].name);
printf("Last name: \n");
scanf("%s",stdt[i].surname);
printf("UUN: \n");
scanf("%s",stdt[i].UUN);
printf("Department: \n");
scanf("%s",stdt[i].department);
printf("Gender (m/f): \n");
scanf("%c",stdt[i].gender);
printf("Age: \n");
scanf("%d",stdt[i].age);
}
findOldest(p,6);
return 0;
}
This should work.
student_t findOldest(student_t *p, int len){
int i;
student_t max = *(p+0);
for(i=1;i<len;i++)
{if((*(p+i)).age > max.age)
max = *(p+i);
}
return max;
}
You want to return the student so keep the student in your max variable not the age. And to refer to pointers either use
(p+i)->age > max.age
or use
(*(p+i)).age > max.age
But there are other problems with the code.

Getting multiple struct entries from stdin

I am trying to get multiple entries for my struct via the keyboard. I think I am wrong inside of scanf but I am not sure where I am wrong. Thanks!
Here is what I have:
#include <stdio.h>
#include <math.h>
int main()
{
//define the structure
struct course
{
char title[20];
int num;
} ;
// end structure define
//define the variable
struct course classes;
printf("Enter a course title and course number");
scanf("%s %d", classes[3].title, &classes.num);
return 0;
}
Fix the code as Carl said and it works fine:
#include <stdio.h>
int main()
{
struct course
{
char title[20];
int num;
} ;
struct course class;
printf("Enter a course title and course number");
scanf("%s %d", class.title, &class.num);
printf("%s %d", class.title, class.num);
return 0;
}
There are a couple issues.
You have this struct called "classes", but it has only 1 entry - you're accessing the 3rd entry so you're running off the end.
Also, Title is 20 bytes long, but if you enter something larger in scanf(), it will just overflow. The basic scanf() structure looks ok though.
I would set it up more like this:
#include <stdio.h>
#include <math.h>
#define MAX_CLASSES 50 // how big our array of class structures is
int main()
{
//define the structure
struct course
{
char title[20];
int num;
} ;
// end structure define
//define the variable
struct course classes[MAX_CLASSES];
int nCurClass = 0; // index of the class we're entering
bool bEnterMore = true;
while (bEnterMore == true)
{
printf("Enter a course title and course number");
scanf("%s %d", classes[nCurClass].title, &classes[nCurClass].num);
// if user enters -1 or we fill up the table, quit
if (classes[nCurClass].num == -1 || nCurClass > MAX_CLASSES-1)
bEnterMore = false;
}
}
That's the basic idea. Another improvement that could be made would be checking the length of the course title before assigning it to classes[].title. But you need something to do ;-)

Resources