6

If I use char *s[], I can do the following:

char *s[] = {"foo", "bar", "foobar", "whatever", "john", "doe"};

What is the difference with **s? How do I use the char **s instead of char *s[] in that case?

Example: int main (int argc, char **argv) instead of *argv[]

Alok Singhal
  • 93,253
  • 21
  • 125
  • 158
Marcelo Araujo
  • 145
  • 3
  • 13
  • Marcelo, don't forget to mark an answer as accepted if it solved the problem or ask for further clarification. – sidyll Jul 27 '11 at 19:08

9 Answers9

7

For function parameters, there is no difference.

Otherwise:

char *s[];

s is an array of pointer to char. And

char **s;

s is a pointer to pointer to char.

You use the former if you need an array of pointer to char, and you use the latter if you need a pointer to a pointer to a char.

sidyll
  • 57,726
  • 14
  • 108
  • 151
4

As function parameters, there is no difference whatsoever. They are equivalent.

void f(int** p);
void f(int* p[]);
void f(int* p[42]);

These three declarations are equivalent.

As objects, they have different types;

char *s[] = {"foo", "bar", "foobar", "whatever", "john, "doe"};

s is an array of 6 pointers to char sizeof(s) == 6*sizeof(void*)

char **s;

s is a pointer to pointer to char. sizeof(s) == sizeof(void*)

Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • +1 for a concise answer. Minor nit (it shouldn't make a difference): you should be using `sizeof(char *)` instead of `void *`. – tomlogic Jul 21 '11 at 20:28
  • 1
    @tomlogic: I am using `void*` to emphasize that all pointers have the same size and that one is a pointer and the other is an array of pointers (no matter what poiners). – Armen Tsirunyan Jul 21 '11 at 20:33
  • @Armen: not quite: http://stackoverflow.com/questions/1241205/are-all-data-pointers-of-the-same-size-in-one-platform. Still, `char *` and `void *` have the same size and representation. – Alok Singhal Jul 21 '11 at 21:30
1

They create the same data structure. The only difference s that char*s[] automatically mallocates enough memory for {"foo", "bar", "foobar", "whatever", "john, "doe"} upon initialization. char **s would only allocate one byte for the pointer then you'd to manually mallocate memory yourself for the each string in the array.

Paul
  • 139,544
  • 27
  • 275
  • 264
1

Arrays and pointers are different things. A pointer can be used to access an element in the array. To be able to initialize an array, you need to declare an array, not a pointer.

To show clearly the difference try this:

int[] ia = {1, 2, 3, 4, 5, 6, 7, 8};
int* ip = ia;

printf("sizeof(ia): %zu, sizeof(ip): %zu", sizeof(ia), sizeof(ip));

The first should print the size of the array, the second the size of an int pointer.

The odd thing with C is that when an array is passed as a parameter to a function it decays into a pointer. See more in section 2.3 of http://www.lysator.liu.se/c/c-faq/c-2.html. The reason main accepts argv** instead of argv*[] is that argv*[] is decayed into argv** when passed as a function parameter.

caf
  • 233,326
  • 40
  • 323
  • 462
Anders Abel
  • 67,989
  • 17
  • 150
  • 217
1

Not direct answer to your que but this might help you understand a bit more:

#include <stdio.h>
#include <string.h>

int main() {

    char *s[] = {"foo", "bar", "foobar", "whatever", "john", "doe"};

    printf("  s[0]: %s \n", s[0]);
    printf("    *s: %s \n", *s);
    printf("  *s+1: %s \n", *s+1);
    printf("*(s+1): %s \n", *(s+1));

return 0;
}

Output:

$ gcc -o chararr chararr.c 
$ ./chararr 
  s[0]: foo   
    *s: foo 
  *s+1: oo 
*(s+1): bar 
hari
  • 9,439
  • 27
  • 76
  • 110
0

From my knowledge, **s is the address of the address of s, where *s[] is the address of array s, I think you would store single values in s, yet in s[] you would store array, and array itself is a pointer. Hope this helps!

Grigor
  • 4,139
  • 10
  • 41
  • 79
  • Nah, for the double pointer you could store a single value, but its more likely a block of data or a block of pointers that point to blocks – alternative Jul 21 '11 at 20:17
  • I meant it points to the array, not that array is the pointer, my bad on that one. – Grigor Jul 21 '11 at 20:22
0

If you define

char **s[] = {"foo", "bar", "foobar", "whatever", "john, "doe"};

I think that it's the same like defining tridiensional arrays (char s[10][10][10]), since char *s[] is defining a bidimensional array.

Emil Condrea
  • 9,705
  • 7
  • 33
  • 52
0

when you use char *s[] = {"foo", "bar", "foobar", "whatever", "john, "doe"}; the compiler already knows the length of array ie: in this case it knows the its a pointer to pointers of 6 character arrays.

char** lacks the length information and thats specifically why main has 2 arguments {length, pointer to pointer to char} == {argc, arv}

Soumen
  • 1,006
  • 2
  • 12
  • 19
0

It depends upon your requirement. If your program doesn't have to modify these strings later you can use

char *s[] = {"foo", "bar", "foobar", "whatever", "john", "doe"};

These are compiled as string literals in read only section.

Assembly output:

        .file   "test.c"
        .section        .rodata
.LC0:
        .string "foo"
.LC1:
        .string "bar"
.LC2:
        .string "foobar"
.LC3:
        .string "whatever"
.LC4:
        .string "john"
.LC5:
        .string "doe"
        .text

If you try to modify these strings later in the program you would get a segmentation fault. In that case you have to use char **s

Santhosh
  • 891
  • 3
  • 12
  • 31