Search code examples
cscanf

Reading a matrix using scanf


I want to receive a matrix from the user, like the example below

6 5
*###**
##***#
##*###
##*###
#**###

this is my code:

#include <stdio.h>

int main()
{
    int n, m;
    scanf("%d %d\n", &n, &m);
    char list[n][m];
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            scanf("%c", &list[i][j]);
            
        }
    }

    for(int i=0;i<n;i++)
    {
        for(int j =0;j<m;j++)
        {
            printf("%c",list[i][j]);
        }
    }
    return 0;
}

But instead of the input I gave it, it gives me an output like below

*###**
##***#
##*###
##*###
#*

I think the problem is that the spaces after each line are saved as a character. Can anyone help me?


Solution

  • There are several problems here.

    • While you think that your input might be a 6x5 matrix, C has no notion of such, it only knows about array dimensions and it's the programmer which has to define which dimension that corresponds to what. That is, you could either do char list[n][m]; or char list[m][n];.

      Since you are reading 6 characters per line and doing so from the inner loop corresponding to the right-most dimension of the array, you either have to give input 5 6 or change the array to [m][n].

    • scanf leaves new line \n characters in stdin whenever the user press enter. These have to be read or discarded. %d input ignores them since they aren't numbers, but %c reads then. This is a problem that every single person learning C struggles with, see scanf() leaves the newline character in the buffer.

      The reason why your output looks funny is because scanf("%c" in the loop keeps reading '\n' characters and storing them in the data. But there's no room to store them there. You end up 4 characters short because of 4 read \n getting stored in the data. And then the loops finish before all of the actual data has been read.

    As for how to fix it, the best solution is to forget that you ever heard about scanf and use fgets instead. Learning all the details of console I/O and stdio.h in general is not time well-spent.

    The easy and quick solution is to simply discard all line feed as you go and then later print line feeds separate from the data. You can discard a line feed either with scanf("\n"); or just by a single getchar(), either munches up the linefeed.


    Fixed program which works with 5 6 as input:

    #include <stdio.h>
    
    int main()
    {
        int n, m;
        scanf("%d%d\n", &n, &m);
        char list[n][m];
    
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                scanf("%c", &list[i][j]);
            }
            scanf("\n"); // discard line feed
        }
    
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                printf("%c",list[i][j]);
            }
            printf("\n"); // print line feed explicitly
        }
        return 0;
    }