pointer to an array -Is there an out of bound access?

Discussion in 'C Programming' started by Kavya, Oct 28, 2006.

  1. Kavya

    Kavya Guest

    int main (){

    int a[][3]={{1,2,3},{4,5,6}};
    int (*ptr)[3]=a;

    /* This should be fine and give 3 as output*/
    printf("%d\n",(*ptr)[2]);

    ++ptr;

    /* This should be fine and give 6 as output*/
    printf("%d\n",(*ptr)[2]);

    return 0;
    }

    But what if I do something like this

    int main (){

    int a[][3]={{1,2,3},{4,5,6}};
    int (*ptr)[3]=a;

    /* This should be fine and give 3 as output*/
    printf("%d\n",(*ptr)[2]);

    /* Will this be fine??
    printf("%d\n",(*ptr)[5]);
    return 0;
    }

    Is the second printf call in second code fine? or is it out of bound
    access?
    I tried both the codes with gcc 3.4.5 with -Wall and -pedantic. There
    was no warning and got the correct output as 3 and 6 in both codes.
     
    Kavya, Oct 28, 2006
    #1
    1. Advertising

  2. Kavya

    Cong Wang Guest

    On Oct 28, 11:43 am, "Kavya" <> wrote:
    > int main (){
    >
    > int a[][3]={{1,2,3},{4,5,6}};
    > int (*ptr)[3]=a;
    >
    > /* This should be fine and give 3 as output*/
    > printf("%d\n",(*ptr)[2]);
    >
    > ++ptr;
    >
    > /* This should be fine and give 6 as output*/
    > printf("%d\n",(*ptr)[2]);
    >
    > return 0;
    >
    > }But what if I do something like this
    >
    > int main (){
    >
    > int a[][3]={{1,2,3},{4,5,6}};
    > int (*ptr)[3]=a;
    >
    > /* This should be fine and give 3 as output*/
    > printf("%d\n",(*ptr)[2]);
    >
    > /* Will this be fine??
    > printf("%d\n",(*ptr)[5]);
    > return 0;
    >
    > }Is the second printf call in second code fine? or is it out of bound
    > access?
    > I tried both the codes with gcc 3.4.5 with -Wall and -pedantic. There
    > was no warning and got the correct output as 3 and 6 in both codes.


    It's out.
    I also use gcc and got the following:

    3
    -1074239864

    .. In fact, 'ptr' is NOT a common int pointer. See the following:

    int *p = (int*)a;
    printf("%d\n", p[5]);

    That's OK, because 'p' is a common int pointer.
     
    Cong Wang, Oct 28, 2006
    #2
    1. Advertising

  3. Kavya:

    > int main (){
    >
    > int a[][3]={{1,2,3},{4,5,6}};



    Equivalent to:

    int a[2][3] = {{1,2,3},{4,5,6}};


    > int (*ptr)[3]=a;



    Equivalent to:

    int (*ptr)[3] = &a[0];


    > /* This should be fine and give 3 as output*/
    > printf("%d\n",(*ptr)[2]);



    Equivalent to:

    printf("%d\n", a[0][2]);


    > ++ptr;



    Equivalent to:

    ptr = &a[1];


    > /* This should be fine and give 6 as output*/
    > printf("%d\n",(*ptr)[2]);



    Equivalent to:

    printf("%d\n", a[1][2]);


    > return 0;
    > }



    That works fine.


    > But what if I do something like this
    >
    > int main (){
    >
    > int a[][3]={{1,2,3},{4,5,6}};
    > int (*ptr)[3]=a;
    >
    > /* This should be fine and give 3 as output*/
    > printf("%d\n",(*ptr)[2]);
    >
    > /* Will this be fine??
    > printf("%d\n",(*ptr)[5]);



    Basically you're asking if the Standard necessitates that multi-dimensional
    arrays be lain out in a particular way in memory, specifically:

    a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2]

    I'm pretty sure that things have to be like this, but maybe someone can
    give a quote from the Standard proving or disproving the necessity.

    --

    Frederick Gotham
     
    Frederick Gotham, Oct 28, 2006
    #3
  4. Frederick Gotham:

    > Basically you're asking if the Standard necessitates that
    > multi-dimensional arrays be lain out in a particular way in memory,
    > specifically:
    >
    > a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2]
    >
    > I'm pretty sure that things have to be like this, but maybe someone can
    > give a quote from the Standard proving or disproving the necessity.



    I actually, if I put a tad bit of thought into it, I don't need to consult
    the Standard.

    We know that:

    (1) There cannot be padding between array elements or after.
    (2) Each consecutive array element must have ascending addresses.

    Also, there's no such thing as multi-dimensional arrays in C, but rather
    arrays of arrays. Therefore, looking at the first array:

    int (a[2])[3];

    We know that the three elements in this array must not have padding between
    them, and that their addresses must be ascending. Now, if we look at the
    array type, we see that each element is an int[2]. We know that this inner
    array must also have no padding between elements, and also that the
    addresses must be ascending.

    Therefore, the memory layout I showed above is necessitated by the
    Standard.

    --

    Frederick Gotham
     
    Frederick Gotham, Oct 28, 2006
    #4
  5. Frederick Gotham said:

    <snip>

    > Also, there's no such thing as multi-dimensional arrays in C


    Utter bilge.


    From C89's 3.3.2.1 Array subscripting:

    Successive subscript operators designate a member of a multi-dimensional
    array object.

    From C99's 6.5.2.1 Array subscripting:

    Successive subscript operators designate an element of a multidimensional
    array object.


    If the Standard says C has multi-dimensional arrays, C has multi-dimensional
    arrays.

    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
     
    Richard Heathfield, Oct 28, 2006
    #5
  6. Richard Heathfield:

    >> Also, there's no such thing as multi-dimensional arrays in C

    >
    > Utter bilge.



    Yes, you're right.


    > From C89's 3.3.2.1 Array subscripting:
    >
    > Successive subscript operators designate a member of a multi-dimensional
    > array object.



    Indeed they do.


    > From C99's 6.5.2.1 Array subscripting:
    >
    > Successive subscript operators designate an element of a
    > multidimensional array object.



    Again, you're right.


    > If the Standard says C has multi-dimensional arrays, C has
    > multi-dimensional arrays.



    Yes you're right. But how exactly do these multi-dimensional arrays work?

    Do you think it's right to say that, other than the proton and the
    electron, that there's a third kind of particle within the atom? Some would
    say yes, the neutron. Others would say no, because a neutron is little more
    than an electron and a proton bound together.

    So, I say that a multi-dimensional array is merely an array of arrays. And
    guess what, that way of thinking works well for me.

    If the Standard, or you for that matter, would like to say that there are
    multi-dimensional arrays in C, then go ahead, you're right; but as far as
    the grammar of the C programming language goes, they work like an array of
    arrays.

    --

    Frederick Gotham
     
    Frederick Gotham, Oct 28, 2006
    #6
  7. On Sat, 28 Oct 2006 10:57:12 GMT, Frederick Gotham
    <> wrote:

    >Frederick Gotham:
    >
    >> Basically you're asking if the Standard necessitates that
    >> multi-dimensional arrays be lain out in a particular way in memory,
    >> specifically:
    >>
    >> a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2]
    >>
    >> I'm pretty sure that things have to be like this, but maybe someone can
    >> give a quote from the Standard proving or disproving the necessity.

    >
    >
    >I actually, if I put a tad bit of thought into it, I don't need to consult
    >the Standard.
    >
    >We know that:
    >
    > (1) There cannot be padding between array elements or after.
    > (2) Each consecutive array element must have ascending addresses.
    >
    >Also, there's no such thing as multi-dimensional arrays in C, but rather
    >arrays of arrays. Therefore, looking at the first array:
    >
    > int (a[2])[3];
    >
    >We know that the three elements in this array must not have padding between
    >them, and that their addresses must be ascending. Now, if we look at the
    >array type, we see that each element is an int[2]. We know that this inner
    >array must also have no padding between elements, and also that the
    >addresses must be ascending.


    I agree with your intent but I think you would have been closer to the
    point you were trying to make to say the first array has two elements,
    each of which is an int[3] and then proceed to discuss the absence of
    padding between a[0] and a[1] followed by the combined effects of
    aligning a and a[0] and the absence of padding between a[j]
    and a[j+1].

    >
    >Therefore, the memory layout I showed above is necessitated by the
    >Standard.


    But if the compiler performs range checking on constant subscripts or
    inserts range checking into the executable code, it would compliant to
    issue a diagnostic and reject the translation unit or terminate the
    execution of the program for a serious run time error, respectively.


    Remove del for email
     
    Barry Schwarz, Oct 28, 2006
    #7
  8. Richard Heathfield <> writes:
    [...]
    > From C89's 3.3.2.1 Array subscripting:
    >
    > Successive subscript operators designate a member of a multi-dimensional
    > array object.
    >
    > From C99's 6.5.2.1 Array subscripting:
    >
    > Successive subscript operators designate an element of a multidimensional
    > array object.
    >
    >
    > If the Standard says C has multi-dimensional arrays, C has
    > multi-dimensional arrays.


    Yes, but it's really just a matter of terminology. If the C standard
    didn't mention multidimensional arrays, or even if it explicitly
    stated "The C language does not have multidimensional arrays, but it
    does have arrays of arrays", then it would still describe exactly the
    same language.

    You can declare an array of arrays. The question of whether you can
    call that a multidimensional array has a clear answer (yes, because
    the standard says so), but it's not a very important question.

    Note that some languages do support multidimensional arrays as a
    distinct concept; arr1[x][y] indexes into an array of arrays, and
    arr2[x,y] indexes into a two-dimensional array. C, of course, doesn't
    do this (and the existence of the comma operator makes arr2[x,y] a
    trap for the unwary).

    Digression follows.

    Similarly, we say that C *doesn't* have pass-by-reference because the
    standard doesn't use that term. But if the standard referred to
    passing a pointer-to-foo as passing the foo by reference, then we'd
    have to say that C *does* support pass-by-reference. In fact, C does
    support pass-by-reference *as a programming technique*, but not as a
    language construct.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Oct 28, 2006
    #8
  9. Keith Thompson said:

    <snip>

    > Digression follows.
    >
    > Similarly, we say that C *doesn't* have pass-by-reference because the
    > standard doesn't use that term. But if the standard referred to
    > passing a pointer-to-foo as passing the foo by reference, then we'd
    > have to say that C *does* support pass-by-reference. In fact, C does
    > support pass-by-reference *as a programming technique*, but not as a
    > language construct.


    As you probably recall, I think it is easier to explain parameter-passing to
    a newbie if one sticks strictly to the "pass-by-value" terminology, even
    when pointers are being passed. There is no need to make an exception for
    pointers, and to do so leads to confusion, as we occasionally see in
    questions on this newsgroup.

    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
     
    Richard Heathfield, Oct 28, 2006
    #9
  10. Richard Heathfield <> writes:
    > Keith Thompson said:
    > <snip>
    >
    >> Digression follows.
    >>
    >> Similarly, we say that C *doesn't* have pass-by-reference because the
    >> standard doesn't use that term. But if the standard referred to
    >> passing a pointer-to-foo as passing the foo by reference, then we'd
    >> have to say that C *does* support pass-by-reference. In fact, C does
    >> support pass-by-reference *as a programming technique*, but not as a
    >> language construct.

    >
    > As you probably recall, I think it is easier to explain parameter-passing to
    > a newbie if one sticks strictly to the "pass-by-value" terminology, even
    > when pointers are being passed. There is no need to make an exception for
    > pointers, and to do so leads to confusion, as we occasionally see in
    > questions on this newsgroup.


    I think it depends on the newbie. For someone who's learning to
    program for the first time, it probably makes sense to stick to the
    idea of "pass-by-value", and later introduce the idea that passing
    pointers by value can be a useful technique if you want to modify the
    pointed-to object.

    On the other hand, someone who's new to C, but has experience in some
    other language that *does* directly support pass-by-reference, will
    likely find it useful to know that passing a pointer is the way to
    implement the equivalent of pass-by-reference in C. (When I first
    learned C, most of my programming experience was in Pascal.)

    I might also argue that pass-by-reference is a useful concept in
    computer science in general, independent of any particular language,
    and it's useful to see how that concept is mapped onto the constructs
    of a particular language.

    C doesn't "have" linked lists, binary trees, or pass-by-reference.
    You can implement them all using pointers. If I present a chunk of C
    code that implements a linked list and say "This is a linked list",
    nobody is going to jump up and say "No, C doesn't have linked lists;
    that's just a structure with a pointer in it and some functions that
    operate on it".

    But that's not a perfect analogy, and I can certainly see your point.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
     
    Keith Thompson, Oct 28, 2006
    #10
  11. Barry Schwarz:

    >>Therefore, the memory layout I showed above is necessitated by the
    >>Standard.

    >
    > But if the compiler performs range checking on constant subscripts or
    > inserts range checking into the executable code, it would compliant to
    > issue a diagnostic and reject the translation unit or terminate the
    > execution of the program for a serious run time error, respectively.



    Wha. . . ? Sounds a bit drastic. Are you sure the compiler is entitled to
    do that even when you definitely should be able to do what you're trying to
    do? Consider the following code for instance; it's not exactly politically
    correct, but there shouldn't be a problem with it.

    #include <stdlib.h>
    #include <stdio.h>
    #include <assert.h>

    int main(void)
    {
    assert( sizeof(double) > sizeof(int) );

    { /* Start */

    double *p;
    int *q;
    char unsigned const *pover;
    char unsigned const *ptr;

    p = malloc(5 * sizeof*p);
    q = (int*)p++;
    pover = (char unsigned*)(p+4);
    ptr = (char unsigned*)p;
    p[3] = 2423.234;
    *q++ = -9;

    do printf("%d",(int)*ptr++);
    while (pover != ptr);

    return 0;

    } /* End */
    }


    The code might look a bit weird, but that shouldn't entitle a compiler to
    do whatever it wants with it.

    --

    Frederick Gotham
     
    Frederick Gotham, Oct 28, 2006
    #11
  12. Frederick Gotham:

    > p = malloc(5 * sizeof*p);



    if (!p) return EXIT_FAILURE;



    > return 0;



    free(--p);
    return 0;

    --

    Frederick Gotham
     
    Frederick Gotham, Oct 28, 2006
    #12
  13. Kavya

    Old Wolf Guest

    Frederick Gotham wrote:
    > Do you think it's right to say that, other than the proton and the
    > electron, that there's a third kind of particle within the atom? Some would
    > say yes, the neutron. Others would say no, because a neutron is little more
    > than an electron and a proton bound together.


    A neutron is nothing at all like an electron and a proton bound
    together (whatever that means). What have you been smoking?
     
    Old Wolf, Oct 29, 2006
    #13
  14. Frederick Gotham said:

    > Barry Schwarz:
    >
    >>>Therefore, the memory layout I showed above is necessitated by the
    >>>Standard.

    >>
    >> But if the compiler performs range checking on constant subscripts or
    >> inserts range checking into the executable code, it would compliant to
    >> issue a diagnostic and reject the translation unit or terminate the
    >> execution of the program for a serious run time error, respectively.

    >
    >
    > Wha. . . ? Sounds a bit drastic. Are you sure the compiler is entitled to
    > do that even when you definitely should be able to do what you're trying
    > to do?


    Yes, the compiler is entitled to do that, and exceeding bounds is not
    something you should definitely be able to do.


    > Consider the following code for instance; it's not exactly
    > politically correct, but there shouldn't be a problem with it.


    If you want help with your code, don't obfuscate it, and don't hurl insults
    at the very people who can help you.

    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
     
    Richard Heathfield, Oct 29, 2006
    #14
  15. Kavya

    pete Guest

    Kavya wrote:

    > int main (){
    >
    > int a[][3]={{1,2,3},{4,5,6}};
    > int (*ptr)[3]=a;
    >
    > /* This should be fine and give 3 as output*/
    > printf("%d\n",(*ptr)[2]);
    >
    > /* Will this be fine??
    > printf("%d\n",(*ptr)[5]);
    > return 0;
    > }
    >
    > Is the second printf call in second code fine?
    > or is it out of bound access?


    It's an out of bound access.

    > I tried both the codes with gcc 3.4.5 with -Wall and -pedantic. There
    > was no warning and got the correct output as 3 and 6 in both codes.


    That's the point of programmers learning the language better.

    --
    pete
     
    pete, Oct 29, 2006
    #15
  16. Kavya wrote:

    > I tried both the codes with gcc 3.4.5 with -Wall and -pedantic. There
    > was no warning and got the correct output as 3 and 6 in both codes.


    Sometimes you can get lucky with undefined behavior. Nothing to see
    here, folks. Move along.
     
    james of tucson, Oct 29, 2006
    #16
  17. Frederick Gotham wrote:
    > ...
    > I actually, if I put a tad bit of thought into it, I don't need to consult
    > the Standard.
    >
    > We know that:
    >
    > (1) There cannot be padding between array elements or after.
    > (2) Each consecutive array element must have ascending addresses.
    >
    > Also, there's no such thing as multi-dimensional arrays in C, but rather
    > arrays of arrays. Therefore, looking at the first array:
    >
    > int (a[2])[3];
    >
    > We know that the three elements in this array must not have padding between
    > them, and that their addresses must be ascending. Now, if we look at the
    > array type, we see that each element is an int[2]. We know that this inner
    > array must also have no padding between elements, and also that the
    > addresses must be ascending.
    >
    > Therefore, the memory layout I showed above is necessitated by the
    > Standard.
    > ...


    The memory layout is indeed necessitated by the standard, but the issue here is
    not limited to the memory layout. The formal issue here is in fact the same as
    with the recently-discussed "struct hack". It, once again, depends on the
    intended meaning of the pointer arithmetic rules. When applied to indexing an
    array object, were they supposed to refer to the declared size of the array
    object or the actual size of the underlying memory block? The standard itself
    does not answer that question explicitly (neither C89/90 nor C99). (Several
    people here insisted that it does, but no one was able to produce a convincing
    quote.) However, it is informally known that the intent was to limit the pointer
    arithmetic for such cases with the _declared_ size of the array object.

    Applied to the OP's example, this means that accessing, say, '(*ptr)[5]' when
    'ptr' is declared as 'int (*ptr)[3]' is illegal. Attempts to tie this formal
    requirement to practice usually insist that implementation is allowed to
    represent the '*ptr' value is a way that only allows access to elements in 0-2
    range (exactly the same reasoning as with the "struct hack"). Once again, this
    is based on the aforementioned "informally canonical" interpretation of the
    address arithmetic rules.

    As an interesting side note, IIRC, Stroustrup's C++ book includes (-ed?) an
    example where a multi-dimensional array is actually accessed in that "illegal"
    fashion, even though C++'s address arithmetic rules are no different from C's.

    --
    Best regards,
    Andrey Tarasevich
     
    Andrey Tarasevich, Oct 31, 2006
    #17
  18. Andrey Tarasevich:

    > Applied to the OP's example, this means that accessing, say, '(*ptr)[5]'
    > when 'ptr' is declared as 'int (*ptr)[3]' is illegal. Attempts to tie
    > this formal requirement to practice usually insist that implementation
    > is allowed to represent the '*ptr' value is a way that only allows
    > access to elements in 0-2 range (exactly the same reasoning as with the
    > "struct hack"). Once again, this is based on the aforementioned
    > "informally canonical" interpretation of the address arithmetic rules.



    What about the following, is it OK?

    int arr[2][2];

    int *p = *arr;

    p[3] = 8;

    If it is OK, then the following should be OK aswell:

    arr[0][3] = 8;

    , because the compiler must treat it as:

    *( *(arr+0) + 3)

    arr decays to a pointer to its first element, an R-value of type int(*)[2]
    It then has zero added to it, which has no effect.
    It is then dereferenced, yielding an L-value of type int[2]
    It then decays to a pointer to its first element, an R-value of type int*
    It then has 3 added to it
    It is then dereference, yielding an L-value of type int.

    Even when we use "arr" directly, I don't see the problem.

    --

    Frederick Gotham
     
    Frederick Gotham, Oct 31, 2006
    #18
  19. Frederick Gotham said:

    > What about the following, is it OK?
    >
    > int arr[2][2];
    >
    > int *p = *arr;
    >
    > p[3] = 8;


    No, for reasons that have already been explained ad nauseam.

    --
    Richard Heathfield
    "Usenet is a strange place" - dmr 29/7/1999
    http://www.cpax.org.uk
    email: rjh at above domain (but drop the www, obviously)
     
    Richard Heathfield, Oct 31, 2006
    #19
  20. Richard Heathfield:

    > Frederick Gotham said:
    >
    >> What about the following, is it OK?
    >>
    >> int arr[2][2];
    >>
    >> int *p = *arr;
    >>
    >> p[3] = 8;

    >
    > No, for reasons that have already been explained ad nauseam.



    Then how can we treat any chunk of memory as if it's an array of unsigned
    char?

    --

    Frederick Gotham
     
    Frederick Gotham, Oct 31, 2006
    #20
    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. sunil panda

    Lower bound & Upper bound

    sunil panda, Dec 25, 2003, in forum: Java
    Replies:
    9
    Views:
    7,295
    thushara wijeratna
    Oct 7, 2008
  2. Rhiner Dan
    Replies:
    1
    Views:
    755
    Mike Wahler
    Mar 27, 2005
  3. Mario Krsnic
    Replies:
    0
    Views:
    389
    Mario Krsnic
    Jun 23, 2006
  4. Phillip Vong
    Replies:
    0
    Views:
    426
    Phillip Vong
    Jul 27, 2006
  5. , India

    pointer to an array vs pointer to pointer

    , India, Sep 20, 2011, in forum: C Programming
    Replies:
    5
    Views:
    465
    James Kuyper
    Sep 23, 2011
Loading...

Share This Page