Here's the part of my code:
Problem: It skips the input of "please enter your name" to "please enter your marks"
What I tried: flushall(); _flushall(); - which worked yesterday somehow, and trying to place these functions between printf,scanf..
student *Create_Class(int size) {
int i, j;
int idStud, nameStud, markStud;
student *classStudent;
classStudent = (student*)malloc(size * sizeof(student));
for (i = 0; i < size; i++) {
classStudent[i].name = (char*)malloc(51 * sizeof(char));
int numOfmarks = 4;
printf("Please enter your name: ");
gets(classStudent[i].name);
_flushall(); //tried _flushall() and it worked yesterday.. tried fflush(NULL) too.
printf("\nPlease enter 4 marks: ");
for (j = 0; j < numOfmarks; j++) {
scanf("%d", &classStudent[i].marks[j]);
}
Avg_Mark(&classStudent[i]);
}
return classStudent;
}
EDIT: (FULL CODE)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
typedef struct {
char *name;
int marks[4];
float avg;
} student;
student *Create_Class(int);
void Avg_Mark(student*);
void Print_One(student*);
void exStudents(student *s, int size);
int main() {
int size, i;
student *arr;
printf("\nEnter the number of students: \n");
scanf("%d", &size);
arr = Create_Class(size);
exStudents(arr, size);
for (i = 0; i < size; i++)
free(arr[i].name);
free(arr);
getch();
}
student *Create_Class(int size) {
int i, j;
int idStud, nameStud, markStud;
student *classStudent;
classStudent = (student*)malloc(size * sizeof(student));
for (i = 0; i < size; i++) {
classStudent[i].name = (char*)malloc(51 * sizeof(char));
int numOfmarks = 4;
int sizeOfName;
printf("Please enter your name: \n");
_flushall();
fgets(classStudent[i].name,50,stdin);
sizeOfName = strlen(classStudent[i].name);
printf("Please enter 4 marks: ");
for (j = 0; j < numOfmarks; j++) {
scanf("%d", &classStudent[i].marks[j]);
}
Avg_Mark(&classStudent[i]);
}
return classStudent;
}
void Avg_Mark(student *s) {
int i, numOfMarks = 4, sum = 0;
for (i = 0; i < numOfMarks; i++) {
sum += s->marks[i];
}
s->avg = (sum / 4.0);
}
void Print_One(student *s) {
printf("The average of %s is %f", s->name, s->avg);
}
void exStudents(student *s, int size) {
int flag = 1;
while (size > 0) {
if (s->avg > 85) {
Print_One(s);
flag = 0;
}
s++;
size--;
}
if (flag)
printf("\n There're no students with above 85 average.");
}
As you have already been told in comments, the solution is to use a two-step approach: Read lines first, then scan these lines as appropriate. This reflects how users are going to answer your prompts, namely by providing the information and then hitting enter.
Here's a variant of your code which does that. I've also changed the main function, because it also used scanf and I've added a function to strip white space from the string input by fgets. (This function requires the <ctype.h> header.)
#include <ctype.h>
int main()
{
char line[80];
int size, i;
puts("Enter the number of students:");
if (fgets(line, sizeof(line), stdin) == NULL) exit(1);
if (sscanf(line, "%d", &size) == 1 && size > 0) {
student *arr = Create_Class(size);
exStudents(arr, size);
for (i = 0; i < size; i++) free(arr[i].name);
free(arr);
}
return 0;
}
/*
* strip white space from beginning and end of string
*/
char *strip(char *str)
{
size_t l = strlen(str);
while (l > 0 && isspace((unsigned char) str[l - 1])) l--;
str[l] = '\0';
while (isspace((unsigned char) *str)) str++;
return str;
}
/*
* Create students and prompt user for input
*/
student *Create_Class(int size)
{
int i;
student *classStudent = malloc(size * sizeof(student));
for (i = 0; i < size; i++) {
char line[80];
char *p;
int okay = 0;
puts("Please enter your name:");
if (fgets(line, sizeof(line), stdin) == NULL) exit(1);
p = strip(line);
classStudent[i].name = malloc(strlen(p) + 1);
strcpy(classStudent[i].name, p);
while (!okay) {
int j = 0;
okay = 1;
puts("Please enter 4 marks:");
if (fgets(line, sizeof(line), stdin) == NULL) exit(1);
p = line;
while (p && j < 4) {
char *tail;
int m = strtol(p, &tail, 10);
if (p == tail) break;
if (m < 1 || m > 100) {
puts("Illegal mark.");
okay = 0;
}
classStudent[i].marks[j++] = m;
p = tail;
}
if (j < 4) {
printf("Expected 4 marks, but got %d.\n", j);
okay = 0;
}
}
Avg_Mark(&classStudent[i]);
}
return classStudent;
}
Please refrain from flushing buffers wihout reason. When a new-line character is written, stdout is flushed, so make it a rule to terminate all your strings with a new-line. New-lines at the beginning of strings instead of at the end are a sign of untidy output.
SOLUTION:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
typedef struct { //struct decleration
char *name;
int marks[4];
float avg;
} student;
//functions decleration
student *Create_Class(int);
void Avg_Mark(student*);
void Print_One(student*);
void exStudents(student *s, int size);
int main() {
/*variable declerations*/
int i, size;
char line[80];
student *arr;
/*Input number of students*/
printf("\nEnter the number of students: \n");
fgets(line, sizeof(line), stdin);
sscanf(line, "%d", &size);
/*Get name of students, marks, and calculate average above 85*/
arr = Create_Class(size);
exStudents(arr, size);
/*Free memory*/
for (i = 0; i < size; i++)
free(arr[i].name);
free(arr);
getch();
}
student *Create_Class(int size) { /*Get names of each student, and their 4 marks.*/
/*Variable declerations*/
int i, j;
char line[51];
student *classStudent;
/*Dynamic allocation to assign structure to every student*/
classStudent = (student*)malloc(size * sizeof(student));
/*Get name of students and their 4 marks*/
for (i = 0; i < size; i++) {
/*Variable decleration and dynamic allocation of 51 chars*/
classStudent[i].name = (char*)malloc(51 * sizeof(char));
int numOfmarks = 4;
int sizeOfName;
/*Input name of student*/
printf("Please enter your name: \n");
scanf("%s", classStudent[i].name);
/*Input marks of student*/
printf("Please enter 4 marks: ");
for (j = 0; j < numOfmarks; j++) {
scanf("%d", &classStudent[i].marks[j]);
}
/*Calculate average, and print averages of students above 85*/
Avg_Mark(&classStudent[i]);
}
return classStudent;
}
/*Calculate averages of students*/
void Avg_Mark(student *s) {
int i, numOfMarks = 4, sum = 0;
for (i = 0; i < numOfMarks; i++) {
sum += s->marks[i];
}
s->avg = (sum / 4.0);
}
/*Print average (if bigger than 85)*/
void Print_One(student *s) {
printf("The average of %s is %0.1f\n", s->name, s->avg);
}
/*Check whether the average is bigger than 85*/
void exStudents(student *s, int size) {
int flag = 1; //flag to check if there are any students with avg above 85
while (size > 0) {
if (s->avg > 85) {
Print_One(s); //Print the average
flag = 0; //We found atleast one student with avg > 85
}
s++; //Advance to next student
size--;
}
if (flag)
printf("\n There're no students with above 85 average.");
}
The problem in your code is that scanf does not consume the new-line returned by the user in:
scanf("%d", &size);
So when the program reaches:
fgets(classStudent[i].name,50,stdin);
the remaining new-line in stdin is received before the user can type anything.
A solution is to replace the initial scanf call by fgets and atoi calls.
char size_str[5];
fgets(size_str,5,stdin);
size = atoi(size_str);
A combination of fgets and sscanf also works also fine in general to first process user inputs and then convert it.
The variant with sscanf is:
char size_str[5];
fgets(size_str,5,stdin);
sscanf(size_str,"%d\n",&size);
Note that it might be safe to stop the program if the value entered is too large. Here we allow from 0 up to 999.
Note also that you have to do the same change some lines below.
instead of:
scanf("%d", &classStudent[i].marks[j]);
write:
char mark_str[5];
fgets(mark_str,5,stdin);
sscanf(mark_str,"%d\n",&classStudent[i].marks[j]);
Hope this helps.
Related
code: (at //right here is the line that doesnt work)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void insert(int size, char *arr);
void swap(char *arr, int pos1, int pos2);
void printList(int size, char *arr);
int main()
{
int size = 0;
do
{
printf("Put in size of the list (Range[1;2^16-1]): ");
scanf(" %d", &size);
if (size < 0)
printf("Put in a correct length!\n");
} while (size <= 0);
printf("Put in ur List: ");
char buffer[size];
int errFlag;
do
{
errFlag = 1;
while (fgets(buffer, size + 2, stdin))
{
}
for (int i = 0; i < size; i++)
if (!isdigit(buffer[i]))
errFlag = 0;
if (errFlag == 0)
printf("Input failed try again:");
} while (errFlag == 0);
char *list = malloc(size*sizeof(char));
strcpy(list, buffer);
insert(size, list);
printList(size, list);
int input = 0;
do
{
printf("\nDo u want to add another element(0) or a list(1)? If u want to stop type (2): ");
scanf(" %d", &input);
if (input != 0 && input != 1 && input != 2)
printf("\nInput failed try again: ");
else if (input == 1)
{
int tempElem = 0;
printf("Input ur element: ");
scanf(" %d", &tempElem);
size++;
printf("%d", tempElem);
list = (char *)realloc(list, size + 1); //right here
list[size-1]=tempElem;
printf("New ");
insert(size, list);
printList(size, list);
}
} while (input != 0);
return 0;
}
void insert(int size, char *arr)
{
for (int i = 1; i < size; i++)
for (int j = i - 1; j >= 0; j--)
if (arr[j] > arr[j + 1])
swap(arr, j, j + 1);
else
j = 0;
}
void swap(char *arr, int pos1, int pos2)
{
char temp = arr[pos1];
arr[pos1] = arr[pos2];
arr[pos2] = temp;
}
void printList(int size, char *arr)
{
printf("ArrayList: ");
for (int i = 0; i < size; i++)
{
printf("[");
printf("%d", arr[i]-48);
printf("] ");
}
}
My code works properly until the reallocation, but i dont get an error. The programm just stops (VScode). I did some research but didnt find any solution.
Output:
Put in size of the list (Range[1;2^16-1]): 3
Put in ur List: 123
^Z (my input to stop f gets)
ArrayList: [1] [2] [3]
Do u want to add another element(0) or a list(1)? If u want to stop type (2): 1
Input ur element: 3
3
Then it stops. Normally i would expect: New ArrayList: [1] [2] [3] [4]
I have made one program, where you enter a few characters (10 max). It makes you a list, count average length of surnames, tell about how much different names. But the problem is, when I enter the last number (10) - it sorts me it incorrectly (like 39399349349, 3443993). Beneath I will present my code. I am newbie in C, so please don't shut on me) I am convinced that sorting function is incorrect, but don't know what exactly(
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct people {
int num[10];
char surname[20];
char name[10];
} peoples[10], c;
int compare_people_num(const void *a, const void *b);
int main()
{
int i, j, k = 0, l = 0, m = 0, n = 0;
float s = 0;
char str[100];
system("chcp 1251 > nul");
for (i = 0, j = 0; i < 10; i++, j++)
{
printf("Enter number, surname, name %d of your human: ", i + 1);
fgets(str, sizeof str, stdin);
sscanf(str, "%d %s %s", &peoples[j].num, &peoples[j].name, &peoples[j].name);
while (str[n] != '\n')
{
if (str[n] != ' ')
{
peoples[j].num[k] = str[n];
}
else
break;
n++;
k++;
}
n++;
k = 0;
while (str[n] != '\n')
{
if (str[n] != ' ')
{
peoples[j].surname[k] = str[n];
}
else
break;
n++;
k++;
}
n++;
k = 0;
while (str[n] != '\n')
{
if (str[n] != '\0')
{
peoples[j].name[k] = str[n];
}
else
break;
n++;
k++;
}
n = 0;
k = 0;
}
for (i = 0; i < 10; i++)
{
for (j = i + 1; j < 10; j++)
{
if (!strcmp(peoples[i].name, peoples[j].name))
m = 1;
}
if (m == 0)
l++;
m = 0;
s = s + strlen(peoples[i].surname);
}
for (i = 0; i < 9; i++)
for (j = 0; j < 9; j++)
if (strcmp(peoples[j].num, peoples[j+1].num) > 0)
{
qsort(peoples, 10, sizeof(struct people), &compare_people_num);
}
for (i = 0; i < 10; i++)
{
printf("%d ", peoples[i].num);
printf("%s ", peoples[i].name);
printf("%s ", peoples[i].surname);
printf("\n");
}
printf("\nYou have %d different names\n", l);
printf("Avarege lenght of surname is = %f\n", s / 10);
}
int compare_people_num(const void *a, const void *b)
{
const struct people *p1 = a;
const struct people *p2 = b;
return p1->num - p2->num; // Change order to reverse sort
}
I went through your code and removed things that weren't needed. In both your input and sorting, it seemed like you were doing things twice. I tried to document the changes I made and explain why they should be made.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// It's generally a good idea to use #define when you have some global constants
// I made some of the constants larger than what you showed to prevent issues
#define MAX_NAME_LEN 40
#define MAX_SURNAME_LEN 40
#define NUM_PEOPLE 10
#define BUFF_LEN 100
// Separate your struct...
struct person {
int num;
char name[MAX_NAME_LEN];
char surname [MAX_SURNAME_LEN];
};
// ... and array decleration
static struct person people[NUM_PEOPLE];
// I added this function, to make it easier to display a person
void print_person (const struct person * p) {
printf("Person %d %s %s\n", p->num, p->name, p->surname);
}
// This function will print out every person in the people array
void print_people (void) {
for (int i=0; i<NUM_PEOPLE; i++) {
print_person(&people[i]);
}
}
// Compares two people by number
int compare_people_num (const void * a, const void * b) {
struct person * p0 = (struct person *) a;
struct person * p1 = (struct person *) b;
return p0->num - p1->num;
}
// Compares two people by name
int compare_people_name (const void * a, const void * b) {
struct person * p0 = (struct person *) a;
struct person * p1 = (struct person *) b;
return strcmp(p0->name, p1->name);
}
int main (void) {
int i;
char buffer[BUFF_LEN];
for (i=0; i<NUM_PEOPLE; i++) {
printf("Enter number, surname, and name of person %d: ", i+1);
fflush(stdout); // fflush makes sure that our text is shown to the user
fgets(buffer, BUFF_LEN, stdin); // Read user input in to buffer
// It's unclear what you were doing here
// This sscanf line takes a line of text, and splits it into a number and two words
// It then stores that number in people[i].num, and stores the words in name and surname
// However, right after this, you have several while loops that appear to be manually doing the same
// thing all over again. If you want to read all of the input in, just the line below is enough
sscanf(buffer, "%d %s %s", &people[i].num, people[i].name, people[i].surname);
}
// We've read all of the people in now
// Uncomment the next line to check out the output at this state:
// print_people();
// To count names, we first need to sort the people by their name
// We do this using a qsort call
qsort(people, NUM_PEOPLE, sizeof(struct person), compare_people_name);
// Once the names are sorted, we'll calculate how many different names there are
// We start the count at 1, and start checking from the second person (index 1)
// This is because the first person will always be unqiue, and we can't compare to
// person negative 1
int n_names = 1;
for (i=1; i<NUM_PEOPLE; i++) {
char * current = people[i].name;
char * previous = people[i-1].name;
if (!strcmp(current, previous)) {
n_names ++;
}
}
// Now we have to sort the people based on their num field
// Again, in your code, it looked like you were doing this more than nessecary
// We just have to call qsort once, as such
qsort(people, NUM_PEOPLE, sizeof(struct person), compare_people_num);
// We will also do a loop through to calculate the average surname length
float avg_surname_len = 0;
for (i=0; i<NUM_PEOPLE; i++) {
avg_surname_len += (float)strlen(people[i].surname);
}
avg_surname_len /= (float)NUM_PEOPLE;
// We're all done! The people are sorted by number.
print_people();
printf("There are %d unique names\n", n_names);
printf("The average surnames is %f characters\n", avg_surname_len);
}
I am trying to change the sorting of a the arr list which could consist of zero, one, two as the inputted and stored values for arr. The stringreplace function is meant to shift every single element by one so the new sorting would be one, two, zero. I am trying to replace the elements with one another by using the strncpy function but I think it is a bit faulty, how could i fix this?
strncpy function
char stringreplace( char a[], int b){
for(int j = 0; j > b -1; j++){
strncpy(a[j], a[j+1], sizeof(a));}
for(int j = 0; j > b; j++){
printf("%s",a[j]);}
}
main function
int main()
{
char input[100];
char arr[100]= {0};
int number;
printf("Input the number of strings: ");
scanf("%d", &number);
for(int i= 0; i < number; i++){
printf("Input the number of strings: ");
scanf("%s", input);
arr[i] = input;
}
stringreplace(arr, number);
return 0;
}
You may consider allocating strings dynamically, assigning a pointer for each string into an array words, and then rotating each pointer in the array to the left.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void lrot_words(char *words[], int n);
int main(void)
{
char *p, word[100], *words[100];
int i, num_words;
printf("Enter the number of words: ");
scanf("%d", &num_words);
for(i = 0; i < num_words; i++){
printf("Enter a word: ");
scanf("%s", word);
if ((p = malloc(strlen(word) + 1)) == NULL) {
fprintf(stderr, "Error: malloc failed\n");
exit(EXIT_FAILURE);
}
words[i] = strcpy(p, word);
}
lrot_words(words, num_words);
for (i = 0; i < num_words; i++) {
printf("%s\n", words[i]);
}
return 0;
}
void lrot_words(char *words[], int n)
{
char *temp = words[0];
int i;
for (i = 0; i < n - 1; i++) {
words[i] = words[i+1];
}
words[i] = temp;
}
I created a code with 4 functions:
Data_duplication that checks if the name is already exists.
Init that the function initializes through input from the user a set of names and a set of scores. Both arrays of the same size which called size. Whenever data is collected for arrays, they must be valid. If the user typed an invalid name, an error message should be printed and an alternate statistic requested. A valid score is complete between 0 and 100. A valid name meets the following conditions:
Begins with a large Latin letter.
All but the first characters are lowercase Latin characters.
Not already in the array. (The array must not contain the same name twice.)
Find function that gets as parameters, an array of names, an array of grades, and the size of these arrays. In addition, it receives as a student name parameter. The function finds the student's position in the array of names, and returns its grade. If the student does not appear in the set, 1- will be returned.
FreeAll that frees all the memory from the arrays.
PROBLEM:
When i enter for example that there are 3 students it is asking from me to write a fourth student and then it writes a grade that I don't know from where and gets out of the program.
Code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#define SIZE 20
int Data_duplication(char* temp, char** names, int line);
void Init(char*** names, int** grades, int* size);
int Find(char** names, int* grades, int size, char* name);
void FreeAll(char*** names, int** grades, int size);
int main()
{
char** Names = NULL;
int* Grades = NULL;
int size, grade;
char name[SIZE] = { 0 };
Init(&Names, &Grades, &size);
printf("Enter a student name\n");
scanf("%s", name);
grade = Find(Names, Grades, size, name);
printf("%d", grade);
FreeAll(&Names, &Grades, size);
return 0;
}
void Init(char*** names, int** grades, int* size)
{
int i, j, flag;
int strlengh;
char temp[SIZE] = { 0 };
printf("Enter number of students\n");
scanf("%d", size);
*names = (char**)malloc((*size) * sizeof(char*));
if (!(*names))
{
printf("Error");
return;
}
*grades = (int*)malloc((*size) * sizeof(int));
if (!*grades)
{
printf("Error");
return;
}
for (i = 0; i < *size; i++)
{
printf("Enter a name\n");
scanf("%s", temp);
strlengh = strlen(temp);
do
{
flag = 1;
if (strlen(temp) > 20)//if it longer then it should be
flag = 0;
if (temp[0] > 'Z' || temp[0] < 'A') //start with capital letter
flag = 0;
for (j = 1; temp[j] != '\0'; j++)//all the letter is a lower case letters except from the first
{
if (temp[j] > 'z' || temp[j] < 'a')
{
flag = 0;
break;
}
}
if (Data_duplication(temp, *names, i))//if its not a name that already entered
{
flag = 0;
}
if (flag)//if the name is ok
{
(*names)[i] = (char*)malloc((strlengh + 1) * sizeof(char));
if (!(*names)[i])
{
printf("Error");
return;
}
strcpy((*names)[i], temp);
}
else//if somthing wrong
{
printf("Bad name,try again.\n");
scanf("%s", temp);
}
} while (!flag);
printf("Enter grade\n");
scanf("%d", (*grades + i));
while (*(*grades + i) < 0 || *(*grades + i) > 100)//if the grade between 0 to 100
{
printf("Bad grade,try again.\n");
scanf("%d", (*grades + i));
}
}
}
int Data_duplication(char* temp, char** names, int line)//find if there is another name like this that already entered
{
for (int i = 0; i < line; i++)
{
if (!strcmp(temp, names[i]))
{
return 1;
}
}
return 0;
}
int Find(char** names, int* grades, int size, char* name)
{
int i;
for (i = 0; i < size; i++)
{
if (strcmp(name, names[i]) == 0);
{
return (*(grades + i));
}
}
return -1;
}
void FreeAll(char*** names, int** grades, int size)//free al the dynamic memo allocation
{
for (int i = 0; i < size; i++)
{
free(*(*names + i));
}
free(*names);
free(*grades);
}
arrays passed by reference so you don't need to pass pointer to array.
I made changes in your code.
#include <stdio.h>
#include <stdlib.h>
#include<malloc.h>
#include<string.h>
#define SIZE 20
int Data_duplication(char* temp, char** names, int line);
void Init(char** names, int* grades, int size);
int Find(char** names, int* grades, int size, char* name);
void FreeAll(char** names, int* grades, int size);
int main()
{
int size, grade;
char name[SIZE];
printf("Enter number of students\n");
scanf("%d", &size);
char** Names=(char**)malloc((size) * sizeof(char*));
int* Grades= (int*)malloc((size) * sizeof(int));
Init(Names, Grades, size);
printf("--------------------------------------------------------------------\n");
printf("Enter a student name\n");
scanf("%s",name);
grade = Find(Names,Grades,size,name);
printf("%d", grade);
FreeAll(Names, Grades, size);
return 0;
}
void Init(char** names, int* grades, int size)
{
int i, j, flag;
int strlengh;
if (!(names))
{
printf("Error");
return;
}
for(i = 0; i < size ; i++){
names[i] = malloc(sizeof(char)*SIZE);
if(!names[i])
{
printf("Error");
return;
}
}
if (!grades)
{
printf("Error");
return;
}
for (i = 0; i < size; i++)
{
printf("Student i= %d\n",i);
do
{
char temp[SIZE]="";
printf("Enter a name\n");
scanf("%s", temp);
strlengh = strlen(temp);
flag = 1;
if (strlen(temp) > SIZE)//if it longer then it should be
flag = 0;
if (temp[0] > 'Z' || temp[0] < 'A') //start with capital letter
flag = 0;
for (j = 1; temp[j] != '\0'; j++)//all the letter is a lower case letters except from the first
{
if (temp[j] > 'z' || temp[j] < 'a')
{
flag = 0;
break;
}
}
if (Data_duplication(temp, names, i))//if its not a name that already entered
{
flag = 0;
}
if (flag)//if the name is ok
{
strcpy(names[i], temp);
printf("temp= %s\n", temp);
printf("names[i]= %s\n", names[i]);
}
else//if somthing wrong
{
printf("Bad name,try again.\n");
}
} while (!flag);
printf("Enter grade\n");
scanf("%d",&grades[i]);
while (grades[i] < 0 || grades[i] > 100)//if the grade between 0 to 100
{
printf("Bad grade,try again.\n");
scanf("%d",&grades[i]);
}
}
}
int Data_duplication(char* temp, char** names, int line)//find if there is another name like this that already entered
{
for (int i = 0; i < line; i++)
{
if (!strcmp(temp, names[i]))
{
return 1;
}
}
return 0;
}
int Find(char** names, int* grades, int size, char* name)
{
int i;
for (i = 0; i < size; i++)
{
printf("name= %s\n",name);
printf("names[i]= %s\n", names[i]);
if (strcmp(name, names[i]) == 0)
{
return (grades[i]);
}
}
return -1;
}
void FreeAll(char** names, int* grades, int size)//free al the dynamic memo allocation
{
for (int i = 0; i < size; i++)
{
free(names[i]);
}
free(names);
free(grades);
}
I've got a task to get no. of students, get their name and marks and output the students which has average over 85.
The problem: After I enter blabla 99 98 95 90, I don't get the appropriate message. what I get is just some kind random of average instead. I mean, Print_One() isn't executed after that input. (Failing to print the average above 85)
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
typedef struct {
char *name;
int marks[4];
float avg;
} student;
student *Create_Class(int);
void Avg_Mark(student*);
void Print_One(student*);
void exStudents(student *s, int size);
int main() {
int size, i;
student *arr;
printf("\nEnter the number of students: \n");
scanf("%d", &size);
arr = Create_Class(size);
exStudents(arr, size);
for (i = 0; i < size; i++)
free(arr[i].name);
free(arr);
getch();
}
student *Create_Class(int size) {
int i, j;
int idStud, nameStud, markStud;
student *classStudent;
classStudent = (student*)malloc(size * sizeof(student));
for (i = 0; i < size; i++) {
classStudent[i].name = (char*)malloc(51 * sizeof(char));
int numOfmarks = 4;
int sizeOfName;
printf("Please enter your name: \n");
flushall();
gets(classStudent[i].name);
sizeOfName = strlen(classStudent[i].name);
/*
if (classStudent[i].name > 50) {
classStudent[i].name = realloc(classStudent[i].name, 51);
classStudent[i].name[51] = '\0';
} else {
classStudent[i].name = realloc(classStudent[i].name, sizeOfName + 1);
}
*/
printf("Please enter 4 marks: ");
for (j = 0; j < numOfmarks; j++) {
scanf("%d", &classStudent[i].marks[j]);
}
Avg_Mark(&classStudent[i]);
}
return classStudent;
}
void Avg_Mark(student *s) {
int i, numOfMarks = 4, sum = 0;
for (i = 0; i < numOfMarks; i++) {
sum += s->marks[i];
}
s->avg = (sum / 4.0);
}
void Print_One(student *s) {
printf("The average of %s is %f", s->name, s->avg);
}
void exStudents(student *s, int size) {
int flag = 1;
while (size > 0) {
if (s->avg > 85) {
Print_One(s);
flag = 0;
}
s++;
size--;
}
if (flag)
printf("\n There're no students with above 85 average.");
}
If your input is like this:
1
blabla
99 98 95 90
The first newline after 1 is still in the input buffer when your program reaches get, so an empty line is read and then the scanfs will fail.
An easy fix could be to read the first number using this format:
scanf("%d ", &size);
// note ^ the space will consume the newline
But, as #chqrlie pointed out, "it will continue to read bytes from stdin until it sees one that is not whitespace. This will require the user to respond to the next question before the prompt is written."
A better idea is to read the name using another scanf, but limiting the maxium number of chars read to the allocated size and adding a space at the beginning of the format string to consume all pending whitespaces:
// read max 50 char till a newline and extract the rest of line without storing it
scanf(" %50[^\n]%*[^\n]", classStudent[i].name);
// ^^^ a space at the beginning will also consume trailing spaces or newline
It worked for me. All i did was using
_flushall();
instead of
flushall();