pointer-to pointer and aray of pointer

Jun 22, 2010 at 2:09am
a char pointer-to pointer: char **ptr1;
an array of char pointer: char*[];

In
int main(int argc,char **argv) = int main(int argc,char *argv[]) as it does the same thing that it takes an input string from the command line. However,
if you have a function, say:

void printStr(char **pointer)// you have to use char* ptr[] instead
{
cout<<pointer[0];
}

and the main:
int main()
{
printStr("hello_world");
}

it causes error.But this is how main takes the string via a pointer -to-pointer.

Hence, I always thought that an array of pointers is just one dimensional pointers. say:
1)char *q[10];
2)char test[] = "hello"
3)q[0] = test;

however, pointer-to -pointer:
char **ptr;
char *test = "hello";
ptr = &test;

Hence if they are different then why does the argv in main() works both ways?
Why does it not work for the printStr()?

Thanks in advance.
Jun 22, 2010 at 2:18am
Hence, I always thought that an array of pointers is just one dimensional pointers. say:
[snip]
however, pointer-to -pointer:


Your understanding is correct.

Hence if they are different then why does the argv in main() works both ways?


It doesn't. argv in main is a pointer to a series of pointers to chars. IE: it's a pointer ot multiple C strings.

It would sort of be like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void printStrs(int count, const char** pointer)
{
  for(int i = 0; i < count; ++i)
    cout << pointer[i];
}

int main()
{
  const char* a = "This is one string";
  const char* b = "This is another";

  const char* ptrs[2] = {a,b};

  printStrs( 2 , ptrs );  // we're not giving it a string, we're giving it a pointer to an array of strings
}



The printStr that only prints 1 string would be just const char* (single *, not double **):

1
2
3
4
5
6
7
8
9
void printStr(const char *pointer)
{
  cout<<pointer;
}

int main()
{
  printStr("hello_world");  // now this will work
}
Last edited on Jun 22, 2010 at 2:19am
Jun 22, 2010 at 4:31am
Hence if they are different then why does the argv in main() works both ways?
Because [] means something different when used to declare a function parameter. It's impossible to pass arrays to functions, so the way the language works, these three functions take parameters of the same type:
1
2
3
void f1(char *a);
void f2(char a[]);
void f3(char a[10]);
In the case of f3(), the compiler doesn't even use the 10 for extra information (for example, for compile time bounds checking).
Jun 23, 2010 at 9:29pm
However, if at the command line in the shell(for example)when you type the program.o hello_world
, the main function be it char **argv or char *argv[] will out put hello_world for argv[1]. Alas, in the case of the former, it should take an address of a pointer and not a constant string, so why is that possible.
Jun 23, 2010 at 10:17pm
I'm not sure I got what you're asking.

Do you mean why you get a string and not a memory address as output? For the same reason that when you do
1
2
const char *p="Hello, World!\n";
std::cout <<p;
you don't get a memory address. operator<<() has an overload that takes a const char * as a parameter and interprets is as pointing to a C string.

Or do you mean you can apply the offset operator ([]) to pointers?
1
2
const char *p="Hello, World!\n";
std::cout <<p[1];
In reality, you can only apply it to pointers. When you do something like
1
2
int a[10];
std::cout <<a[1];
What you're really doing is taking a pointer to a, adding 1 to it, and dereferencing that.
1
2
3
4
int a[10];
int *p=a;
std::cout <<p[1];
std::cout <<*(p+1);
It's important here to make the distinction between pointers and arrays. Pointers are integers that refer to memory locations. Arrays are one of the things that can occupy memory locations. Variables and objects also occupy memory locations. But a pointer can't make a distinction between the two; all it sees is the memory it points to. This means that, depending on how you interpret it, a pointer can point to both a single value or an array of values. This is why in C and C++ it's very important to keep the size of the arrays being pointed to. There's otherwise no way of telling how long the array a pointer points to is. It could be 2^20 elements long, or 1. The pointer won't tell you.
One more thing: In my previous example, a is declared as a stack arrays. Stack arrays are not the same as pointers:
1
2
3
4
int a[10];
int *p=a;
p++;
a++; //Error. You can't increment arrays. 
Jun 27, 2010 at 5:51am
I apologize and Let me be clearer:

output]int main(int agrc, char**argv)
{
cout<<argv[1]<<endl;
}


at cmd line: ./prog1 hello_world


outPut:

hello_world

but why is this so. it seems that char **argv = "hello_world" and it does not make sense as it should point to a pointer.
Jun 27, 2010 at 6:37am
it seems that char **argv = "hello_world" and it does not make sense as it should point to a pointer.


It doesn't make sense because that's not the case.

argv pointers to a series of char*s. Each char* points to the start of a new string.

argv[0] points to "./prog1"
argv[1] points to "hello_world"

it's similar to this:

1
2
3
4
5
6
7
8
9
// these are the pointers to the strings
char* a = "prog1";
char* b = "hello_world";

