1

There is some code piece right here below:

main ()
  {
    char in[8];
    char out[255];
    iconv_t cd;
    cd = iconv_open("gb18030", "utf-8");     
        ...
    char *p_in = in;
    char *p_out = out;
    size_t inlen = strlen(in);
    size_t outlen = sizeof(out);
    if (iconv(cd, &p_in, &inlen, &p_out, &outlen) < 0)
    {
          ...
        return -1
    }
          ...
        return 0;
  }

I can't totally understand the 2nd and 3rd parameters of the call to iconv. Why should that be ** pointer not the * pointer as the input? Can anyone explain the cases in C when the ** pointer should be used?

Jonathan Leffler
  • 666,971
  • 126
  • 813
  • 1,185
W.Costanza
  • 59
  • 6
  • 2
    Note that 21st Century C requires a return type for `main()` — only the archaic C89 standard did not require an explicit return type. (There were good reasons for that decision in C89; there were good reasons for changing it ten years later in C99.) – Jonathan Leffler Aug 19 '17 at 03:35
  • @Jonathan Lefflerwhy is that two reasons? would u say something about that concisely or give some reference of it if u know the details. – W.Costanza Aug 19 '17 at 03:41
  • @W.Costanza start from this: https://stackoverflow.com/questions/204476/what-should-main-return-in-c-and-c – Antti Haapala Aug 19 '17 at 06:19

1 Answers1

4

Pointer to pointer is used where the passed pointer is need to be modified in the called function and that modification need to be seen in the caller function. This is required because in C arguments are passed by value. So, when an argument is passed to a function then it simply copied to the function's parameter and created a local copy having block scope. Any change to that variable will not be seen in the argument that has been passed.

void foo(in x){
    x = 10;
}

int main(void){
     int x = 5;
     foo(x)
     printf("%d\n", x);  // x will be 5
}

Same happens with pointers

void bar(char *p){
    p = "foobar";
}

int main(void){
     char *p = NULL;
     bar(p);
     if(p)
         printf("p is pointing to %s\n", p);
     else 
         printf("p is NULL\n");   // This will 
}

Using a pointer to pointer will do the desired job (pointing p to the string "foobar"

void bar(char **p){ *p = "foobar"; }

int main(void){
     char *p = NULL;
     bar(&p);
     if(p)
         printf("p is pointing to %s\n", p);
     else 
         printf("p is NULL\n");   // This will 
}  

Another use is when an array of string is need to passed to a function. Like

int main(int argc, char **argv)  

or

void print_fruits(char **fruits, size_t len){
    for(int i = 0; i < len; i++)
        printf("%s\n", fruits[i]);
}

int main(void){
    char *fruits[5] = {"Apple", "Banana", "Cherry", "Kiwi", "Orange"};
    print_fruits(fruits, sizeof(fruits)/sizeof(fruits[0]));
}

Note that in function call print_fruits, fruits in the argument list will decay to pointer to its first element and the expression fruits will become of type char ** after the conversion.

haccks
  • 97,141
  • 23
  • 153
  • 244