array of pointers

J

Jess

Hi,

If I have an array of pointer like:

char* a[] = {"a","b","c"};

then it works fine. Since "a" is effectively "a" char**, I tried the
following, which doesn't work:

char** a = {"a","b","c"};

What's wrong here?

I also tried the following program:

#include<iostream>
#include<string>
using namespace std;


void f1(char* a[]){
cout << "in f1" << endl;
for (size_t i = 0; i < 3; i++)
cout << *(a) << endl;
}

void f2(char** a){
cout << "in f2" << endl;
for (size_t i = 0; i < 3; i++)
cout << *(a) << endl;
}

int main(){
char* a[] = {"a","b","c"};
for (size_t i = 0; i < 3; i++)
cout << *(a) << endl;

f1(a);
f2(a);
return 0;
}

Then it works fine. So, when I pass an array to an function, I can
treat it as char**, but not when I define it?

Thanks,
Jess
 
?

=?iso-8859-1?q?Erik_Wikstr=F6m?=

Hi,

If I have an array of pointer like:

char* a[] = {"a","b","c"};

then it works fine. Since "a" is effectively "a" char**

No, "a" is a char*, not a char**, but perhaps that was a typo?
I tried the following, which doesn't work:

char** a = {"a","b","c"};

You make the mistake of thinking that T[] and T* are the same thing
(where T is a type), they are not, the first is an array and the
second is a pointer. What makes it easy to think so is that an array
can be converted into a pointer, however as you noticed the reverse is
not true. One of the big differences between an array and a pointer is
that an array has a number of elements, consider the following code:

template<class T, size_t N>
void printSize(const T (&arr)[N])
{
std::cout << N;
}

int main()
{
int arr[] = {1, 2, 3};
printSize(arr);
return 0;
}

So when converting the array to a pointer we lose some information
which makes it impossible to convert the pointer back to an array.
 
V

Victor Bazarov

Jess said:
Hi,

If I have an array of pointer like:

char* a[] = {"a","b","c"};

then it works fine.

No, it doesn't. Were you the one who asked about the segfault
if you try changing the content of the memory pointed to by any
of 'a' elements? If you were, you know the answers. If you were
not, then look it up.
Since "a" is effectively "a" char**

No, it isn't. The construct '"a"' in C++ has the type

const char[2]

At best it's "char const*".
, I tried the
following, which doesn't work:

char** a = {"a","b","c"};

What's wrong here?

Everything. You cannot initialise a _pointer_ with a brace-enclosed
initialiser list, that's first.
I also tried the following program:

#include<iostream>
#include<string>
using namespace std;


void f1(char* a[]){
cout << "in f1" << endl;
for (size_t i = 0; i < 3; i++)
cout << *(a) << endl;
}

void f2(char** a){
cout << "in f2" << endl;
for (size_t i = 0; i < 3; i++)
cout << *(a) << endl;
}

int main(){
char* a[] = {"a","b","c"};
for (size_t i = 0; i < 3; i++)
cout << *(a) << endl;

f1(a);
f2(a);
return 0;
}

Then it works fine. So, when I pass an array to an function, I can
treat it as char**, but not when I define it?


An array of blahs decays to a pointer to blah, and you already know
that, don't you? So, if 'a' is an array of pointers to char, you
can expect it to decay to a pointer to a pointer to char.

The same thing as if you have

char *a[5];
char **aa = a; // allowed -- array decays

V
 
J

James Kanze

If I have an array of pointer like:
char* a[] = {"a","b","c"};
then it works fine. Since "a" is effectively "a" char**,

No. "a" is a char const[2]. It converts to a char const* in
certain contexts, and in a very few, limited contexts (an
uniquely to avoid breaking legacy code) to a char*.
I tried the
following, which doesn't work:
char** a = {"a","b","c"};
What's wrong here?

You try to initialize a scalar variable with aggregate
initialization. Your initializer would be appropriate for an
array of char const*, but not for anything else.
I also tried the following program:
#include<iostream>
#include<string>
using namespace std;
void f1(char* a[]){

Attention. The above line does NOT do what you think. It
declares a parameter with type char**, not with type char* a[].
There is no such thing as a parameter with array type in C++.
cout << "in f1" << endl;
for (size_t i = 0; i < 3; i++)
cout << *(a) << endl;
}

void f2(char** a){

This is exactly the equivalent of the preceding.
cout << "in f2" << endl;
for (size_t i = 0; i < 3; i++)
cout << *(a) << endl;

}

