0

i have to program a function which asks for an array and its size, and then prints its values. The main function must call 2 other functions, both of them take two arguments (an array and its size). The first one asks for values to fill the array, the second one prints each value.

Im new to C and to programming in general, so any tips and useful info is very welcomed. I know very little about pointers aswell.

void requestarray(int a[], int  size){       
int i;
 for (i=0;i<size;i++)
 {
  printf("Insert value for %d position of the array\n",i);
  scanf("%d\n",&a[i]);
 }
}

void printarray(int a[], int size){     
int i;

 for (i=0;i<size;i++){
 printf("%d\n",a[i]);
 }
}

int main(void){
int size;

  printf("Insert array length\n");
  scanf("%d\n",&size);

int a[size];
requestarray(&a[size],size);
printf("\n");
printf("The array is\n");
printarray(&a[size],size);

return 0;
}

the program compiles but does not work. when i debug it using gdb, i place a breakpoint after

 int a[size];

then i print the value of a and it returns an array with size length and random values (mainly big numbers). Then i place a breakpoint after

requestarray(&a[size],size);

(which should modify the values of the array) but it returns the same values as printed in the previous breakpoint.

if i change the code in the main function like this

 requestarray(a[size],size);
printf("\n");
printf("The array is\n");
printarray(a[size],size);

the debugger gives me this warning

arreglo1.c: In function ‘main’:
arreglo1.c:33:14: warning: passing argument 1 of ‘requestarray’ makes pointer from integer without a cast [-Wint-conversion]
resquestarray(a[size],size);
              ^
