Malloc for structures - c

I am not getting the correct output here,
The code takes the no of inputs and option as an input, then takes the name of student year and gender and based on option provided gives the output. The output can be the name appearing first in the dictionary or the smaller value of the year amongst the inputs.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student_record
{
int passing_year;
char gender;
char name[20];
};
typedef struct student_record student;
student* find_specific(student* find, int option_num, int number)
{
int i;
student* temp = find;
int opt = option_num;
int num = number;
if(opt==1)
{
for(i=0; i<num; i++)
{
if( strcmp(temp->name, find[i].name) >0)
temp = find+i;
}
}
else
{
for(i=0; i<num; i++)
{
if (temp->passing_year > find[i].passing_year)
temp = find+i;
}
}
return temp;
}
int main() {
student* example;
student* final;
int i;
int option_num, number_of_students;
printf("Enter 2the number of students, option number");
scanf("%d" "%d", &number_of_students, &option_num);
example = (student* )malloc(number_of_students * sizeof(student));
printf("Enter the name, passing year and gender");
for(i=0; i< number_of_students; i++)
{
scanf("%s" "%d" "%c", example[i].name, &example[i].passing_year, &example[i].gender);
}
final = find_specific(example, option_num, number_of_students);
printf("%s" "%d" "%c", final->name, final->passing_year, final->gender );
return 0;
}
i am getting a segmentation fault. I can't figure out exactly where am I screwing up.

Your scanf() and printf() format strings are probably wrong.
scanf("%s" "%d" "%c", example[i].name, &example[i].passing_year, &example[i].gender);
should probably be
scanf("%s %d %c", example[i].name, &example[i].passing_year, &example[i].gender);
(without the extra quotes). The compiler will concatenate adjacent
string literals, so instead of a compiler error, it interpreted your format string as equivalent to "%s%d%c" (without whitespace in between).
That probably doesn't match the layout of your input, so some of the values were probably left uninitialized in a way that caused problems later.
You should always check the return value of scanf and similar library functions,
to ensure that you got the input format you told the compiler to expect.

Related

I can't seem to figure out why scanf in my code is acting so weird

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
# define ListSize 100
typedef int DataType;
typedef struct {
DataType elem[ListSize];
int length;
}SqList;
SqList * createList(int n)
{
SqList *L;
int i;
L=(SqList *)malloc(sizeof(SqList));
L->length=0;
printf("Input the elements:\n");
for (i=0;i<n;i++)
{
scanf("%d ",&(L->elem[i]));
L->length++;
}
return L;
}
void display(SqList *L)
{
int i;
for (i = 0; i < L->length; i++)
{
printf("%d\t" , L->elem[i]);
printf("\n");
}
}
int insert(SqList *L, int mark, DataType x)//Insert element x into list in the position mark
{
int i=0;
if(mark>L->length||mark<0)
return 0;
else
{
for (i=L->length-1;i>=mark;i--)
L->elem[i+1] = L->elem[i]; //move elements
L->elem[i+1]=x; //insert
L->length++;
return 1;
}
}
void main()
{
int num;
int in,loc;
SqList *List;
printf("Input the number of elements:");
scanf("%d",&num);
List=createList(num);
printf("\n The list is: \n");
display(List);
printf("Please input location and element to insert into the list: \n");
scanf("%d %d",&loc,&in);
insert(List,loc,in);
display(List);
}
So my assignment was to create a sequential list and insert an element into the user typed position in the list. I came up with the above code but my scanf function is acting weird. It asks me to type in the number of elements I want in the list but for some reason it takes one more input that it should. And that input actually goes to the value of variable loc. I can't seem to understand why it's working like that.
The problem is with the line
scanf("%d ",&(L->elem[i])); in createList. Specifically, the trailing space in the format string "%d " is consuming the carriage return when you enter the first number and you must type something else for the first call to scanf to complete. So when you think you're entering the second element, you're actually still giving input to the first scanf call. For more details on spaces in scanf format string, see this answer.
How does C treat trailing spaces in scanf?
Simply remove the trailing space "%d" and it will work as you intended.