int main(){
char* a[] = {"a","b","c"};
for (size_t i = 0; i < 3; i++)
cout << *(a) << endl;

f1(a);
f2(a);

When calling the function, there is an implicit conversion of
the array type to a pointer. It works in exactly the same way
you can call an 'f(char)' with a double.
return 0;
}
Then it works fine. So, when I pass an array to an function, I can
treat it as char**, but not when I define it?

You can't pass an array to a function, at least not by value, so
the question doesn't come up. You can pass it by reference,
e.g.:

void f(
char* (&array)[ 3 ] )
{
// Here, array has the type reference to array, not
// pointer...
}

f( a ) ;

In practice, I'm not sure how useful this is, because whether
the dimension is known is part of the type, so an int&[] doesn't
match an int [3]. (It's useful for templates, however.)
 
D

Daniel Oberhoff

Jess said:
Hi,

If I have an array of pointer like:

char* a[] = {"a","b","c"};

then it works fine. Since "a" is effectively "a" char**, I tried the
following, which doesn't work:

char** a = {"a","b","c"};

What's wrong here?

The first is proper semantics: you tell c++ that you want an array and
it provides you with an array initializer. In the second case you want a
pointer, not an array explicitly, so the array initializer doesn't
work. Behind the scenes it happens so that a actually is just a pointer
to the first element, but this is implementation details :) (but you are
allowed to depend on this, i think, think of it as grammatically wrong,
even though it is clear what you mean, and compilers are very strict
about their grammar).

cheers

Daniel
 
R

Rolf Magnus

Daniel said:
Jess said:
Hi,

If I have an array of pointer like:

char* a[] = {"a","b","c"};

then it works fine. Since "a" is effectively "a" char**, I tried the
following, which doesn't work:

char** a = {"a","b","c"};

What's wrong here?

The first is proper semantics: you tell c++ that you want an array and
it provides you with an array initializer. In the second case you want a
pointer, not an array explicitly, so the array initializer doesn't
work. Behind the scenes it happens so that a actually is just a pointer
to the first element,

No, it doesn't. When you use the array, in most (but not all) cases, it
behaves as if it was a pointer, but it definitely isn't, neither to the
programmer, nor "behind the scenes".
 
R

Rolf Magnus

Erik said:
Hi,

If I have an array of pointer like:

char* a[] = {"a","b","c"};

then it works fine. Since "a" is effectively "a" char**

No, "a" is a char*, not a char**, but perhaps that was a typo?

I think by "a", the OP means the variable, not the literal.
 
R

Rolf Magnus

Jess said:
If I have an array of pointer like:

char* a[] = {"a","b","c"};

then it works fine. Since "a" is effectively "a" char**, I tried the
following, which doesn't work:

char** a = {"a","b","c"};

What's wrong here?

Your understanding of pointers and arrays. Please write down 1000 times:

An array is NOT a pointer!
 
J

Jess

I think by "a", the OP means the variable, not the literal.

Yes, that's what I meant.

Another question that still bothers me is that the name of an array
can decay into a pointer pointing to its first element, but we never
use a a pointer pointing to the whole array. I rewrite my example as
follows to avoid the confusion of "a":

const char* x = {"a", "b", "c"};

Then "x" is a const char*[3], and can decay into const char**. I've
heard about a pointer pointing to the entire array, but haven't seen
an example yet. For my example, how can I get a pointer pointing to
the whole "x" array? In addition, what can we use it for?

In addition, each string literal (like "b" above) is a const char[2].
Then it looks like I can declare "x" as:

const char x[2][3] = {"a", "b", "c"};

However, this multidimension array declaration failed. Why did it
fail?

Another array problem is that if I have a function (T is some type):

void foo(T* p);

and suppose I try to make it versatile so that it is applicable to
both a pointer and an array that decays into a pointer. When this
function is called, there's no direct way for the function to know
whether its argument is really a pointer or an array, is this right?
If so, I guess it's the responsibility of this function to check (by
some method) if the argument is a pointer or not. Is this right? I
think if "T" is "char" and if I pass a string literal, then this
checking can be done relatively easily because there is a '\0' at the
end. However, I can't see any method for other "T". Any suggestion
how I can solve my problem? Thanks!

Jess
 
V

Victor Bazarov

Jess said:
Yes, that's what I meant.

Another question that still bothers me is that the name of an array
can decay into a pointer pointing to its first element, but we never
use a a pointer pointing to the whole array. I rewrite my example as
follows to avoid the confusion of "a":

const char* x = {"a", "b", "c"};

You probably meant

const char* x[] = {"a", "b", "c"};
Then "x" is a const char*[3], and can decay into const char**. I've
heard about a pointer pointing to the entire array, but haven't seen
an example yet. For my example, how can I get a pointer pointing to
the whole "x" array?

