Search code examples
arrayscpointersc-stringsfunction-definition

How to Print out an unknown size of string array in C?


I would like to print out an array of string with unknown size, for example {"Green", "Yellow", "Black", "White", "Purple", "Saphire", .....} and probably without NULL ending. My code is as below:((char **) has to be the argument of PrintStringArray)

void PrintStringArray(char **list) {
    int i = 0;

    for (;; i++) {
        char *p = list[i];
        while (*p)
                putchar((*p++));
        putchar('\n');
    }
}

void main()
{
    char *list[] = {"Green", "Yellow", "Black", "White", "Purple", "Saphire"};
    PrintStringArray(list);
    return;
}

But the result is,
Green
Yellow
Black
White
Purple
Saphire
Segmentation fault (core dumped)
How could I avoid segmentation fault? May I have your comments? Thank you,


Solution

  • Pointers do not keep information whether they point to single objects or for example first elements of arrays.

    Consider the following code snippet

    char *p;
    
    char c = 'A';
    
    p = &c;
    
    putchar( *p );
    
    char s[] = "ABC";
    
    p = s;
    
    putchar( *p );
    

    Thus you have to provide yourself the information about whether a pointer points to an element of an array.

    You can do this in two ways. The first one is to specify the number of elements in the sequence the first element of which is pointed to by the pointer. Or the sequence must to have a sentinel value as strings have.

    For example

    int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    
    for ( int *p = a; p < a + sizeof( a ) / sizeof( *a ); ++p )
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
    {
        printf( "%d ", *p );
    }
    printf( "\n" );
    

    Or

    int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    
    int *p = a;
    
    do
    {
        printf( "%d ", *p );
    } while ( *p++ != 0 );
              ^^^^^^^^^
    
    printf( "\n" );
    

    These code snippets can be written as functions

    void f( int a[], size_t n ) 
    {
        for ( int *p = a; p < a + n; ++p )
        {
            printf( "%d ", *p );
        }
        printf( "\n" );
    }
    

    Or

    void f( int a[] )
    {
        int *p = a;
    
        do
        {
            printf( "%d ", *p );
        } while ( *p++ != 0 );
    
        printf( "\n" );
    }
    

    The same way an array of strings can be printed. Either you will report explicitly the number of elements in the array yourself. Or you can use a sentinel value as for example a null pointer or an empty string.

    For example

    #include <stdio.h>
    
    void PrintStringArray( char *s[], size_t n ) 
    {
        for ( char **p = s; p < s + n; ++p )
        {
            puts( *p );
        }
        printf( "\n" );
    }
    
    int main( void )
    ^^^^^^^^^^^^^^^^
    {
        char *list[] =
        { 
            "Green", "Yellow", "Black", "White", "Purple", "Saphire" 
        };
    
        PrintStringArray( list, sizeof( list ) / sizeof( *list ) );
    
        return 0;
    }
    

    Or

    #include <stdio.h>
    
    void PrintStringArray( char *s[] ) 
    {
        char **p = s;
    
        while ( *p != NULL )
        {
            puts( *p++ );
        }     
    
        printf( "\n" );
    }
    
    int main( void )
    ^^^^^^^^^^^^^^^^
    {
        char *list[] =
        { 
            "Green", "Yellow", "Black", "White", "Purple", "Saphire", NULL
                                                                      ^^^^  
        };
    
        PrintStringArray( list );
    
        return 0;
    }