Student Struct Troubles - c

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

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.

Allocating memory for a struct variable using a function

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.

What syntax am i missing out on regarding char arrays and pointers to them

I was doing some testing for a program of mine and was wondering why the program was crashing when entering my function. Don't mind the logic of the program, since i was still in the phase of making sure i understood how to use my tools at hand.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Constants */
#define HEX_CAPITAL_LETTERS_BEGIN 65
#define HEX_CAPITAL_LETTERS_END 90
#define HEX_NUMBERS_BEGIN 48
#define HEX_NUMBERS_END 57
#define EXIT_SUCCES 0
/* Prototypes */
void codeToField(char *charArray, int i, int hexFloor, int hexCeil, char *outputArray);
/* Main Function */
int main(void) {
char *code, warehouse, product, qualifiers;
int i = 0;
printf("Enter a MMOC product code: ");
scanf("%s", &code);
codeToField(code, i, HEX_CAPITAL_LETTERS_BEGIN, HEX_CAPITAL_LETTERS_END, &warehouse);
codeToField(code, i , HEX_NUMBERS_BEGIN, HEX_NUMBERS_END, &product);
strcpy(&qualifiers, code + i);
printf("\n\nWarehouse: %s\nProduct: %s\nQualifiers: %s\n", &warehouse, &product, &qualifiers);
return EXIT_SUCCES;
}
void codeToField(char *charArray, int i, int hexFloor, int hexCeil, char *outputArray) {
int j = 0;
while (charArray[i] >= hexFloor && charArray[i] <= hexCeil) {
outputArray[j] = charArray[i];
i++;
j++;
}
}
Thanks in advance.
First, this does not do what you want:
char *code, warehouse, product, qualifiers;
The only pointer is code, the other are just a single char. You're printing them as strings with printf, and you use warehouse and product as outputArray in your function. They need to be pointers (or arrays) too:
char *code, *warehouse, *product, *qualifiers;
Then you need memory. The pointers are still uninitialized, so any reading from them is undefined behavior.
You can either allocate memory with automatic storage duration (on the stack) or dynamically (on the heap).
Stack:
char codestr[100];
code = codestr;
but then, you could also just have declared code as
char code[100];
to avoid to have two variables.
If you want to allocate the memory dynamically, you would use malloc:
code = malloc(100);
Don't forget to free the memory again:
free(code);
warehouse, product, qualifiers all need memory too. Some of the array sizes could be deduced form the defined constants.
char *code, warehouse, product, qualifiers;
int i = 0;
printf("Enter a MMOC product code: ");
scanf("%s", &code);
Here, code is an uninitialized pointer to memory so once you do the scanf call, your program is hosed.
I think you want something more like
char code[100];
printf ("Enter a MMOC product code: ");
scanf ("%s", code);
The reason is because code has no memory allocated to it. It is an uninitialized pointer. Try this instead:
// ...
char myString[16], *code, warehouse, product, qualifiers;
code = &myString[0];
int i = 0;
printf("Enter a MMOC product code: ");
scanf("%15s", code);
// ...

Array of structs in c: giving all the strings same values (with the int it works well). What sould I do?

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.

How to return an array of structure by reference?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct data{
char name[20];
char lastname[25];
int age;
}person;
void insert(person *p,int *num);
int main()
{
int num;
person p;
insert(&p,&num);
printf("Name: %s",p[0].nome); /* Here i would print the first struct by
my array, but: is not array or not pointer Why?? */
}
void insert(person *p, int *num)
{
int dim;
person *arr;
printf("Insert how many people do you want? "); /* How many index the
array should have */
scanf("%d",&dim);
arr = (person *) malloc(dim*sizeof(person)); /* I'm not sure for
this explicit cast. */
for(int i = 0; i < dim; i++)
{
printf("Insert name: ");
scanf("%s",arr[i].name);
printf("Insert lastname: ");
scanf("%s",arr[i].lastname);
printf("Insert age:': ");
scanf("%d",&arr[i].age);
}
*num = dim;
*p = *arr;
}
I've tried: `person *insert(int *num)
And it's works,but how can pass an array reference?`
This programm should ask how many person do you want to insert ( in function insert) and with a for, he should ask name,surname,age.
After the insert, he should print, but for quick, i would tried with first element (index) of array (structs).
You can't return entire array from the function, but you can return the base location of the array. For example you can do like this : person *insert(int *sz);. But i see in your code you're passing &p and the &num variable into the insert method, maybe you want to modify them within that function and manipulate it afterwards in your main(). For that i would have these recommendations:
Change Line 16 person p to person *p. Since p is supposed to hold base value of an array. Remember array name is nothing but a base address to the first element of the list.
Change your function definition to recieve person** rather than person*. Since you want to modify a pointer variable and therefore you'd need a pointer to a pointer variable. Change it like this:` void insert(person **p, int *num)
Free the memory after usage; add a free(p) at the end of main.
`

Resources