1

Acc. to this post, the most used method to store text in a 2D array is by using %s approach. But, this approach has a downfall, i.e. whenever you press spacebar, the text which is typed after goes into the second element of array. for e.g. you typed

Input:-

1st element of char array = Hi everyone

Output:-

1st element of char array = Hi

2nd element of char array = everyone

Expected output:-

1st element of char array = Hi everyone

So, i want to ask why the below written approach cannot be used to enter text into a 2D array?

#include <stdio.h>
int main()
{
     char ch[20];
     printf("Enter name:");  
     scanf("%19[^\n]", ch);
     printf("Your name is: %s", ch);
     return 0;
}

If the above approach can be used, then please let me know how?

Please do not introduce pointer concepts/code in answer to this post. This is a question to understand why the above written approach fails.

Consider this as the code which fails:-

#include <stdio.h>

int main()
{
    char name[4][20];
    int i;
    printf("Enter names:-\n");
    for(i=0; i<4; i++)
    {
            printf("Enter name %d: ", i);
            scanf("%19[^\n]", name[i]);
            printf("\n");   
    }
    for(i=0; i<4; i++)
    {
        printf("Entered name %d: %s", i, name[i]);
        printf("\n");
    }
    return 0;
}

The above program compiles without any error or warning, but fails during runtime.

Blaze
  • 16,736
  • 2
  • 25
  • 44
code_smoke
  • 43
  • 5
  • 2
    For the input of e.g. `Hi everyone`, what should the result be? If you have your "2D" array, what should it look like, and after your input what should it contents be? – Some programmer dude Feb 13 '19 at 13:28
  • 1
    *"This is a question to understand why the above written approach fails."* It doesn't fail (at least not for me) and neither is it a 2D array. If it's not working as intended for you, a more detailed problem description is necessary. – Blaze Feb 13 '19 at 13:29
  • @Someprogrammerdude Check the post, updated it. – code_smoke Feb 13 '19 at 13:33
  • @Gahlot, if you want to convert "hi everyone" to 2 dimensional with "hi" and "everyone" in seperate string with 0ne scanf function then it is doable as: char ch[2][20]; scanf("%s %19[^\n]", ch[0], ch[1]); but doing so is not recommended as it can overflow the array as per the input. – Deepak Feb 13 '19 at 13:33
  • @Blaze I am asking when you use the above approach for 2D array it fails then why? – code_smoke Feb 13 '19 at 13:34
  • You still haven't shown the "2d" array itself, or the error messages you get. Please create a [mcve] to show us, and copy-paste the full and complete output from attempting to build that example. Also please take some time to read about [how to ask good questions](http://stackoverflow.com/help/how-to-ask), as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Feb 13 '19 at 13:36
  • @Someprogrammerdude Updated. – code_smoke Feb 13 '19 at 13:40
  • @Deepak please re-read the post and answer again. – code_smoke Feb 13 '19 at 13:41
  • @Gahlot: scanf("%19[^\n]", ch); will read the input till it encounter \n character or 19 character. So it is equivalent to %s with which input read will be a string which is a one dimensional character array, so scanf expect the same. so if you give a 2 dimensional array to this intelligent compiler should give warning/error. – Deepak Feb 13 '19 at 13:41
  • @Deepak No `"%19[^\n]"` is not the same as `"%19s"`. The `%s` format reads *space delimited* strings. You need the first format to read strings containing spaces. – Some programmer dude Feb 13 '19 at 13:43
  • First of all, please [learn how to debug your programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). Use a debugger to catch the crash and find out where in your code it happens. Secondly, `&name[i]` is a pointer to the *array* and not a pointer to the first character of the array. That would be `&name[i][0]` which is the same as `name[i]`. It happens to work because both are pointing to the same location, but they are semantically very different. – Some programmer dude Feb 13 '19 at 13:45
  • @Someprogrammerdude: yes, both are not exactly same, how they parse is not same but both expect a char * variable, Please correct me if my understanding is improper – Deepak Feb 13 '19 at 13:46
  • 3
    Furthermore, if you want to read *lines* why don't you use [`fgets`](https://en.cppreference.com/w/c/io/fgets) instead? As in `fgets(name[i], sizeof name[i], stdin);` – Some programmer dude Feb 13 '19 at 13:46
  • @Gahlot:you are passing a 2 dimensional array to scanf, you can read as scanf("%19[^\n]", name[i]); remove the & in that. – Deepak Feb 13 '19 at 13:47
  • @Deepak & is not the issue. with/without & your solution fails. – code_smoke Feb 13 '19 at 13:48
  • @Gahlot: got it. this is because you are having '\n' as delimiter, scanf will not remove the delimiter specified, so next scanf will encounter the same again and again. so only first input it prints as it get to first variable, all other will have NULL. this is the behavior of scanf(). if you use %s this will work fine. – Deepak Feb 13 '19 at 13:51