Proper use of structures and pointers

I have to declare a vector with the "struct" type which, for every n students, it creates a value for the group that student belongs to (which is like a counter), their names and their grades.
The program has to output the name of the students with the highest grade found in these groups. I have to allocate the vector on the heap (I only know the theoretical explanation for heap, but I have no idea how to apply it) and I have to go through the vector using pointers.
For example if I give n the value 4, there will be 4 students and the program will output the maximum grade together with their names as shown here.
This will output Ana 10 and Eva 10.
I gave it a try, but I have no idea how to expand it or fix it so I appreciate all the help I can get with explanations if possible on the practical application of heap and pointers in this type of problem.
#include <stdio.h>
#include <stdlib.h>
struct students {
int group;
char name[20];
int grade;
};
int main()
{
int v[100], n, i;
scanf("%d", n);
for (i = 0; i < n; i++) {
v[i].group = i;
scanf("%s", v[i].name);
scanf("%d", v[i].grade);
}
for (i = 0; i < n; i++) {
printf("%d", v[i].group);
printf("%s", v[i].name);
printf("%d", v[i].grade);
}
return 0;
}
Here I was just trying to create the vector, nothing works though..
It appears, int v[100]; is not quite what you want. Remove that.
You can follow either of two ways.
Use a VLA. After scanning the value of n from user, define the array like struct students v[n]; and carry on.
Define a fixed size array, like struct students v[100];, and use the size to limit the loop conditions.
That said,
scanf("%d", n); should be scanf("%d", &n);, as %d expects a pointer to integer type argument for scanf(). Same goes for other cases, too.
scanf("%s", v[i].name); should better be scanf("%19s", v[i].name); to avoid the possibility of buffer overflow by overly-long inputs.
Even though you are asking for the number of students (groups) using scanf, you hardcoded the upper bound of this value using v[100]. So, I passed your input variable n (the number of students) to malloc in order to allocate the space you need for creating an array of n students.
Also, I used qsort to sort the input array v where the last element would be the max value. Here qsort accepts an array of structs and deference the pointers passed to the comp function to calculate the difference of the comparison.
Finally, I printed the sorted array of structs in the last loop.
#include <stdio.h>
#include <stdlib.h>
struct students {
int group;
char name[20];
int grade;
};
int comp(const void *a, const void *b)
{
return ((((struct students *)a)->grade > ((struct students *)b)->grade) -
(((struct students *)a)->grade < ((struct students *)b)->grade));
}
int main()
{
int n;
printf("Enter number of groups: ");
scanf("%d", &n);
printf("\n");
struct students *v = malloc(n * sizeof(struct students));
int i;
for(i = 0; i < n; i++)
{
v[i].group = i;
printf("\nName: ");
scanf("%s", v[i].name);
printf("Grade: ");
scanf("%d", &v[i].grade);
}
qsort(v, n, sizeof(*v), comp);
for(i = 0; i < n; i++)
{
printf("Group %d, Name %s, grade %d\n", v[i].group, v[i].name, v[i].grade);
}
return (0);
}
You need to replace the standalone array v[100], with an array of structs referencing your structure:
struct students v[100];
However, if you want to use malloc to allocate memory on the heap, you will need to do something like this:
struct students *students = malloc(n * sizeof(struct students));
/* Check void* return pointer from malloc(), just to be safe */
if (students == NULL) {
/* Exit program */
}
and free the requested memory from malloc() at the end, like this:
free(students);
students = NULL;
Additionally, adding to #Sourav Ghosh's answer, it is also good to check the return value of scanf(), especially when dealing with integers.
Instead of simply:
scanf("%d", &n);
A more safe way is this:
if (scanf("%d", &n) != 1) {
/* Exit program */
}
With all this said, your program could look something like this:
#include <stdio.h>
#include <stdlib.h>
#define NAMESTRLEN 20
typedef struct { /* you can use typedef to avoid writing 'struct student' everywhere */
int group;
char name[NAMESTRLEN+1];
int grade;
} student_t;
int
main(void) {
int n, i;
printf("Enter number of students: ");
if (scanf("%d", &n) != 1) {
printf("Invalid input.\n");
exit(EXIT_FAILURE);
}
student_t *students = malloc(n * sizeof(*students));
if (!students) {
printf("Cannot allocate memory for %d structs.\n", n);
exit(EXIT_FAILURE);
}
for (i = 0; i < n; i++) {
students[i].group = i;
printf("Enter student name: ");
scanf("%20s", students[i].name);
printf("Enter students grade: ");
if (scanf("%d", &(students[i].grade)) != 1) {
printf("Invalid grade entered.\n");
exit(EXIT_FAILURE);
}
}
printf("\nStudent Information:\n");
for (i = 0; i < n; i++) {
printf("Group: %d Name: %s Grade: %d\n",
students[i].group,
students[i].name,
students[i].grade);
}
free(students);
students = NULL;
return 0;
}