arreglo1.c:8:6: note: expected ‘int *’ but argument is of type ‘int’
 void requestarray(int a[], int  size){
      ^~~~~~~~~~~~
arreglo1.c:36:16: warning: passing argument 1 of ‘imprimearreglo’ makes pointer from integer without a cast [-Wint-conversion]
 printarray(a[size],size);
            ^
arreglo1.c:17:6: note: expected ‘int *’ but argument is of type ‘int’
 void printarray(int a[], int size){
      ^~~~~~~~~~~~   
  • Just pass `a` as the parameter. BTW, the error message you quoted in the title doesn't come from that code. See [mcve]. – user3386109 Oct 26 '19 at 22:42
  • Your code is largely correct, the `'\n'` in `scanf ("%d\n", &a[i]);` is wrong, simply `scanf ("%d", &a[i]);` will do. (all *conversion specifiers* other than `"%c"` and `"[...]"` consume leading whitespace) Also `requestarray (a, size);` is all that is needed. And `void requestarray(int *a, int size)` would shown an understanding of the *array/pointer* conversion that takes place. – David C. Rankin Oct 26 '19 at 22:52
  • See [`scanf()` and trailing white space in a format string](https://stackoverflow.com/questions/15740024/) — it is the epitome of appalling UI/UX to make people predict what they'll need to enter next before they can finish entering what is currently expected. – Jonathan Leffler Oct 27 '19 at 00:55

1 Answers1

2

scanf ("%d\n", &a[i]); is simply wrong (notice having to press Enter or provide more input than expected?) scanf will not process escape characters in that manner. Instead a literal '\n' causes scanf to disregard all whitespace forcing you to enter a non-whitespace character before it returns.

Whatever character you type to cause scanf to return does not match anything in your format string resulting in that character being left unread in stdin and will be used as your next attempted input.

That is why..., you must validate EVERY input by checking the return of each input function used. For instance in main(), e.g.

    printf ("Insert array length: ");
    if (scanf ("%d", &size) != 1) {     /* validate EVERY input */
        fputs ("error: invalid integer input.\n", stderr);
        exit (EXIT_FAILURE);
    }

and again in requestarray(), e.g.

    for (i = 0; i < size; i++) {
        printf ("Insert value for %d position of the array: ", i + 1);
        if (scanf ("%d", &a[i]) != 1) {     /* validate EVERY input */
            fputs ("error: invalid integer input.\n", stderr);
            exit (EXIT_FAILURE);    /* handle error condition as desired */
        }
    }

Otherwise on a matching or input failure, scanf stops extracting characters from your input buffer (stdin here), the offending character is left in your input buffer just waiting to cause the same failure on your next call to scanf.

When you pass an array, you can simply use a pointer as the array is converted to a pointer on access, see: C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3). So you can write your function as simply:

void requestarray (int *a, int  size)
{       
    int i;

    putchar ('\n');         /* tidy up with newline before looping for input */

    for (i = 0; i < size; i++) {
        printf ("Insert value for %d position of the array: ", i + 1);
        if (scanf ("%d", &a[i]) != 1) {     /* validate EVERY input */
            fputs ("error: invalid integer input.\n", stderr);
            exit (EXIT_FAILURE);    /* handle error condition as desired */
        }
    }
}

(note there is nothing wrong with passing int a[]. Also note how the code is spaced a bit wider making it easier to read (especially for older eyes..))

Putting it altogether you could do:

#include <stdio.h>
#include <stdlib.h>     /* for EXIT_FAILURE define */

void requestarray (int *a, int  size)
{       
    int i;

    putchar ('\n');         /* tidy up with newline before looping for input */

    for (i = 0; i < size; i++) {
        printf ("Insert value for %d position of the array: ", i + 1);
        if (scanf ("%d", &a[i]) != 1) {     /* validate EVERY input */
            fputs ("error: invalid integer input.\n", stderr);
            exit (EXIT_FAILURE);    /* handle error condition as desired */
        }
    }
}

void printarray (int *a, int size)
{     
    int i;

    for (i = 0; i < size; i++){
        printf ("%d\n", a[i]);
    }
}

int main(void) {

    int size;

    printf ("Insert array length: ");
    if (scanf ("%d", &size) != 1) {     /* validate EVERY input */
        fputs ("error: invalid integer input.\n", stderr);
        exit (EXIT_FAILURE);
    }

    int a[size];            /* Variable Length Array of 'size' elements */

    requestarray (a, size);

    puts ("\nThe array is\n");  /* there is no convertion, puts will do */
    printarray (a ,size);

    return 0;
}

Example Use/Output

$ ./bin/inputarray
Insert array length: 5

Insert value for 1 position of the array: 1
Insert value for 2 position of the array: 2
Insert value for 3 position of the array: 3
Insert value for 4 position of the array: 4
Insert value for 5 position of the array: 5

The array is

1
2
3
4
5

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • `scanf` does not process escape characters because the _compiler_ processes them when scanning string literals. – 1201ProgramAlarm Oct 27 '19 at 00:34
  • it worked thank you! the \n in scanf was a recurring issue that i noticed when executing these and other programs that used it. I do not quite understand why the validation of each input is needed, though. – Agustin Osiecki Oct 27 '19 at 00:37
  • @AgustinOsiecki validation is needed because if your user accidentally slips and types an `'r'` while reading for `'5'` a *matching failure* occurs, `scanf` quits extracting characters from `stdin` leaving `'r'` unread in `stdin` and the next time you call `scanf` with `"%d"` to read your next `int`, `'r'` is still there causing that (and every subsequent attempt) to fail. If you try reading in a loop without validating every read, that "slip" sends you spinning off into an infinite loop - not good... `:)` – David C. Rankin Oct 27 '19 at 01:44
  • The initial paragraph is inaccurate. No, there will be no matching failure in this `scanf` because of that `\n`. A whitespace character in `scanf` format string is NOT a request to look for that character in the input. All whitespace characters are treated differently. Any whitespace character is a command to `scanf` to consume *all* whitespace until the first non-whitespace character is encountered. This is exactly what the above `scanf` will be doing. – AnT stands with Russia Oct 27 '19 at 02:15
  • No, it is not correct. `scanf` will never try to match the `\n`. Again, as I said above, whitespace characters in `scanf` format string have special meaning. That special meaning applies to space, `\n`, `\t` and several other characters (see the standard descriptions of `scanf` and `isspace`). – AnT stands with Russia Oct 27 '19 at 02:21