Home > front end >  Reading a matrix using scanf
Reading a matrix using scanf

Time:12-07

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?

CodePudding user response:

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;
}

CodePudding user response:

To fix this issue, you can add a space after the format specifier %c in the call to scanf to consume any whitespace characters (including newlines) after each character:

scanf("%c ", &list[i][j]);

This will cause scanf to read and discard any whitespace characters after each character that is read, so the newlines in the input will not be saved in the list array.

Alternatively, you can use fgets to read the entire line of input into a string, and then use sscanf to parse the individual characters from the string. This will also allow you to handle lines of varying lengths, which your current code does not support:

char line[m   1];
for (int i = 0; i < n; i  )
{
    fgets(line, m   1, stdin);
    sscanf(line, "%s", list[i]);
}

This code will read each line of input using fgets, and then use sscanf to parse the characters from the line and save them in the list array. The m 1 argument passed to fgets ensures that the line is read into a string that is large enough to hold all of the characters, including the null terminator.

  • Related