const char* (*pa)[3] = &x;
In addition, what can we use it for?

Not sure. I can't recall ever needing one.
In addition, each string literal (like "b" above) is a const char[2].
Then it looks like I can declare "x" as:

const char x[2][3] = {"a", "b", "c"};

No, the dimensions are reversed.
However, this multidimension array declaration failed. Why did it
fail?

It ought to be

const char x[3][2] = ...
Another array problem is that if I have a function (T is some type):

void foo(T* p);

and suppose I try to make it versatile so that it is applicable to
both a pointer and an array that decays into a pointer. When this
function is called, there's no direct way for the function to know
whether its argument is really a pointer or an array, is this right?
Right.

If so, I guess it's the responsibility of this function to check (by
some method) if the argument is a pointer or not. Is this right?

No. The responsibility lies on the caller, in most cases. Pass the
size along and treat is an an array if the size > 0. Treat it as
a single object if the size == 0.
I
think if "T" is "char" and if I pass a string literal, then this
checking can be done relatively easily because there is a '\0' at the
end. However, I can't see any method for other "T". Any suggestion
how I can solve my problem? Thanks!

void foo(T* p, size_t s = 0);

V
 
M

Mumia W.

[...]
Another question that still bothers me is that the name of an array
can decay into a pointer pointing to its first element, but we never
use a a pointer pointing to the whole array. I rewrite my example as
follows to avoid the confusion of "a":

const char* x = {"a", "b", "c"};

Then "x" is a const char*[3], and can decay into const char**. I've
heard about a pointer pointing to the entire array, but haven't seen
an example yet. For my example, how can I get a pointer pointing to
the whole "x" array? In addition, what can we use it for?

Here is an example:


#include <cstdlib>
#include <string>
#include <iostream>

using std::cout;
using std::endl;

void print_array(int (*array)[3]) {
const int asize = sizeof(*array)/sizeof((*array)[0]);
cout << "The array size is " << asize << endl;

for (int i = 0; i < asize; ++i) {
cout << (*array) << " ";
}
cout << endl;
}


int main (void)
{
int avals[3] = { 16, 21, 71 };
print_array(&avals);

return EXIT_SUCCESS;
}

</CODE>

I don't think is particularly useful to have a pointer to the whole
array. The only advantage (which I demonstrate) is that the function
called on such an array can know the full array size at compile time.
However, normally that is a reduction in flexibility versus the C/C++
normal way of handling arrays.

In addition, each string literal (like "b" above) is a const char[2].
Then it looks like I can declare "x" as:

const char x[2][3] = {"a", "b", "c"};

const char x[2][3] = {"ab", "cd"};

BTW, now that you have an array of arrays rather than an array of char
pointers, it is safe to remove the 'const':

char x[2][3] = {"ab", "cd"};
However, this multidimension array declaration failed. Why did it
fail?
[...]

The initializer was wrong.
 
O

Old Wolf

Jess said:
Then "x" is a const char*[3], and can decay into const char**. I've
heard about a pointer pointing to the entire array, but haven't seen
an example yet. For my example, how can I get a pointer pointing to
the whole "x" array?

const char* (*pa)[3] = &x;
In addition, what can we use it for?

Not sure. I can't recall ever needing one.

I use them in functions that expect to be passed a fixed-size array,
e.g.
cryptographic functions:
bool des_cbc_checksum( byte (*out)[8], void const *in, size_t
in_len );
No. The responsibility lies on the caller, in most cases. Pass the
size along and treat is an an array if the size > 0. Treat it as
a single object if the size == 0.

void foo(T* p, size_t s = 0);

Wouldn't it make more sense to use 1 as the size of a single object,
and have 0 be an error?
 
J

James Kanze

Then "x" is a const char*[3], and can decay into const char**. I've
heard about a pointer pointing to the entire array, but haven't seen
an example yet. For my example, how can I get a pointer pointing to
the whole "x" array?
const char* (*pa)[3] = &x;
In addition, what can we use it for?
Not sure. I can't recall ever needing one.
[/QUOTE]
I use them in functions that expect to be passed a fixed-size array,
e.g.
cryptographic functions:
bool des_cbc_checksum( byte (*out)[8], void const *in, size_t
in_len );

In most such cases, I'd use a reference to the array, rather
than a pointer (unless, of course, I had to be compatible with
C).
Wouldn't it make more sense to use 1 as the size of a single object,
and have 0 be an error?

It depends. I can't think of a case where it would make sense
to have a parameter which can be either an array or a scalar,
but if it did, I'd probably use -1 as the flag for scalar, in
order to distinguish the case from an array with either 0 or 1
members.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top