array of pointers

Discussion in 'C++' started by Jess, Apr 27, 2007.

  1. Jess

    Jess Guest

    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
     
    Jess, Apr 27, 2007
    #1
    1. Advertising

  2. Jess

    Tim Love Guest

    Jess <> writes:
    > ...
    >So, when I pass an array to an function, I can
    >treat it as char**, but not when I define it?


    http://c-faq.com/aryptr/index.html
    has some similar questions, with answers.
     
    Tim Love, Apr 27, 2007
    #2
    1. Advertising

  3. On 27 Apr, 13:54, Jess <> wrote:
    > 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.

    --
    Erik Wikström
     
    =?iso-8859-1?q?Erik_Wikstr=F6m?=, Apr 27, 2007
    #3
  4. Jess wrote:
    > 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
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Apr 27, 2007
    #4
  5. Jess

    James Kanze Guest

    On Apr 27, 1:54 pm, Jess <> wrote:

    > 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.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Apr 27, 2007
    #5
  6. Jess <> writes:

    > 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
     
    Daniel Oberhoff, Apr 27, 2007
    #6
  7. Jess

    Jess Guest

    Thanks a lot to all of your answers! :)

    Jess
     
    Jess, Apr 28, 2007
    #7
  8. Jess

    Rolf Magnus Guest

    Daniel Oberhoff wrote:

    > Jess <> writes:
    >
    >> 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".
     
    Rolf Magnus, Apr 28, 2007
    #8
  9. Jess

    Rolf Magnus Guest

    Erik Wikström wrote:

    > On 27 Apr, 13:54, Jess <> wrote:
    >> 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.
     
    Rolf Magnus, Apr 28, 2007
    #9
  10. Jess

    Rolf Magnus Guest

    Jess wrote:

    > 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!
     
    Rolf Magnus, Apr 28, 2007
    #10
  11. Jess

    Jess Guest

    On Apr 28, 8:44 pm, Rolf Magnus <> wrote:
    > 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
     
    Jess, Apr 29, 2007
    #11
  12. Jess wrote:
    > On Apr 28, 8:44 pm, Rolf Magnus <> wrote:
    >> 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"};


    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
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Apr 29, 2007
    #12
  13. Jess

    Mumia W. Guest

    On 04/29/2007 04:17 AM, Jess wrote:
    > [...]
    > 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.
     
    Mumia W., Apr 29, 2007
    #13
  14. Jess

    Old Wolf Guest

    On Apr 30, 4:10 am, "Victor Bazarov" <> wrote:
    > Jess wrote:
    > > 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 );

    > > 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.
    >
    > 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?
     
    Old Wolf, Apr 29, 2007
    #14
  15. Jess

    James Kanze Guest

    On Apr 30, 12:22 am, Old Wolf <> wrote:
    > On Apr 30, 4:10 am, "Victor Bazarov" <> wrote:


    > > Jess wrote:
    > > > 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 );


    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).

    > > > 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.


    > > 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?


    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.


    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Apr 30, 2007
    #15
  16. Jess

    Jess Guest

    Thanks a lot for all your useful suggestions! :)

    Jess
     
    Jess, May 2, 2007
    #16
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Peter B. Steiger

    Can a static array contain a dynamic array of pointers?

    Peter B. Steiger, Apr 19, 2004, in forum: C Programming
    Replies:
    8
    Views:
    2,134
    Dave Thompson
    Apr 26, 2004
  2. mann!

    pointer to array v/s array of pointers

    mann!, Feb 25, 2005, in forum: C Programming
    Replies:
    6
    Views:
    356
    E. Robert Tisdale
    Feb 26, 2005
  3. Sean
    Replies:
    2
    Views:
    661
    loufoque
    Sep 24, 2006
  4. Piotrek

    pointers and array of pointers

    Piotrek, Apr 2, 2007, in forum: C Programming
    Replies:
    8
    Views:
    351
    Chris Torek
    Apr 6, 2007
  5. cerr

    pointers, pointers, pointers...

    cerr, Apr 7, 2011, in forum: C Programming
    Replies:
    12
    Views:
    733
Loading...

Share This Page