Search code examples
cmultidimensional-arrayruntime-errorscanfc-strings

scanf() not writing to 2d char array


I am working through a textbook teaching myself C programming using the Code::Blocks v20.03 IDE.

I am really bamboozled by a small program that is to read in three small strings into a 2d char array and then just print them out to the screen. The code for the program is shown below.

#include <stdio.h>

int main(void)
{
   char *colors[3][10] = {'\0'};

   printf("\nEnter 3 colors seperated by spaces: ");
   scanf("%s %s %s", colors[0][0], colors[1][0], colors[2][0]);

   printf("\nYour entered: ");
   printf("%s %s %s\n", colors[0][0], colors[1][0], colors[2][0]);
   return 0;
}

This compiles with zero errors or warnings and when executed produces the following output.

You entered: (null) (null) (null)

Using the IDE's Watches window shows that nothing is written to the array. I understand that an array name is treated as a pointer to the first element in the array. I also understand the use of subscripts/indexes to access elements within the dimensions of the array (e.g. arrays of ints) and so the need to keep the array second dimension at zero in this char array.

Sadly, this has me completely foxxed and so I need help to fill in my gap in understanding.

Best regards,

Stuart


Solution

  • When using scanf with the %s specifier, you must provide a pointer to a memory address for scanf to write to. Therefore, you must first create a memory buffer which has sufficient space for storing the entire string. The simplest way of doing this would be to declare an array of type char.

    However, the line

    char *colors[3][10] = {'\0'};
    

    will not declare an array of type char. Instead, it will create a multidimensional array of pointers.

    If you want to create an array of type char, you can do this:

    char color[10];
    

    If you want to create an array of arrays of type char, you can do this:

    char colors[3][10];
    

    Now you can use the line

    scanf( "%s %s %s", colors[0], colors[1], colors[2] );
    

    which is equivalent to

    scanf( "%s %s %s", &colors[0][0], &colors[1][0], &colors[2][0] );
    

    due to array to pointer decay. In most situations, if you use the name of an array in an expression, it will decay to a pointer to the first element of the array.

    Note that using %s is dangerous, because if the user types more data than fits in the memory buffer (in this case more than 9 characters), then you will have a buffer overflow, which causes undefined behavior.

    Therefore, it would be safer to write it like this:

    scanf( "%9s %9s %9s", colors[0], colors[1], colors[2] );
    

    This limits the number of matched characters to 9 characters per string, so scanf will never write more than 10 characters (9 characters plus the terminating null character) into a memory buffer.