-1

I am trying to create a char pointer array,or another way to put it a string array; using this syntax:

#include <stdio.h>

int main() {
    char **a = {"ab", "ac"};
    printf("%c", *((*a)+sizeof(char)));
}

To my understanding, a is a pointer that points to a char*. When I dereference it, I must access to the char* which in this context is the pointer that points to the first char of the string literal "ab". Adding one byte to the pointer must yield the pointer, address that points to the second char to the string literal, and when dereferenced, it must yield the char: 'b'? So why does this chunk of code generate such error? Is it because the compiler doesn't allocate adequate amount of memory because I am m erely declaring a pointer instead of an array? The prior questions are just speculations and are optional for one to answer. Thanks in advance.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
explorer
  • 31
  • 1
  • 6
  • 4
    The first stop should be compiler warnings. – Weather Vane Jul 01 '22 at 14:03
  • 1
    `char **a = {"ab", "ac"};` doesn't do what you apparently think it does. And the compiler should have [warned you about it](https://godbolt.org/z/h3W6n5roh). – Some programmer dude Jul 01 '22 at 14:04
  • On another note, for any pointer or array `a` and index `i`, the expression `*(a + i)` is *exactly* equal to `a[i]`. The latter syntax (using "array" indexing) is much more clearer and simpler to read and understand. From this equivalence it's also possible to deduce that `*a*` is equal to `a[0]`. Also remember that `sizeof(char)` is specified to *always* be `1`. – Some programmer dude Jul 01 '22 at 14:05
  • 1
    and when used in pointer arithmetic `1` means "1 unit of the object's size". – Weather Vane Jul 01 '22 at 14:09
  • @Someprogrammerdude thanks for the suggestions, what does `char **a = {"ab", "ac"};` do exactly? – explorer Jul 01 '22 at 14:10
  • 1
    @explorer It is simply wrong. – Zakk Jul 01 '22 at 14:11
  • It's the same as `char **a = "ac";` Which is clearly wrong. Use an array: `const char *a[] = { "ab", "ac" };` – Some programmer dude Jul 01 '22 at 14:11
  • @explorer Also, don't ignore your compiler's warnings. – Zakk Jul 01 '22 at 14:11
  • @Zakk they are not comprehensible for one that is new to the language, therefore I dismiss them – explorer Jul 01 '22 at 14:16
  • Compiler warnings should really be treated as *errors*, and that you must fix. Never dismiss messages from the compiler. Especially for a beginner, the compiler will know more about the code than you do. – Some programmer dude Jul 01 '22 at 14:17
  • Also, as a beginner you should learn that code like the one you posted here should not be considered a good example of anything. It's a *bad* example, besides the errors it's very hard to decipher for a beginner. Whomever taught you to write code like that should not be considered a good teacher. – Some programmer dude Jul 01 '22 at 14:19
  • @Someprogrammerdude why is it such a bad example apart from the invalid "array declaration"? – explorer Jul 01 '22 at 14:25
  • Using pointer arithmetic instead of array indexing is unclear and hard to read and understand, especially for beginners. Same with using `sizeof(char)` here, which isn't really relevant in this case (and can give wrong ideas when using pointer arithmetic for other (non-character) arrays). What you seem to want is `a[0][1]`, which is easy to read and understand (and much less to write!). – Some programmer dude Jul 01 '22 at 14:31

2 Answers2

2

This declaration

char **a = {"ab", "ac"};

is incorrect. You may not initialize a scalar object with a braced list that contains more than one initializing expression.

Instead you could declare an array like

char * a[] = {"ab", "ac"};

And if you want to output the second character of the first string literal used as an initializer then you can write for example

printf( "%c", *( *a + 1 ) );

Or you could declare an intermediate pointer like

char * a[] = {"ab", "ac"};
char **p = a;

and then

printf( "%c", *( *p + 1 ) );

If you want to output the whole array using pointers then the corresponding program can look like

#include <stdio.h>

int main( void )
{
    char * a[] = {"ab", "ac"};

    for ( char **p = a; p != a + sizeof( a ) / sizeof( *a ); ++p )
    {
        for ( char *q = *p; *q; ++q )
        {
            printf( "%c", *q );
        }
        putchar( '\n' );
    }
}

The program output is

ab
ac
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

char** is not an array and cannot be used as one. Except for the scenario when it points at the first item in an array of char*.

char **a = {"ab", "ac"}; is not valid C, as the compiler told you with warnings. You might want to consider a different configuration so that you won't have to waste time on things like this, see What compiler options are recommended for beginners learning C?

You could however turn this incorrect line into a valid one by having the char** point at the first item of an array. This can be done with the aid of a compound literal:

char **a = (char*[]){"ab", "ac"};

Please note however that the string literals in this code are read-only, so correct code should actually be:

const char **a = (const char*[]){"ab", "ac"};

Though maybe just drop the pointer to pointer entirely since it fills no obvious purpose here and go with a plain array instead:

const char* a[] = {"ab", "ac"};
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Can you link the self-answered Q&A that you wrote about the difference between pointers and arrays? It is very useful. – Zakk Jul 01 '22 at 14:37
  • @Zakk In case you mean [Correctly allocating multi-dimensional arrays](https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays), then I'd rather not, since arrays of pointers to strings is one of the valid uses of pointer-to-pointers. Also there's no dynamic allocation in this case. – Lundin Jul 04 '22 at 05:59