1

I need to read unknown amount of various numbers on user's input using scanf function. That simply means the number of various integers is determined by the user by sending as many numbers as he can. Note that I read directly the numbers (I have to), as stated in following code:

int main(void)
{
    int numbers[];
    int error = 0;

    int i = 0;
    while(scanf("%i", &numbers[i++]) == 1);

    for(int i = 0; i < sizeof(numbers) - 1; ++i) {
        if(numbers[i] < -10000 || numbers[i] > 10000)
        {
            printf("%i%s", numbers[i], ", ");
        }
        else
        {
            printf("%s", "\b\b\nError: Error: Vstup je mimo interval!\n");
            // Means "Input is out of range!".
            // We have to write exact output to terminal as stated in HW.
            i = sizeof(numbers);
            error = 1;
        }
    }

    ...
}

The int error is actually a boolean value, but I am lazy to implement boolean library, so I define it as integer :D

However, the problem is elsewhere. Compiler throws me an error:

main.c:7:9: error: array size missing in ‘numbers’
     int numbers[];
                ^

Looks like that C program need to know the allocable size of an array. I already looked into some codes others have shared there to find out basics I need to implement and while searching for the array size issue, I found this question:

C - Declaring an array with an undefined value

However, it does not solve the problem with unknown array size for direct input of unknown amount of numbers. I found nowhere exactly I need to solve. I tried to define maximum size of array to hold up to 999 numbers, but then compiler throws me this exception:

main.c:50:23: error: iteration 999u invokes undefined behavior [-Werror=aggressive-loop-optimizations]
             if(numbers[j] > 0)
                       ^
main.c:48:9: note: containing loop
         for(int j = 0; j < sizeof(numbers); ++j)
         ^

Same for every loop used for numbers statistics (total amount, maximum, minimum, odds, evens, positives, negatives, their percentage and average). That means the array is strictly size of 999 numbers with rest of numbers being zeros. I found out a malloc function, but do not understand its usage :(

13
  • 1
    Also, C99 provides the Boolean type _Bool in stdbool.h. Commented Oct 22, 2016 at 14:41
  • 1
    @JohnBode: Strictly, strictly, C99 provides the _Bool type even without the <stdbool.h> header; the header provides bool, true, false (and __bool_true_false_are_defined). But your main point is that C99 has support for a boolean type, and that's correct. Commented Oct 22, 2016 at 14:57
  • 1
    Note that sizeof() returns a size in bytes. If it worked on your array (if your array definition worked), then or(int j = 0; j < sizeof(numbers); ++j) would be trying to index sizeof(int) times too far into the array. It would have been better if you'd shown the second lot of code, but it appears that you defined int numbers[999]; which can only be indexed with values 0..998, but if sizeof(int) == 4 (most common size), then your loop would have tried indexing elements 999 .. 3995, none of which exist in the array. Hence the compiler warning. Commented Oct 22, 2016 at 18:29
  • 1
    There is no mechanism in C to read an indefinite number of integers in a single I/O operation. You have to either know the number in advance or iterate reading some appropriate smaller set of numbers at a time (e.g. one at a time). You could write a function to do the job. How else should the end of the input be detected than by EOF? There are a limited number of ways to tell when you need to exit the loop: EOF, non-numeric input, prior count — did I miss any? A sentinel value (such as -999999) is a variant on 'non-numeric input', I suppose — it is numeric but has a special meaning. Commented Oct 22, 2016 at 18:33
  • 1
    This is exactly what dynamic allocation is for, and in C, you use malloc() (or calloc()) to perform dynamic allocation. Can you explain what you don't understand about malloc()? Commented Oct 22, 2016 at 19:59

3 Answers 3

1

"I need to read unknown amount of various numbers on user's input using scanf function." is a poor design goal.

Any program that allows an externally interface to input any amount of input without bound is a hacker exploit.

Robust code limits user input to a generous, but sane input amount. Good code will code that upper bound as a constant or macro.

Using scanf() is not the best tool to read user input.
Recommend fgets() to read a line. (Not shown here.)

#include <stdio.h>
#include <ctype.h>

// find the next character without consuming it.
int peek_ch(void) {
  unsigned char ch;
  if (scanf("%c", &ch) == 1) {
    ungetc(ch, stdin);
    return ch;
  }
  return EOF;
}

#define INPUT_N 1000
void foo(void) {
  int input[INPUT_N];
  size_t n = 0;

  // Read 1 _line_ of input using `scanf("%d", ....)` to read one `int` at a time
  for (n = 0; n < INPUT_N; n++) {
    int ch;
    while (((ch = peek_ch()) != '\n') && isspace(ch))
      ;
    // %d consume leading white-space including \n, hence the above code to find it.
    if (scanf("%d", &input[n]) != 1) {
      break;
    }
  }

  // TBD: Add code to handle case when n == N

  for (size_t i = 0; i < n; i++) {
    printf("%zu: %d\n", i, input[i]);
  }
}
Sign up to request clarification or add additional context in comments.

Comments

0

Based on your description in the comments, you're going to have to allocate memory dynamically with malloc and extend it with realloc as necessary.

Here's a basic skeleton of an example:

#define INITIAL_SIZE 1024

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

int main( void )
{
  size_t arraySize = 0;
  size_t i = 0;

  // initially allocate numbers array
  int *numbers = malloc( sizeof *numbers * INITIAL_SIZE );
  if ( !numbers )
  {
    fprintf( stderr, "Error allocating memory...exiting\n" );
    exit( EXIT_FAILURE );
  }

  arraySize = INITIAL_SIZE;
  int input;
  while ( scanf( "%d", &input ) == 1 )
  { 
    if ( i == arraySize )
    {
      // double the size of the numbers array
      int *tmp = realloc( numbers, sizeof *numbers * (2 * arraySize) );
      if ( !tmp )
      {
        fprintf( stderr, "Could not extend array size...no more inputs allowed\n" );
        break;
      }
      numbers = tmp;
      arraySize *= 2;
    }
    numbers[i++] = input;
  }

  // process numbers
  ...
  // clean up after ourselves
  free( numbers );

Comments

0

Thank you all for your help, I really appreciate that. It helped me, though what I really needed wasn't that one solution, but slightly different. As stated in comment above, I needed to only meet homework input and output requirements. I contacted my proffessor and he suggested me to get rid of integer array and enclose initial numbers list output and all calculation progress inside the while loop. The final calculation for percentage and average sumation is then wrapped in if condition testing if an error did not occured completed with all final output. This, however, isn't going to be marked as a solving answer as it really helped me alot here. But I marked as answer by chux as it's very logical and any program should be protected against malware exploit by buffer overflow. Again thank you all for your help, I really appreciate that :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.