Array of structs - How to create them correctly - c

I'm learning about structs and memory allocation.
One of the things i found out by studying was that there is not a way to see if a block of memory was allocated correctly.
I think it's working properly, but i was getting ready to read about linked lists and got all confused again.
I ask this, because on linked lists, i have seen:
typedef LIST* Lint;
int main(){
Lint *lint;
}
and by defining the type of class like this on my code:
typedef CLASS* t;
int main(){
t class; // WITHOUT THE * BEFORE class
}
it worked! I thought it would be ok, to give the definition like this. To me makes sense, the class is now a pointer to a type (type ie. CLASS);
So, am i on the right track or this working was pure luck?
The code structure sucks, but i'm still learning :)
typedef struct student {
char name[50];
int grade;
} TURMA;
typedef CLASS* t;
void showS(struct student i){
printf("Name of Student: %s \n Grade of Student: %d\n", i.name, i.grade);
}
void insert(struct student *i,int k){
char n[100]; int q=0;
printf("Define name of student %d\n", k+1); scanf("%s", n);
printf("Define the grade of %s\n", n); scanf("%d", &q);
strcpy(i->name,n);
i->grade = q;
}
int main()
{
t class;
int total,plus,i;
printf("Define number of total students: \n"); scanf("%d", &total);
class = (struct student*) malloc(total*(sizeof(CLASS)));
for(i=0; i<total; i++){
insert(&class[i], i);
}
printf("\n\nThis is the complete class: \n");
for(i=0; i<total; i++){
showS(class[i]);
}
printf("(Total size after malloc: %lu) Add more students (Int)\n",sizeof(*turma)); scanf("%d", &plus);
class = realloc(class, plus*sizeof(CLASS));
free(class);
printf("(Total size after malloc: %lu)", sizeof(*class));
return 0;
}

It is really hard to tell exactly what you are trying to accomplish. I looks like you are trying to create a singly-linked-list out of struct student with a typedef of struct student to TURMA. That's about where the useful information ends. Attempting to declare typedef CLASS* t; makes no sense. The compiler doesn't know what CLASS is. Guessing what you were attempting, the following is what flows from your code.
note: I added one function flush_stdin to empty stdin so you wouldn't have pesky newline characters left in the buffer. I also changed the scanf format string to prevent leaving newlines following your reading of character strings. Take a look below, and I'll look at your latest additions.
Also note in your code, you cannot free (class); then expect to take sizeof(*class)) -- that is undefined behavior.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 100
typedef struct student {
char name[50];
int grade;
} TURMA;
typedef TURMA* t;
void flush_stdin ()
{
int c = 0;
while ((c = getchar()) != '\n' && c != EOF);
}
void showS (TURMA i)
{
printf("Name of Student: %s \n Grade of Student: %d\n", i.name, i.grade);
}
void insert (t i, int k)
{
char n[MAXN] = {0}; int q=0;
printf("Define name of student %d\n", k+1); scanf ("%[^\n]%*c", n);
printf("Define the grade of %s\n", n); scanf("%d", &q); flush_stdin();
strcpy(i->name,n);
i->grade = q;
}
int main()
{
t class;
int total,plus,i;
printf("Define number of total students: \n"); scanf("%d", &total); flush_stdin();
class = malloc (total * sizeof *class);
if (!class) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
for (i=0; i<total; i++){
insert (&class[i], i);
}
printf("\n\nThis is the complete class: \n");
for (i=0; i<total; i++){
showS (class[i]);
}
printf("(Total size after malloc: %lu) Add more students (Int)\n", sizeof *class * total);
scanf("%d", &plus); flush_stdin();
TURMA *turma = realloc (class, plus * sizeof *turma);
if (!turma) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
free (class);
printf("(Total size after realloc: %lu)\n", sizeof *turma * (total + plus));
free (turma);
return 0;
}
Output
$ ./bin/llclass
Define number of total students:
2
Define name of student 1
John James
Define the grade of John James
8
Define name of student 2
Jill James
Define the grade of Jill James
9
This is the complete class:
Name of Student: John James
Grade of Student: 8
Name of Student: Jill James
Grade of Student: 9
(Total size after malloc: 112) Add more students (Int)
2
(Total size after realloc: 224)

Related

Structure function pointer parameter?

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.

How do I insert char* to array of structures?