// the above pointers are put in an array
char* hidden_array[2] = {a,b};

// argv is a pointer that points to the first element in that array
char** argv = &hidden_array[0];


argv is a char** (a pointer to a pointer to a char)
argv[1] is a char* (a pointer to a char, in this case it points to the first character in the "hello_world" string)
argv[1][0] is a char (in this case, it would be == 'h')
Jun 27, 2010 at 7:24am
Great! I understand this part of it. If you say there is a hidden array of pointer, then this code is sound. However, then why does it work for char *argv[].

1
2
3
4
int main(int argc,char *argv[])
{
cout<<argv[1];
}


hello_word


if I follow the same logic, then its a error of trying to convert a double pointer to an array of pointers.

1
2
3
4
5
6
7
8
9
// these are the pointers to the strings
char* a = "prog1";
char* b = "hello_world";

// the above pointers are put in an array
char* hidden_array[2] = {a,b};

//based on the logic it will fail
char *argv[] = {&hidden_array[0],&hidden_array[1]};


so why then char *argv[] and char **argv be used inter-changeably in main.
Jun 27, 2010 at 8:32am
No, that's correct. Why would that fail?
Last edited on Jun 27, 2010 at 12:42pm
Jun 27, 2010 at 12:41pm
1
2
3
4
5
6
7
8
9
// these are the pointers to the strings
char* a = "prog1";
char* b = "hello_world";

// the above pointers are put in an array
char* hidden_array[2] = {a,b};

//based on the logic it will fail
char *argv[] = {&hidden_array[0],&hidden_array[1]};



error: cannot convert âconst char**â to âconst char*â in initialization


This is the error message. I believe an array of pointers would work this way

char *argv[] = {hidden_array[0],hidden_array[1]};
Jun 27, 2010 at 12:43pm
Never mind. A parsing bug.
Yeah, you're right.
Jun 27, 2010 at 1:02pm
so that brings me to the question of why char *argv[] works the same as char **argv.

1
2
3
4
5
6
7
8
9
// these are the pointers to the strings
char* a = "prog1";
char* b = "hello_world";

// the above pointers are put in an array
char* hidden_array[2] = {a,b};

//based on the logic it will fail
char *argv[] = {&hidden_array[0],&hidden_array[1]};


So if this was the process that takes place from the command line to the main(),then char *argv[] could not be used and only char **argv be used.

The concept of hidden array would only work with char **argv and not with char *argv[]. Hence, how is it possible to use them inter-changeably?
Last edited on Jun 27, 2010 at 1:06pm
Jun 27, 2010 at 1:41pm
Only when declaring function parameters is [] a synonym for *. Anywhere else, it declares a proper array, instead of adding a level of indirection.
1
2
3
4
void f(char *p[]){
    char **p2=p; //OK. No conversion performed.
    char *p3[]=p; //Invalid array initialization.
}
Jun 28, 2010 at 6:05am
I think i cracked it and after a lot of testing found out as follows.

char *ptr[] - acts differently when in a function argument and when it is used in a function during initialization.

for eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void f(const char *t[])
   {
 cout<<"in f()"<<endl;
 cout<<t[0]<<"   "<<t[1]<<endl;
  }
  
 
  
void g(const char *p)
  {
  
  cout<<"in g()"<<endl;
  cout<<p[0]<<"   "<<p[1]<<endl;
  }
  
 
  
void d(const char **l)
  {
  
  cout<<"in d()"<<endl;
  cout<<l[0]<<endl;
  }
  
 
  
  int main()
  {
  const char *ptr = "hello";
  const char *ptr1= "world";
  
  
  const char *t[]  = {ptr,ptr1};
  
  d(t);//calling multiple indirection pointer
  
  f(&t[0]);//calls the array of pointers. here you pass the address of the t array and not the the element in t[0] which is ptr. Meaning as a function it acts as a multiple indirection pointer. Taking the address of the pointer.

  g(t[0]);// this is a single pointer and hence you pass t[0] and it will take ptr which is the starting adress of the hello.
  
//now the twist.This however acts like a single pointer and takes t[0] just like how function g() does. Hence inside a function it acts as a single direction pointer.
const char *tt[2] = {t[0],t[1]};
 
 return 0;
}


//output of d()
hello    world


//output of f()
hello


//output of g()
 h    e


Hence, since main is another type of function, that is why *argv[] and **argv works the same.
However, if they were initialized within the function and not as arguments, then they are different with one being a pointer to a pointer(**argv) and the other an array of single pointers(*argv[]).
Jun 28, 2010 at 6:34am
//output of d()

hello world

//output of f()

hello

//output of g()

h e




You got your d() and f() outputs mixed up.
Jun 28, 2010 at 4:56pm
apologize.the output is as follows:

//output of f()

hello world

//output of d()

hello

//output of g()

h e
Topic archived. No new replies allowed.