Thread: initialization in multi dimensional arrays

  1. #1
    Registered User
    Join Date
    Mar 2011
    Posts
    45

    initialization in multi dimensional arrays

    I created and initialized a multi dimensional array as follows:

    Code:
    int arr[3][2] = {{1,2},{3,4},{5,6}};
    when i wrote down the following line, it printed the value 4.
    Code:
    printf("%d",arr[0][3]);
    what i don't understand is that when i created the array,
    i only gave it 2 columns.
    But when i wrote arr[0][3] , it still printed a value.
    How did this happen..??

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by narendrav
    what i don't understand is that when i created the array,
    i only gave it 2 columns.
    But when i wrote arr[0][3] , it still printed a value.
    How did this happen..??
    Imagine if you had declared arr as:
    Code:
    int arr[6] = {1, 2, 3, 4, 5, 6};
    You could still access arr as if it were a 2D array, e.g.,
    Code:
    for (i = 0; i < 3; ++i)
    {
        for (j = 0; j < 2; ++j)
        {
            printf("%d ", arr[i * 2 + j]);
        }
        printf("\n"0;
    }
    So, the same maths applies here: arr[0][3] in your example would be arr[0 * 2 + 3], i.e., arr[3] in my example, which has the value of 4. We get the multiplier of 2 because each increment of the first index "skips" 2 elements, i.e., the number of elements in one of the conceptual "inner arrays".

    That said, you should be careful here because if you were to miscalculate, you risk accessing the array out of bounds, and it would be harder to see at a glance because you are already intentionally accessing the inner arrays out of bounds (but still within the bounds of the array overall).
    Last edited by laserlight; 03-14-2014 at 09:51 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    what you're seeing is called undefined behavior. you're reading beyond what you told the compiler is the end of the array. it just happens that in the implementation of C that you're using, all the elements of the 2D array are stored in contiguous memory. so if you read 2 elements past the end of the first "row," you get the second element of the second "row." this behavior is not guaranteed, and in fact the international C standard allows literally anything to happen under those conditions. it could produce the behavior you see, or it could crash the program, or it could format your hard drive, or it could even, in an extreme edge case, cause Russia's nuclear missiles to launch. none of those outcomes are forbidden by the standard, when you do something that is undefined.
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

  4. #4
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    ^ I was just in the process of typing up a similar reply.

    J.2 Undefined behavior
    1 The behavior is undefined in the following circumstances:

    ...

    — An array subscript is out of range, even if an object is apparently accessible with the
    given subscript (as in the lvalue expression a[1][7] given the declaration int
    a[4][5]) (6.5.6).

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Elkvis
    it just happens that in the implementation of C that you're using, all the elements of the 2D array are stored in contiguous memory.
    All the elements of an array are contiguous. It follows that all of the elements of a 2D array are also contiguous.

    EDIT:
    Quote Originally Posted by Matticus
    I was just in the process of typing up a similar reply.
    Your reply is far more convincing though, since Elkvis' claim of undefined behaviour has an incorrect justification. I am curious if it follows that a direct accessing of a 2D array as if it were a 1D array similiarly results in undefined behaviour: the surrounding points in that section are not clear on that.
    Last edited by laserlight; 03-14-2014 at 10:16 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by laserlight View Post
    Your reply is far more convincing though, since Elkvis' claim of undefined behaviour has an incorrect justification. I am curious if it follows that a direct accessing of a 2D array as if it were a 1D array similiarly results in undefined behaviour: the surrounding points in that section are not clear on that.
    I think the problem is that what is at the end of an array (padding for alignment or optimisation, sentinels, whatever) is up the the compiler. In the case of multidimensional arrays then each "subarray" is an array itself. I.e. given int a[5][2] then a[0] is an int[2] object. Looked at in isolation like this is compiler free to add stuff to the end of a the array aggregate, as it would be for any other single-dimension array? I would say yes, and therefore this would be the source of the undefined behaviour being discussed. I wish I could find a clear reference in the C Standard.

    As a side note, this is one of the reasons I generally avoid multidimensional arrays... I don't like the (my) uncertainty, so I usually implement everything as a 1d array and address it myself
    Last edited by Hodor; 03-14-2014 at 07:04 PM. Reason: typo

  7. #7
    Registered User
    Join Date
    Jan 2014
    Posts
    45
    6.5.3.4 is worth a read. Given that sizeof array / sizeof array[0] computes the number of elements in an array and memcpy(ptr, array, sizeof array) copies the entire array object, the only place you can fit any padding, inside of an int[5][2] object, is inside of an int (whose size is implementation-defined).

  8. #8
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by zyxwvuts View Post
    6.5.3.4 is worth a read. Given that sizeof array / sizeof array[0] computes the number of elements in an array and memcpy(ptr, array, sizeof array) copies the entire array object, the only place you can fit any padding, inside of an int[5][2] object, is inside of an int (whose size is implementation-defined).
    Thanks. I guess that makes sense. Does what you're saying actually indicate that arrays cannot be padded or whatever appended to the end of them? If padding is allowed then the sizeof operator would be aware of that and your example would still work. I'm still not sure.

    What's the best way to pronounce your name?
    Last edited by Hodor; 03-15-2014 at 04:37 AM.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Hodor
    Does what you're saying actually indicate that arrays cannot be padded or whatever appended to the end of them? If padding is allowed then the sizeof operator would be aware of that and your example would still work. I'm still not sure.
    If there were hidden bytes not accounted for by sizeof, then the memcpy example would become problematic since some bytes will not be copied.

    As for memcpy, the conversion of the 2D array to be 1D array of characters (presumably as char* or unsigned char*) via void* is itself well defined. What I am thinking of is say, accessing the individual ints in arr in narendrav's example by having an int* initialised to &arr[0][0] and sizeof(arr) / sizeof(int) passed as the size, i.e., a reverse of my explanation in post #2.

    Quote Originally Posted by Hodor
    What's the best way to pronounce your name?
    zyxwvuts: please provide a canonical audio recording to answer this
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by laserlight View Post
    As for memcpy, the conversion of the 2D array to be 1D array of characters (presumably as char* or unsigned char*) via void* is itself well defined. What I am thinking of is say, accessing the individual ints in arr in narendrav's example by having an int* initialised to &arr[0][0] and sizeof(arr) / sizeof(int) passed as the size, i.e., a reverse of my explanation in post #2.
    And this is where the confusion arises. Why is the example Matticus provided undefined if this is the case?

    I remember a conversation a while ago about pointers and "adjacent" but separate aggregates (in this case arrays)... is this related?

  11. #11
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Why is the example Matticus provided undefined if this is the case?
    Code:
    int s[4][4];
    s[0][5] = 0; // ?
    I imagine the specifically undefined behavior is intended to allow compilers/environments to treat the above as an error.

    [Edit]
    Also obviously ʐ ɪχʋʉɖʂ is the correct pronunciation.
    [/Edit]

    Soma

    Interactive IPA Chart
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  12. #12
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by phantomotap View Post
    Code:
    int s[4][4];
    s[0][5] = 0; // ?
    I imagine the specifically undefined behavior is intended to allow compilers/environments to treat the above as an error.
    That's my point exactly. Why would they want to treat it as an error?

    |Edit|
    Given int a[6], is the compiler allowed to "allocate" that as int a[8] internally, padding with either 0s or whatever it likes? If so, then treating multidimensional arrays becomes... problematic.
    |/Edit|

    How do "canary" values work if the compiler is not allowed to "pad" an array? Buffer overflow protection - Wikipedia, the free encyclopedia


    Last edited by Hodor; 03-15-2014 at 06:03 AM.

  13. #13
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Hodor
    How do "canary" values work if the compiler is not allowed to "pad" an array?
    There is definitely no restriction preventing the reserving space after an array that is not an inner array of some multidimensional array.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  14. #14
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by laserlight View Post
    There is definitely no restriction preventing the reserving space after an array that is not an inner array of some multidimensional array.
    Where does the standard say an "inner array" is treated differently to an array that's not "inner"? That's what I'd like to know...

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Hodor
    Given int a[6], is the compiler allowed to "allocate" that as int a[8] internally, padding with either 0s or whatever it likes?
    I would say yes, that is permitted, but those padding bytes are not counted in the result of sizeof a, hence they are effectively hidden.

    Quote Originally Posted by Hodor
    Where does the standard say an "inner array" is treated differently to an array that's not "inner"?
    If there are hidden padding bytes after each element, then how can we say that the elements of the 2D array (as in 1D arrays) are contiguously allocated? If the padding bytes are counted, then how can sizeof applied to the 1D arrays result in the correct count?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Multi-dimensional arrays using variables
    By Know_Your_Role in forum C++ Programming
    Replies: 13
    Last Post: 12-10-2009, 12:32 PM
  2. multi-dimensional arrays
    By shuo in forum C++ Programming
    Replies: 7
    Last Post: 06-17-2008, 10:22 PM
  3. multi-dimensional arrays
    By maple23 in forum C Programming
    Replies: 4
    Last Post: 05-31-2008, 01:58 AM
  4. Multi-dimensional Arrays
    By thinhare in forum C Programming
    Replies: 9
    Last Post: 12-20-2004, 09:21 PM
  5. multi-dimensional arrays
    By abrege in forum C++ Programming
    Replies: 3
    Last Post: 02-05-2003, 05:09 PM

Tags for this Thread