2 Answers2

1

The problem in the example you provided is that the newline is left in the buffer. You can discard this leading whitespace by changing this:

scanf("%19[^\n]", &name[i]);

To this

scanf(" %19[^\n]", &name[i]);

Note the space before %19. With this, your program prints:

Enter names:-

Enter name 0: foo

Enter name 1: bar

Enter name 2: baz

Enter name 3: qux

Entered name 0: foo

Entered name 1: bar

Entered name 2: baz

Entered name 3: qux

This is because the %[^\n] specifier tells it to take everything but the newline. So the newline will be left in the buffer, and when scanf is called again, it is the first thing in the buffer, so those additional calls can't take any input.

That leading space in the scanf fixes the problem, because it tells scanf to discard any trailing whitespace, which includes that newline left in the buffer.

This is what a reference says about it:

Whitespace character: the function will read and ignore any whitespace characters encountered before the next non-whitespace character (whitespace characters include spaces, newline and tab characters -- see isspace). A single whitespace in the format string validates any quantity of whitespace characters extracted from the stream (including none).

Blaze
  • 16,736
  • 2
  • 25
  • 44
  • Enter names:- Enter name 0: dss dsfsd Enter name 1: sdfs dsfsd Enter name 2: sfs sdfs dsfsd Enter name 3: dsfs sdfsdf fss f Entered name 0: dss dsfsd Entered name 1: sdfs dsfsd Entered name 2: sfs sdfs dsfsd Entered name 3: dsfs sdfsdf fss f okay this works. But why a leading whitespace is required specifically. – code_smoke Feb 13 '19 at 13:47
  • You should probably add a note that the `%[` format specifier does not skip leading white-space (like the newline left by previous call). – Some programmer dude Feb 13 '19 at 13:47
  • @blaze your solution works, but can you explain why a leading whitespace is required?? – code_smoke Feb 13 '19 at 13:51
  • @Gahlot I added an explanation on that – Blaze Feb 13 '19 at 13:55
  • 2
    @Blaze yup thanx. Learned a new thing today ! – code_smoke Feb 13 '19 at 13:58
0

Figured out another approach to get it done.

#include <stdio.h>

int main()
{
    char name[4][20];
    int i;
    printf("Enter names:-\n");
    for(i=0; i<4; i++)
    {
            printf("Enter name %d: ", i);
            scanf("%19[^\n]", name[i]);     
            fflush(stdin);
            printf("\n");   
    }
    for(i=0; i<4; i++)
    {
        printf("Entered name %d: %s", i, name[i]);
        printf("\n");
    }
    return 0;
}
code_smoke
  • 43
  • 5
  • `fflush` is undefined on input streams. https://pubs.opengroup.org/onlinepubs/009695399/functions/fflush.html and https://stackoverflow.com/questions/26446297/fflush-function-not-working-with-stdin. – Neil Sep 20 '19 at 16:49