I can't type all the information in an array of structs

When I try to compile this small program everything is correct but when I run it I find some problems. For example, I can't type the "c" variable in the second element of the table and so on.
#include <stdio.h>
struct point{
char c;
int x,y;
};
int main(void)
{
int size = 4;
struct point tp[size];
for(int i = 0; i < size; i++ )
{
printf("entrer le nom du point no %d: ", i+1);
tp[i].c = fgetc(stdin);
printf("x = ");
scanf("%d", &tp[i].x);
printf("y = ");
scanf("%d", &tp[i].y);
}
}
There are a lots of similar questions here, for example: C scanf() and fgets() problem, fgets doesn't work after scanf.
You could use fgets() for user input and parse string with sscanf() for example.
Or you can use fgetc(stdin); after each scanf() to get rid of '\n' symbol.

How to acces pointer in a structure

This is my code :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct pers
{
int age;
char *name;
float height;
}Person;
void read(Person p[], int *nr) // an array of persons, and nr is the number of persons
{
scanf("%d", nr);
int i;
for(i = 0; i < *nr; i++)
{
scanf("%d", &p[i].age);
p[i].name = calloc(100, sizeof(char));
scanf("%s", p[i].name);
scanf("%f", &p[i].height);
}
}
int main()
{
int nr;
Person p[100];
int i;
read(p, &nr);
for(i = 0; i < nr; i++)
{
printf("%d\n", p[i].age);
printf("%s\n", p[i].name);
printf("%f\n", p[i].height);
}
return 0;
}
I don't know why this not stocate well the data . How can i do with pointers or anything else, to have acces to age and height and also to the *name
If i try only with age and height the code works, but when i add the name, it stucks.
this is my input
3 // numbers of persons
23 // age
John Smith //firstname + lastname //1person
182.5 //height
18
Mat Plow //2person
152.6
56
Alex Grim //3person
172
Any ideas?
i think i might use gets and with some pointer, but i don't know how :D
Thank you !
Because there is nothing wrong with your code, there must be something wrong with your scanf input specification. Check/read the input format specifier documentation. For '%s' it says: "String, up to first white-space character (space, tab or newline)" so if name is "Firstname Lastname" it will only read "Firstname".
Also, you can add debug statements to see what has been read so-far, or you can use a debugger to step through the code to see what happens. A scanf-guru can tell you right away what's wrong; all others must read the documentation.
scanf(" %[^\n]s", p[i].name);
This is what works for me !
Change your scanf call to this:
scanf("%s\n", p[i].name);
Please note the \n added.

Expression must have class type error

