Trouble with entering doubles into an array - c

I'm working on a c program that does not continue on when I enter a double when prompted. It skips and doesn't allow me to enter another number after the first run of the loop. Here is a sample of the code:
void total_max(double sale[], int n, double *total, double *max, int *max_id);
int main()
{
int n = 7; // length of an array
double sale[n];
int i;
for(i=0; i < n; i++)
{
printf("Enter the sales for salesperson %d\n", i+1);
scanf("%.2f", &sale[i]);
printf("\n");
}
Am I doing anything wrong?

fgets can be used to read a line of input, then parse the line with strtod.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n = 7; // length of an array
double sale[n];
char input[50] = "";
char *next = NULL;
int i;
for(i=0; i < n; i++)
{
do {
printf("Enter the sales for salesperson %d\n", i+1);
if ( fgets ( input, sizeof input, stdin)) {//read up to 49 characters or up to newline
sale[i] = strtod ( input, &next);
if ( next == input) {//could not parse a double
*next = '\0';
}
}
else {
fprintf ( stderr, "problem fgets\n");
return 0;
}
} while ( '\n' != *next);//repeat loop if next is not a newline
printf("\n");
}
for(i=0; i < n; i++) {//print the doubles with precision of 2
printf ( "%d %.2f\n", i + 1, sale[i]);
}
return 0;
}

It skips because you are using precision field in format string.
Check this answer: https://stackoverflow.com/a/29095617/9986735
A format specifier for scanf follows this prototype:
%[*][width][length]specifier
There is no precision field in scanf.
Just use: scanf("%lf", &sale[i]); instead.

Related

Taking string and integers in a single scanf skips the rest of integers after getting the string, why? How to do it only in single scanf?

I need to take integers and string from a single scanf. However, unless I do it with two scanfs the code doesn't take the remaining integers. How do I get this single scanf function to take everything that I input?
struct student {
int r;
char a[50];
int c1, c2, c3;
float total, per;
} s[100];
main() {
int i, n;
printf("Enter total number of students\n");
scanf("%d", &n);
for (i = 0; i < n; i++) {
printf("Enter details of student\nRollNo Name c1 c1 c3 marks\n");
scanf("%d %[^\n]*%s %d %d %d", &s[i].r, s[i].a, &s[i].c1, &s[i].c2, &s[i].c3);
// scanf("%d %d %d", &s[i].c1, &s[i].c2, &s[i].c3); this works
}
for (i = 0; i < n; i++) {
printf("%d %s %d %d %d\n", s[i].r, s[i].a, s[i].c1, s[i].c2, s[i].c3);
}
}
The format to read a string of characters different from newline is %[^\n], with an optional but highly recommended width prefix for the maximum number of characters to store into the destination array. The trailing *%s is meaningless.
Note however that this scanf conversion specifier will accept the mark numbers as part of the name:
scanf should stop reading the name when it finds a digit. This will allow the user to give the input on a single line per student, which he/she might do anyway given the prompt.
The format for that is %[^0-9\n] and to prevent undefined behavior if the user types more than 49 characters for the name, specify this limit with %49[^0-9\n].
Using scanf() to parse input is still brittle: recovering from invalid input is tedious.
Here is a corrected version:
#include <stdio.h>
struct student {
int r;
char a[50];
int c1, c2, c3;
float total, per;
} s[100];
int main() {
int i, n;
printf("Enter total number of students\n");
if (scanf("%d", &n) != 1 || n > 100)
return 1;
for (i = 0; i < n;) {
printf("Enter details of student\nRollNo Name c1 c1 c3 marks\n");
if (scanf("%d %49[^0-9\n] %d %d %d",
&s[i].r, s[i].a, &s[i].c1, &s[i].c2, &s[i].c3) == 5) {
i++;
} else {
int c;
fprintf(stderr, "input error\n");
/* consume the rest of the input line */
while ((c = getchar()) != EOF && c != '\n')
continue;
if (c == EOF) {
fprintf(stderr, "unexpected end of file\n");
return 1;
}
}
}
for (i = 0; i < n; i++) {
printf("%d %s %d %d %d\n", s[i].r, s[i].a, s[i].c1, s[i].c2, s[i].c3);
}
return 0;
}

Can I put a for loop inside scanf?

I want to have unknown amount of inputs in a single line. For example, user can input:
"ans: 1 2 3 4 5"
and scanf() will store these five numbers to an array. The problem is that the program don't know how many input will there be.
#include <stdio.h>
int main()
{
int i;
int input[4];
scanf("ans: " for(i = 0, i < 3,i++){scanf(" %d", &input[i]);};
return 0;
}
Sorry I'am totally new to coding, what will be the proper way to write this? Or is this impossible?
Thanks :)
Use fgets() and sscanf() with "%n"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char input[100];
int arr[10];
//fgets(input, sizeof input, stdin);
strcpy(input, "1 2 42 56 -3 0 2018\n"); // fgets
char *pi = input;
int tmp, pp, i = 0;
while (sscanf(pi, "%d%n", &tmp, &pp) == 1) {
if (i == 10) { fprintf(stderr, "array too small\n"); exit(EXIT_FAILURE); }
pi += pp;
arr[i++] = tmp;
}
printf("got this ==>");
for (int k = 0; k < i; k++) printf(" %d", arr[k]);
puts("");
}
You asked this question way round.
You can achieve what you expect by putting scanf inside of a loop.Even you can ask user to give how many inputs he want to enter.
#include <stdio.h>
int main()
{
int i;
int input[4];
printf("Enter the number of inputs you want to give : ");
scanf("%d", &n);
for(i = 0; i < n;i++)
{
printf("Enter the input number %d : ",i);
scanf("%d", &input[i]);
}
return 0;
}

