2

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,

7
  • 9
    You cannot do that. You have to pass the size separately. Commented Mar 11, 2016 at 10:34
  • 3
    You can't. Either the array length needs to be passed into the function or the array must have a terminating sentinal value (as you have rightly mentioned). Commented Mar 11, 2016 at 10:34
  • 1
    or have a ending token, like "FIN"/ "END"... Commented Mar 11, 2016 at 10:35
  • well, you can. After all, the list in your example is constant. Think of int numStrings = sizeof(list)/sizeof (list[0]); - This will give you the number of elements in the array. Commented Mar 11, 2016 at 10:42
  • 3
    @tofro: that is not correct, PrintStringArray does not receive a list with any such type information. Why not try it and see for yourself? Commented Mar 11, 2016 at 10:46

3 Answers 3

3

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;
}
Sign up to request clarification or add additional context in comments.

Comments

3

You can't: the language does not support this.

Programmers normally do one of two things:

  1. Pass the size explicitly whenever the array is passed.

  2. Use an element value that signifies the array end. A \0 as an array element could work for you in that case.

3 Comments

You very well can. See comment on question
@tofro: What makes you think that PrintStringArray receives a list from which sizeof information can be obtained in the way you cite? You are incorrect.
@Bathsheba: I put NULL as an ending, {"Green", "Yellow", "Black", "White", "Purple", "Saphire", NULL}. Meanwhile, modify the code as: while (*p != NULL) putchar((*p++)); Then I got the segmentation fault as usual.
0

To avoid segmentation fault,just change the function to have a second argument of type size_t to let you know exactly how many strings you want to deal with.check the following code :

#include <stdio.h>

void PrintStringArray(char **list , size_t size);

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

void PrintStringArray(char **list, size_t size) {
    size_t i;

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.