the task is to dynamically allocate memory for the array of structures and then fill them from keyboard. I was able to dynamically allocate and fill amount of pages for each of the struct instance in array, but when I try to add char* to it by doing something like:
strcpy(myArray[i]->author, authorName);
But every time I get segmentation error, so what am I doing wrong?
Is it possible that problem is actually in memory allocation?
Here is the code
#include <stdlib.h>
#include <string.h>
struct Book {
char* author;
char* title;
int pages;
int pubYear;
int copies;
};
void allocList(struct Book **myArray, int booksAmount);
void fillKeyboard(struct Book **myArray, int booksAmount);
int main(void) {
struct Book *booksList = NULL;
int booksAmount = 3;
allocList(&booksList, booksAmount);
fillKeyboard(&booksList, booksAmount);
return 0;
}
void allocList(struct Book **myArray, int booksAmount) {
*myArray = (struct Book*) malloc(sizeof(struct Book) * 100);
printf("memory for %d books was allocated \n", booksAmount);
}
void fillKeyboard(struct Book **myArray, int booksAmount) {
int i = 0;
char* authorName = "author name";
while (booksAmount--) {
printf("book number %d \n", i + 1);
printf("enter amount of pages: ");
scanf("%d", &(*myArray)[i].pages);
printf("\nenter author: ");
strcpy(myArray[i]->author, authorName);
printf("%s is \n", authorName);
i++;
printf("\n");
}
}
Thank you.
myArray[i].author is a string.
so (in C) an array of char.
as an array you need to allocate it with a malloc
myArray[i].author=malloc(sizeof(char) * 100);
your while loop should look like this:
while (booksAmount--) {
myArray[i].author=malloc(sizeof(char) * 100);
printf("book number %d \n", i + 1);
printf("enter amount of pages: ");
scanf("%d", &(myArray)[i].pages);
printf("\nenter author: ");
strcpy(myArray[i].author, authorName);
printf("%s is \n", authorName);
i++;
printf("\n");
}
keep in mind that 100 is a "magic number" so if the author name is longer than 100 character it's not going to work
edit: same thing with the title, you need to allocate the needed memory in your array's element
If you care about memory, you should not create an array of 100 books. A good way to avoid such allocations is linked lists, so your program will always allocate just the needed memory. Your Book struct would look like this:
struct Book {
char* author;
char* title;
int pages;
int pubYear;
int copies;
struct Book *next;
};
The program will certainly be a bit more complex, but the result is a clean memory usage, and a truly dynamic program.

fgets taking struct pointer inside function crashes

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.

array of structs in c-user input

I am new to programming in general and to C in particular.
I am trying to write a program that uses an array of structs, but I am experiencing problems if that struct contains strings.
Somehow the compiler crashes after the user has given the last input.
The struct below is just a simplified version containing only one item, because the problem seems to be reading strings into the array.
Any help is much appreciated, thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char* name;
}student;
int main()
{
int size;
printf("enter number of entries\n");
scanf("%d" , &size);
student* all=malloc(size*sizeof(student));
int i;
for(i=0;i<size;i++)
{
printf("enter name\n");
scanf("%s" , all[i].name);
}
return 0;
}
Before taking input scanf("%s" , all[i].name); , you need to allocate memory to all[i].name .
An example-
for(i=0;i<size;i++)
{
all[i].name=malloc(20*sizeof(*(all[i].name)));
if(all[i].name!=NULL){
printf("enter name\n");
scanf("%19s" , all[i].name);
}
}
//use these strings
for(i=0;i<size;i++){
free(all[i].name); //free the allocated memory
}
free(all);
Or in your structure instead of char * ,declare name as a char array (if you don't want to use dynamic allocation)-
typedef struct{
char name[20]; //give any desired size
}student;
/* no need to free in this case */
No memory is allocated for the students names (char* name), so when trying to scanf to that pointer, invalid memory is accessed and the program crashes.
The easiest way is to declare name as an array: char name[28];
The return value of malloc() needs to be checked too, in case there was problem allocating the memory for the students, which would return a NULL pointer. At the end, the allocated memory needs to be freed with free().
For example:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[28];
unsigned int age;
} student;
int main()
{
size_t size = 0;
printf("\nEnter number of entries: ");
scanf("%zu", &size);
// add some check for size
student* students = (student*)malloc(size * sizeof(student));
if (students == NULL) {
printf("\nProblem with allocating memory:\n"
" - size: %zu\n"
" - total size needed: %zu\n",
size, size * sizeof(student));
return 0;
}
for (size_t i = 0; i < size; ++i) {
printf("Enter name: ");
scanf("%27s", students[i].name);
printf(" Enter age: ");
scanf("%u", &students[i].age);
}
printf("\nList of students:\n");
for (size_t i = 0; i < size; ++i) {
printf("%s (%u)\n", students[i].name, students[i].age);
}
free(students); // free the allocated memory
return 0;
}

Simple structure with dynamic memory allocation

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.

Resources