geting input of string and character in a loop on c

Actually recently i found a problem where i need to count occurrence a given(by oj) char in a given string(with test case).So i write this code but output is not as i desired.I'm a beginner so i'll be greatly thankful for any kind of instructive advice or help.THANK YOU.
#include<stdio.h>
#include<string.h>
int main ()
{
int ara [123];
char s[1000];
int l, j, i, len;
char c;
scanf ("%d\n", &l);
while (l >= 0){
for (i = 65; i <= 122; i++)
{
ara[i] = 0;
}
fgets(s, 1000, stdin);
len = strlen(s);
for (i = 0;i <= len; i++)
{
ara[s[i]]++;
}
scanf(" %c\n", &c);
j = c;
printf("count : %d\n", ara[j]);
l--;
}
return 0;
}
The problem is that scanf is leaving a newline in the input to be read as the target sentence.
You can get around this by using fgets and sscanf instead. I also added some cues to make it easier to know what is expected.
#include <stdio.h>
#include <string.h>
int main (void)
{
int ara [128]; // increased array size
char s[1000];
char t[10];
int l, j, i, len;
char c;
printf("Enter how many loops:\n");
fgets(t, sizeof t, stdin); // replace scanf
sscanf (t, "%d\n", &l); // with sscanf
while (l > 0){ // changed end test
for (i = 'A'; i <= 'z'; i++) // replaced magic numbers
{
ara[i] = 0;
}
printf("Enter the string:\n");
fgets(s, sizeof s, stdin);
len = strlen(s);
for (i = 0;i <= len; i++)
{
ara[s[i]]++;
}
printf("Enter the letter:\n");
fgets(t, sizeof t, stdin); // replace scanf
sscanf (t, "%c\n", &c); // with sscanf
j = c;
printf("count : %d\n", ara[j]);
l--;
}
return 0;
}
Program session
Enter how many loops:
2
Enter the string:
one two three four
Enter the letter:
o
count : 3
Enter the string:
three seven
Enter the letter:
e
count : 4
Note that ideally, you should also check the function return values from fgets and sscanf.

get name and marks of students with structs

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

C : Array of strings - Can input only n-1 strings for an input size of n

I have to sort strings in a lexicographical order using the Bubble Sort technique without using any library functions. I have written the following code which is working fine in sorting the strings.
But the problem is that if I give n as the input (say n = 4), I can enter only n-1 strings (only 3 strings).
The problem can be solved by running the for loops from 0 to n, but that isn't a logical solution.
What am I doing wrong here?
#include <stdio.h>
#include <string.h>
#include <malloc.h>
void swap(int indx[], int j)
{
int temp;
temp = indx[j];
indx[j] = indx[j+1];
indx[j+1] = temp;
}
void sort(char **str, int indx[], int n)
{
int i, j, k;
for(i=0; i<n; i++)
{
for(j=0; j<n-i-1; j++)
{
k = 0;
while(str[j][k] != '\0')
{
if((str[indx[j]][k]) > (str[indx[j+1]][k]))
{
swap(indx, j);
break;
}
else if((str[indx[j]][k]) < (str[indx[j+1]][k]))
break;
else
k++;
}
}
}
}
void display(char **str, int indx[], int n)
{
int i;
printf("Sorted strings : ");
for(i=0; i<n; i++)
printf("%s\n", str[indx[i]]);
}
int main(void)
{
char **str;
int n, i, j, *indx;
printf("Enter no. of strings : ");
scanf("%d", &n);
str = (char **) malloc (n * (sizeof(char *)));
indx = (int *) malloc (n * sizeof(int));
for(i=0; i<n; i++)
str[i] = (char *)malloc(10 * sizeof(char));
printf("Enter the strings : ");
for(i=0; i<n; i++)
{
gets(str[i]);
indx[i] = i;
}
sort(str, indx, n);
display(str, indx, n);
}
The problem is your use of scanf(). When you do scanf("%d", &n), the scanf() function reads input until it finds an integer, and puts the value into n. However, when you entered that integer, you didn't just type '4', you typed '4' and pressed Enter. And the newline is still in the input buffer. The gets() function, on the other hand, reads input up to and including the first newline, and the newline character is discarded. So when you're reading the input strings, the gets call to gets() reads the newline, and returns immediately. And then, the first string that you enter is read by the second call to gets()...
Incidentally, The gets() function should never, ever, under any circumstances, ever be used for real programs, because it doesn't allow you to limit input. Better would be to use fgets(). fgets(str[i], BUFFERSIZE-1, stdin).
int main(void)
{
char **str;
int n=4, i, j, *indx;
printf("Enter no. of strings : ");
//scanf("%d", &n);
str = (char **) malloc (n * (sizeof(char *)));
indx = (int *) malloc (n * sizeof(int));
for(i=0; i<n; i++)
str[i] = (char *)malloc(10 * sizeof(char));
printf("Enter the strings : ");
for(i=0; i<n; i++)
{
gets(str[i]);
indx[i] = i;
}
sort(str, indx, n);
display(str, indx, n);
}
//if i comment out scanf and give int the value it works fine //
so the problem is use of fgets just after scanf as scanf leave a newline character in the buffer// so consume it before using fgets
Try this at the line where you have to input the string. Instead of:
gets(str[i]);
type:
scanf("%s",str[i]);

Resources