I'm working on a homework assignment and I've hit a brick wall. I think I have all of the code that I need, I just need to get the program to compile. The object of the assignment is
Create a structure to hold student names and averages. The structure should contain a first name, last name and an integer grade average.
Then:
Write a program that will do the following:
1.) Create an array of pointers to these student structures.
2.) Prompt the user for names and averages.
3.) After you get the student’s information use malloc to provide the memory to store the information.
4.) Place the address of the student, returned by malloc, into the pointer array.
5.) AFTER the user indicates there are no more students:
Search the data entered and find the highest and lowest grade
average.
a)Print the name and grade for the highest grade
b)Print the name and grade for the lowest grade
c)Print the average of all grades entered
Here is my code:
#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
#define SIZE 25
int enterStudents (int ePointArray[SIZE]);
void searchData (int *sPointArray, int *sHigh, int *sLow);
int calculateAvg (int, int *avgPointArray);
void printData (int, int *pHigh, int *pLow);
struct student
{
char firstName[20];
char lastName[20];
int average;
};
int main()
{
int pointArray[SIZE], high[3], low[3];
int i = 0, studentCounter, avgGrade;
for (i = 0; i < SIZE; i++)
pointArray[i] = 0;
studentCounter = enterStudents(pointArray);
searchData(pointArray, high, low);
avgGrade = calculateAvg(studentCounter, pointArray);
printData(avgGrade, high, low);
return 0;
}
int enterStudents (int ePointArray[SIZE])
{
char tempFname[20], tempLname[20], yesNo[2] = "y";
int tempAvg, counter = 0;
int *studPtr;
struct student aStud={"\0", "\0", 0};
while( counter < SIZE && strcmp(yesNo, "y")==0)
{
printf(" Enter first name: ");
scanf("%s", tempFname);
printf(" Enter last name: ");
scanf("%s", tempLname);
printf(" Enter grade average:");
scanf("%d", tempAvg);
strcpy(aStud.firstName, tempFname);
strcpy(aStud.lastName, tempLname);
aStud.average = tempAvg;
studPtr = malloc(sizeof(struct student));
ePointArray[counter] = *studPtr;
counter++;
printf("/n");
printf(" Do you have more students? yes or no:");
scanf("%s", yesNo);
}
return counter;
}
void searchData (int sPointArray[SIZE], int sHigh[3], int sLow[3])
{
int searchCounter = 0;
while( searchCounter = 0)
{
if( *sPointArray[searchCounter].average > *sPointArray[searchCounter+1].average)
{
sHigh[0] = &sPointArray[searchCounter].firstName;
sHigh[1] = &sPointArray[searchCounter].lastName;
sHigh[2] = &sPointArray[searchCounter].average;
}
if( *sPointArray[searchCounter].average < *sPointArray[searchCounter+1].average)
{
sLow[0] = &sPointArray[searchCounter].firstName;
sLow[1] = &sPointArray[searchCounter].lastName;
sLow[3] = &sPointArray[searchCounter].average;
}
searchCounter++;
}
}
int calculateAvg( int totalStudents, int avgPointArray[SIZE])
{
int sum = 0;
int avgCounter;
double overallAvg;
for( avgCounter = 0; avgCounter < totalStudents; avgCounter++)
sum = sum + *avgPointArray[avgCounter].average;
overallAvg = sum/totalStudents;
return overallAvg;
}
void printData (int pAverage, int pHigh[3], int pLow[3])
{
printf(" Highest Grade: %s %s %d", pHigh[0], pHigh[1], pHigh[3]);
printf("/n");
printf(" Lowest Grade: %s %s %d", pLow[0], pLow[2], pLow[3]);
printf("/n");
printf(" Average Grade: %d",pAverage);
}
The main chunk of problems come from the searchData function. In the if statements, every occurrence of *sPointArray and &sPointArray is underlined in red and the error reads
"Error: expression must have class type"
The same thing also happens in the calculateAvg function with *avgPointArray in the for loop. I know that the error is a fairly common problem for noobie C programmers (i.e myself) and that it generally has to do with writing the code as a function instead of a statement or something like that, but I can't for the life of me find where I have went wrong. Any help would be highly appreciated. I've been working at this for so long my vision is blurring.
Also, for anyone who solves this in like two seconds and wants proof that I'm a true idiot, there is an error in the enterStudents function where it says StudPtr = malloc(sizeof...). The error shows under the assignment symbol and says
"Error: a value of type "void*" cannot be assigned to an entity of type "int*".
I understand this concept in theory, but some advice for how to fix it would be highly appreciated.
Thank you in advance for any help.
You declare the sPointArray as an array of integers, but use it as an array of structures.

Resources