4

Can anyone tell me why this code does not work? When i run, it just prints out "Enter info about trail 1" and without any input, skips to another step.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 15

void readingArrays(int numberOfTrails,char arr[MAX][20]);

char array[MAX][20];

int main(void)
{
    int numberOfTrails;
    printf("Enter the number of trails\n");
    scanf("%d",&numberOfTrails);

    readingArrays(numberOfTrails,array);

    return 0;
}

void readingArrays(int numberOfTrails,char arr[numberOfTrails][20])
{
    for(int i=0;i<numberOfTrails;i++)
    {
        printf("Enter info about trails %d\n",i+1);
        fgets(arr[i],4,stdin);
        //getchar();
        //strtok(arr[i], "\n");
        printf("%s\n",arr[i]);
    }
}
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Levan
  • 125
  • 2
  • 9
  • 4
    It it happens for the first run of the loop, it is caused by a newline character left in the input stream from a previous line. Please post a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) so we can see the surrounding code also. – R Sahu Nov 20 '15 at 22:18
  • Is "stdin" declared and open? – Ohmless Nov 20 '15 at 22:21
  • if i use getchar() , it prints "Enter info..." normally, but printing input starts only after 2nd step and it removes first char of input. So whatever i write it prints out only in another step. – Levan Nov 20 '15 at 22:25
  • http://stackoverflow.com/questions/2907062/fgets-instructions-gets-skipped-why – nnn Nov 20 '15 at 22:33
  • You want to read a line but only read a number. – David Schwartz Nov 20 '15 at 22:42
  • 1
    Uila, stdin is declared in stdio.h, alongside stderr and stdout. – Ray Nov 20 '15 at 23:01

3 Answers3

2

Issue

The scanf function in main reads the integer, but leaves the newline \n on the input stream. When the first loop iteration of readingArrays comes around, fgets sees this newline and assumes you have already entered your trail info and pressed enter. It prints the empty string and newline, and goes on to the next iteration.

Solution

One solution would be to tell scanf to read and ignore whitespace after the digit by adding a space after %d format specifier.

So to get numberOfTrails from stdin, you would do

scanf("%d ",&numberOfTrails);

Thanks to @Ray for pointing out this solution!

AlexPogue
  • 757
  • 7
  • 14
  • 2
    or `scanf("%d%*c",&numberOfTrails);` – David C. Rankin Nov 20 '15 at 22:42
  • You're right, I had forgotten about `*` specifiers in scanf. Thanks – AlexPogue Nov 20 '15 at 22:48
  • Happy to help! If this answer or any other one solved your issue, please mark it as accepted. – AlexPogue Nov 20 '15 at 22:57
  • If you're using scanf, you don't need to worry about consuming the whitespace manually. `Input white-space characters (as specified by the isspace function) are skipped, unless the specification includes a [, c, or n specifier.` (C99 7.19.6.2/8) Additionally, whitespace in the scanf format specifier itself means "read and discard whitespace until the next non-whitespace character". So if you have an fscanf followed by an fgets, fscanf(stdin, "%d ", &n); fgets(buf, BUFSIZ, stdin); will result in the fscanf consuming the trailing whitesspace (including the newline) before the fgets is called. – Ray Nov 20 '15 at 23:06
  • @Ray: Have you tested the theory that fscanf consumes the trailing newline? Please try the code in the last part of the question and explain why it behaves as it does. – AlexPogue Nov 21 '15 at 14:01
  • scanf consumes the newline if there's a space after the `%d` in the format specifier. Your code has `scanf("%d")`. It needs to be `scanf("%d ")`. – Ray Nov 22 '15 at 18:28
  • Note that the 7.19.6.2/8 quote refers to whitespace *before* the thing being read by %d. So `scanf("%d%d", &a, &b)` would work even if the numbers were on separate lines. But since the second read isn't done by scanf in your case, you need the space after the `%d` to force it to keep reading after it reads the number and discard the trailing space. – Ray Nov 22 '15 at 18:39
  • @Ray: Nice, that is probably a better solution. My solution assumes the newline immediately follows the number in the scanf'ed string, and chokes if there are other characters or whitespace between the number and newline. Personally, I would rather read the whole line using `fgets`, then parse the integers from there using `strtol` - better error handling that way. – AlexPogue Nov 22 '15 at 19:39
  • Could you edit the answer to remove the part claiming it doesn't work? (Or better still, edit the example to use scanf("%d ") such that it does work.) – Ray Nov 23 '15 at 22:31
2

The perl language gives you chomp, which removes the newline from lines read from input. I find it a useful function to have lying around,

char*
chomp(char* p)
{
    if(!p) return p;
    size_t len=strlen(p);
    //if(len<=0) return(p);
    if(len>0) len--;
    if(p[len]=='\n') p[len--]='\0';
    if(len>=0) if(p[len]=='\r') p[len--]='\0';
    return(p);
}

So, declare a variable to use to read a line, and then just use gets to parse the line. Loads clearer. And notice that your array is an array of MAX arrays of char[20], and you may well enter a far larger line. It can be effective to read the entire line entered, and then extract the part you want,

char array[MAX][20];
int ndx;
char line[100];
for( ndx=0; fgets(line,sizeof(line)-1),stdin); ++ndx ) {
    chomp(line);
    strncpy(array[ndx],line,sizeof(array[ndx])-1);
    //combine both into one line:
    //strncpy(array[ndx],chomp(line),sizeof(array[ndx])-1);
    /*NULL termination of array[ndx] left as exercise for reader*/
}
ChuckCottrill
  • 4,360
  • 2
  • 24
  • 42
0

1) Add this line after scanf() : getchar()

2) Change fgets (...) 4 to 19.

The program will work.

Jay Kumar R
  • 537
  • 2
  • 7