i have written this program (its not finished, there are more functions to be added) however, I want to know why my withinBudget function is sometimes producing correct results and other times producing inaccurate results. The withinBudget works out whether or not the customer has sufficient balance or not. if it returns true it prints purchase has been successful or prints insufficient balance.
#include <stdio.h>
int isItemExist(char itemPrefixes[], char itemPrefix);
void displayMenu(char itemPrefixes[], int itemPrices[], int n);
int withinBudget(int budget, char itemPurchased, char itemPrefixes[], int itemPrices[]);
int n;
int main() {
char itemPrefixes[5];
int itemPrices[5];
int budget = 0;
char itemPurchased;
printf("***ItemPrefixes***");
printf("\nA: Apple\n");
printf("O: Orange\n");
printf("M: Mango\n");
printf("P: Pear\n");
printf("G: Grapes\n");
printf("\n***ShopKeeperPanel***");
printf("\nHow many fruit items do you want to add to the shop?: ");
scanf_s("%d", &n);
int chosenFruitItem = 0;
while (chosenFruitItem < n) {
printf("\n(%d) Enter the item prefix: ", chosenFruitItem + 1);
char itemPrefix = ' ';
scanf_s(" %c", &itemPrefix, 1);
if (isItemExist(itemPrefixes, itemPrefix) == 1) {
printf("Error Item already exist");
continue;
}
else {
itemPrefixes[chosenFruitItem] = itemPrefix;
printf("Enter price for item (%c): ", itemPrefix);
scanf_s("%d", &itemPrices[chosenFruitItem]);
chosenFruitItem++;
}
}
displayMenu(itemPrefixes, itemPrices, n);
printf("\n**CUSTOMER PANEL***");
printf("\nWhat is your budget for today?: ");
scanf_s("%d", &budget);
printf("\nPlease enter Item Prefix from the menu to purchase: ");
scanf_s(" %c", &itemPurchased, 1);
if (withinBudget(budget, itemPurchased, itemPrefixes, itemPrices) == 1) {
printf("PURCHASS SUCCESS");
}
else
{
printf("INSUFFICENT BUDGET");
}
}
int isItemExist(char itemPrefixes[], char itemPrefix) {
for (int i = 0; i < n; i++) {
if (itemPrefixes[i] == itemPrefix) {
return 1;
}
}
return 0;
}
void displayMenu(char itemPrefixes[], int itemPrices[], int n) {
printf("\n*** ShopMenu ***");
printf("\nItem: \t Price: ");
for (int i = 0; i < n; i++) {
printf("\n%c:\t %d", itemPrefixes[i], itemPrices[i]);
}}
int withinBudget(int budget, char itemPurchased, char itemPrefixes[], int itemPrices[]) {
for (int i = 0; i < n; i++) {
if (itemPurchased == itemPrefixes[i] && itemPrices[i] < budget)
{
return 1;
}
return 0;
}
}
the output:
Please ident your code. Either simplest mistakes could go unnoticed because of this.
Here you have an auto one.
After doing this to your code, here's the last function:
int withinBudget(int budget, char itemPurchased, char itemPrefixes[], int itemPrices[]) {
for (int i = 0; i < n; i++) {
if (itemPurchased == itemPrefixes[i] && itemPrices[i] < budget) {
return 1;
}
return 0;
}
}
As you can see, return 0 is inside loop, it's working only if itemPurchased == itemPrefixes[0] && itemPrices[0] < budget as i will never be incremented.
So your function should be:
int withinBudget(int budget, char itemPurchased, char itemPrefixes[], int itemPrices[]) {
for (int i = 0; i < n; i++) {
if (itemPurchased == itemPrefixes[i] && itemPrices[i] < budget) {
return 1;
}
}
return 0;
}
Related
I'm doing the day 8 of the 30 days of code in HackerRank and I am having a problem with strcmp.
The code asks the user for names of people and their numbers, then asks for other names, if a name wasn't entered before, then it outputs Not found, but if it was then it outputs the name and his number. But for some reason, the output only works in the last loop of the for statement.
Code:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
typedef struct {
char name[100];
int number;
} phonebook;
int main() {
int n = 0;
do {
scanf("%i", &n);
} while (n < 1 || n > 100000);
int i = 0;
phonebook people[n];
for (i = 0; i < n; i++) {
scanf("%s %i", people[i].name, &people[i].number);
}
char othernames[n][100];
for (i = 0; i < n; i++) {
scanf("%s", othernames[i]);
}
for (i = 0; i < n; i++) {
if (strcmp(othernames[i], people[i].name) == 0) {
printf("%s=%i\n", people[i].name, people[i].number);
} else {
printf("Not found\n");
}
}
return 0;
}
You didn't find the othernames from the beginning to end to compare peopleevery time, so you need to replace
for (i = 0; i < n; i++) {
if (strcmp(othernames[i], people[i].name) == 0) {
printf("%s=%i\n", people[i].name, people[i].number);
}
else {
printf("Not found\n");
}
}
to
bool found = false;
for (i = 0; i < n; i++) {
for ( j = 0 ; j < n ; j++ ) {
if (strcmp(othernames[j], people[i].name) == 0) {
printf("%s=%i\n", people[i].name, people[i].number);
found = true;
}
}
}
if ( found == false ) printf("Not found\n");
The problem is othernames should just be an array of char, not a matrix. And for each othername entered, you must scan whole phonebook to find it or display Not found. As coded, you only test if the i-th othername typed happens to correspond to the i-th entry in the phone book.
Here is a modified version:
#include <stdio.h>
#include <string.h>
typedef struct {
char name[100];
int number;
} phonebook;
int main() {
int n = 0;
do {
if (scanf("%i", &n) != 1)
return 1;
} while (n < 1 || n > 100000);
phonebook people[n];
for (int i = 0; i < n; i++) {
if (scanf("%99s %i", people[i].name, &people[i].number) != 2)
return 1;
}
for (int i = 0; i < n; i++) {
char othername[100];
if (scanf("%99s", othername) != 1)
break;
int j;
for (j = 0; j < n; j++) {
if (strcmp(othername, people[j].name) == 0) {
printf("%s=%i\n", people[i].name, people[i].number);
break;
}
}
if (j == n) {
printf("Not found\n");
}
}
return 0;
}
Note that it is probably not a good idea to store phone numbers as int values. Better use a char array so an initial 0 is significant and to store longer numbers.
Input data works for me in the Init function. But once I put in some names and ask for the score of an existing name or a non-existent name, it always returns the grade of the first name
I create two arrays. One of names and one of grade.
Checks whether they meet all the terms of "proper name" as defined by us.
Takes another name and checks if it is in a database. If so, returns the score if it does not return -1
''''
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);
}
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 am having trouble doing my homework.
I am doing an RSA application which can encrypt and decrypt.
The problem is that after I Input things to encrypt the results are weird and I can't decrypt anything. This is because when I copied the results of encryption which are symbols, I got more weird stuffs.
I'm guessing it has something to do with my formula getting negative ASCIIs as results.
Below is what I tried, and, in order to understand what I meant by weird, just compile and try it out(I have some unused stuffs which I haven't removed yet):
Output:
Code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#define boolean int
#define true 1
#define false 0
//===================================================//
int p = 0;
int q = 0;
int n = 0;
int m = 0;
int divider = 2;
int tempdivider = 2;
int initial = 0;
int x = 0;
int y = 0;
char msg[100];
char alphabet[27];
//===================================================//
void cls();
void menu();
void init();
void reinit();
void inputencrypt();
//int encrypt(int num);
void encrypt();
char decrypt(char text[]);
int fpb(int num);
int d(int num);
int primecheck(int a);
boolean checkdigit(char text[]);
//===================================================//
int main() {
frontpage();
init();
menu();
getchar();
return 0;
}
//===================================================//
void cls() {
for (int i = 0;i < 25;i++) {
printf("\n");
}
}
//===================================================//
boolean checkdigit(char text[]) {
int len = strlen(text);
for (int i = 0;i < len;++i) {
if (text[i]<'0' || text[i]>'9') {
return false;
}
}
return true;
}
int primecheck(int a) {
if (a == 1) {
return false;
}
for (int i = 2;i < a;i++) {
if (a%i == 0) {
return false;
}
}
return true;
}
//===================================================//
void reinit() {
for (int i = 1;i < 27;i++) {
alphabet[i] = 'a' + i - 1;
}
p = 0;
q = 0;
n = 0;
m = 0;
divider = 2;
tempdivider = 2;
initial = 120;
x = 0;
y = 0;
}
void init() {
reinit();
do {
printf("p = ");
scanf("%d", &p);fflush(stdin);
if (!primecheck(p)) {
printf("must be prime number! \n");
}
} while (!primecheck(p));
do {
printf("q = ");
scanf("%d", &q);fflush(stdin);
if (!primecheck(q)) {
printf("must be prime number! \n");
}
} while (!primecheck(q));
n = p*q;
m = (p - 1)*(q - 1);
initial = m;
x = fpb(m);
y = d(m);
printf("n = %d\n", n);
printf("m = %d\n", m);
printf("e = %d\n", x);
printf("d = %d\n", y);
system("pause");
}
//===================================================//
void menu() {
char input[2];
int input1 = 0;
do {
do {
cls();
printf("main menu\n");
printf("================\n");
printf("1. encrypt\n");
printf("2. decrypt\n");
printf("3. exit\n");
printf(">> ");
scanf("%s", input);fflush(stdin);
if (checkdigit(input)) {
input1 = atoi(input);
}
} while (!checkdigit(input));
switch (input1) {
case 1:
int c;
char encrypted[100];
char word[100];
printf("input word to encrypt : ");
scanf(" %[^\n]", word);fflush(stdin);
for (int i = 0;i < strlen(word);i++) {
if (word[i] == ' ') {
encrypted[i] = ' ';
//i++;
}
else {
for (int j = 1;j < 27;j++) {
if (word[i] == alphabet[j]) {
c = 0;
c = pow(j, x);
c = c%n;
encrypted[i] = c;
break;
}
}
}
}
printf("\n\nWord ASCII [ ");
for (int i = 0;i < strlen(word);i++) {
//printf("%d", c);
printf("%d ", word[i]);
}
printf(" ]\n");
printf("\n\nEncrypted ASCII [ ");
for (int i = 0;i < strlen(word);i++) {
//printf("%d", c);
printf("%d ", encrypted[i]);
}
printf(" ]\n");
printf("\n\nEncrypted [ ");
for (int i = 0;i < strlen(word);i++) {
//printf("%d", c);
printf("%c", encrypted[i]);
}
printf(" ]");
printf("\n\n\n");
system("pause");
break;
case 2:
int temp[100];
char decrypted[100];
char wordx[100];
int h;
printf("input word to decrypt : ");
scanf(" %[^\n]", wordx);fflush(stdin);
for (int i = 0;i < strlen(wordx);i++) {
temp[i] = wordx[i];
//temp[i] -= 97;
//printf("%d ::: %c\n", temp[i], temp[i]);
}
for (int i = 0;i < strlen(wordx);i++) {
if (wordx[i] == ' ') {
decrypted[i] = ' ';
}
else {
h = 0;
h = pow(temp[i], y);
h = h%n;
decrypted[i] = h;
for (int j = 1;j < 27;j++) {
if (decrypted[i] == j) {
decrypted[i] = alphabet[j];
}
}
}
}
printf("\n\nWord ASCII [ ");
for (int i = 0;i < strlen(wordx);i++) {
//printf("%d", c);
printf("%d ", wordx[i]);
}
printf(" ]\n");
printf("\n\nDecrypted ASCII [ ");
for (int i = 0;i < strlen(wordx);i++) {
//printf("%d", c);
printf("%d ", decrypted[i]);
}
printf(" ]\n");
printf("\n\nDecrypted [ ");
for (int i = 0;i < strlen(wordx);i++) {
//printf("%d", decrypted[i]);
printf("%c", decrypted[i]);
}
printf(" ]");
printf("\n\n\n");
system("pause");
break;
}
} while (input1 != 3);
}
//===================================================//
int fpb(int num) {
if (!primecheck(num)) {
if (num%divider == 0) {
num = num / divider;
divider = 2;
}
else {
divider++;
}
fpb(num);
}
else if (primecheck(num)) {
if (!primecheck(num + divider)) {
tempdivider++;
divider = tempdivider;
num = initial;
fpb(num);
}
else {
return num + divider;
}
}
}
int d(int num) {
for (int i = 1;i < num;i++) {
if ((x*i) % num == 1) {
return i;
}
}
}
You have a general comprehension problem. Your console is only able to represent 96 characters correctly (known as printable 7bit-ASCII characters, 0x20 to 0x7F), but a byte can hold 255 different values. Your encryption algorithm does not care about this limited range, it will encrypt any value in the range [0..255] into another value in the range [0..255]. So your ASCII input characters will most likely be encrypted into values that cannot be represented by your console correctly. Copy&Past will not work correctly for non-printable characters (like 0x0B, which is a tab).
But now you will wonder: Why does that work for e.g. E-Mails? Simply: Because those characters are converted into an ASCII representation. Please google a bit for Base64 encoding.
As an alternative, you can always stream your encrypted characters into a file and later read back from that. This way you will bypass the limitations of your console.
Btw: Please have a look at the documentation of printf() and you will know, why you get those negative values.
The encrypt option has these three statements consecutively
c = 0;
c = pow(j, x);
c = c%n;
and the last of those will leave c in the range 0..(n-1).
Apart from that, there is no else clause and int c; can remain uninitialised.
So all in all it is inevitable that when you print c values as characters you will get "weird" results.
As for negative values, char encrypted[100]; is probably signed char so any integer value in the range 128..255 assigned to that, although undefined behaviour, may possibly show up as a negative number because the signed char is promoted back to int when passed as format %d to printf.
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.