简体   繁体   中英

How to use arbitrary number of scanf() format specifiers?

I want to use infinite type specifiers ( %d ) in scanf() function.

For example-

printf("Enter numbers: \t");
scanf("--%d SPECIFIERS--");

So its not definite how many nos. the user will enter. I don't want my program to ask the user the 'numbers of characters'.. but I want to allow any the numbers of characters. But its not possible to enter infinite %d in scanf() .

So can anyone please tell what is the C program of finding average of numbers given by the user (if you dont know how much nos. the user will give and you don't want the program to ask 'how many numbers.')?

This is tricky. 2 approaches

1 - fgets() Read 1 line, then parse

char buffer[1000];
int count = 0;
double sum = 0;
int num;
fgets(buffer, sizeof buffer, stdin);
const char *p = buffer;
int n;
while (sscanf(p, "%d%n", &num, &n) == 1) {
  p += n;
  ; // do something with `num`
  sum += num;
  count++;
}     
printf("Average %f\n", sum/count);

2 - Lets say you infinite input ends with the end-of-line. Now the problem is that %d will consume all leading whitespace, including \\n . Thus we need to consume and test all whitespace beforehand

int count = 0;
double sum = 0;
int num;
for (;;) {
  int ws = 0;
  while (isspace(ws = fgetc(stdin)) && (ws != '\n'));
  if (ws == '\n') break;
  ungetc(ws, stdin);
  if (scanf("%d", &num) != 1) break;
  ; // do something with num
  sum += num;
  count++;
}
printf("Average %f\n", sum/count);

If you really interested in infinite number of inputs the just try this

while(1)
{
    printf("Enter numbers: \t");
    scanf("%d", number);
}  

It will take input until you forcibly close your program!
But does it make any sense of doing this ?

If the user input is always numbers separeted by spaces and then at the end is an enter (newline). Then you can use the following code

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int input;
    char c;
    while (scanf(" %d%c", &input, &c) == 2 ) {
        printf("number is %d\n", input);
        if ( c == '\n') break;
    }
}

If the use want to communicate the number of input as argument

int main(int argc, char *argv[])
{
    int number_of_input = atoi(argv[1]);
    int input, i;
    for (i=0; i<number_of_input; i++) {
        scanf(" %d", &input);
    }
}

and when you call you program. you call it in this way:

$ myprogram 5

and 5 here is the number of the integer that you can input

  • myprogram will be saved in argv[0]
  • 5 will be saved in argv[1]

myprogram and 5 are saved as sting in the argv[] array. atoi(argv[1]) will convert the "5" as string to 5 as integer


you can make the user enter an infinite integer input in this way too:

int main(int argc, char *argv[])
{
    int input, i;
    while (1) {
        scanf(" %d", &input);
    }
}

And you can give the user a way to stop this infinite loop:

int main(int argc, char *argv[])
{
    int input;
    while (scanf(" %d", &input) != EOF) {
        //....
    }
}

here you can stop the infinite loop with

EOF = CTRL + D (for Linux)

EOF = CTRL + Z (for Windows)

At first reading, the solution to a problem like this is to loop until the user inputs a "done" character. This could be a letter Q for example. By reading in the input as a string you can process both numbers and letters. The code below processes one input at a time (followed by ) - with the possibility to either Quit (terminate program), or Clear (restart calculation, keep program running):

printf("Enter numbers to average. Type Q to quit, or C to clear calculation.\n");
char buf[256];
double sum=0, temp;
int ii = 0;
while(1)
{
    printf("Input: \t");
    fgets(buf, 255, stdin);
    if (tolower(buf[0])=='q') break;
    // allow user to "clear" input and start again:
    if (tolower(buf[0])=='c') {
      sum = 0;
      ii = 0;
      printf("Calculation cleared; ready for new input\n");
      continue;
    }
    ii++;
    sscanf(buf, "%lf", &temp);
    sum += temp;
    printf("At this point the average is %lf\n", sum / (double)ii);
}

printf("Done. The final average of the %d numbers is %lf\n", ii, sum / ii);

EDIT Following some back-and-forth in the comments to this and other answers, here is a solution that addresses your problem. Code has been tested - it compiles, runs, gives expected results:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void){
  double sum=0;
  int ii=0;
  char buf[256], *temp;
  char *token;

  printf("Enter the numbers to average on a single line, separated by space, then press <ENTER>\n");
  fgets(buf, 255, stdin);
  temp = buf;
  while((token=strtok(temp, " ")) != NULL) {
    temp = NULL; // after the first call to strtok, want to call it with first argument = NULL
    sum += atof(token);
    ii++;
    printf("Next token read is number %d: '%s'\n", ii, token); // so you see what is going on
                                                               // remove in final code!!
  }
  printf("AVERAGE: ***** %lf *****\n", sum / (double)ii);
  return 0;
}

One more edit If you want to use getline instead (which you asked about in the comments - and it's even safer than fgets since it will increase the buffer size as needed), you would change to change the code a little bit. I am just giving some of the pertinent lines - you can figure out the rest, I'm sure:

double sum=0;
char *buf, *temp;      // declaring buf as a pointer, not an array
int nBytes = 256;      // need size in a variable so we can pass pointer to getline()
buf = malloc(nBytes);  // "suggested" size of buffer

printf("Enter numbers to average on a single line, separated with spaces\n")

if (getline(&buf, &nBytes, stdin) > 0) {
 temp = buf;
 // rest of code as before
}
else {
 // error reading from input: warn user
}

I am sure you can figure it out from here...

You should have some way of knowing where the input ends. There are many ways for it and each has a possibly different solution. The two most common ones would be:

Input finishes at end-of-line

The solution is to read one line and then parse the line to get your numbers until the line ends.

This has the benefit that the program could ask for other input afterwards for other parts of the program. The disadvantage is that the user has to input all the numbers in the same line.

Input finishes at end-of-file

Simply loop, reading one number until end of file:

while (scanf("%d", &num) == 1)
    /* do something with num */

Note: the user can enter end-of-file in a Linux console with Ctrl + D

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM