1

Related thread here: Does C99 guarantee that arrays are contiguous?

Apparently answer() isn't valid below, but could be re-written to use char * or cast to int[nElements] (possibly). I'll admit I don't understand the standard references and why a contiguous block of int couldn't be accessed via int* if properly aligned.

First is the following code block valid on most C++ platforms?

void answer(int *pData, size_t nElements)
{
    for( size_t i=0; i<nElements; ++i )
        pData[i] = 42;
}

void random_code()
{
    int arr1[1][2][3][4];               // local allocation
    answer(arr1, sizeof(arr1) / sizeof(int));
    int arr2[20][15];
    answer(arr2, sizeof(arr2) / sizeof(int));
}

Second does answer() remain valid for all allocation types (global, local, heap(hopefully correct!))?

int g_arr[20][15]; // global
void foo() {
    int (*pData)[10] = new int[50][10];  // heap allocation, at least partially
    answer(&pData[0][0], 50*10);
    // not even sure if delete[] will free pData correctly, but...
}
Community
  • 1
  • 1

3 Answers3

1

The code in answer() is fine. The code in random_code() is misusing answer() (or not calling the overload of answer() shown in the question). It should be:

void random_code()
{
    int arr1[1][2][3][4];
    answer(&arr1[0][0][0][0], sizeof(arr1) / sizeof(int));
    int arr2[20][15];
    answer(&arr2[0][0], sizeof(arr2) / sizeof(int));
}

The code in answer() expects an int *; you were passing an int (*)[2][3][4] and an int (*)[15], neither of which looks like int *.

This remains valid for other allocation mechanisms that allocate a single contiguous block of data, such as the ones shown.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • I should have run this first I guess, dern pseudo code. It looks like this also works: `answer((int*)arr1, sizeof(arr1) / sizeof(int));`. –  Nov 08 '13 at 15:55
  • "This remains valid for other allocation mechanisms" - Except anything with a loop-based array allocation with more than one call to new, malloc etc. Those might be jagged, or could be spread all over memory. –  Nov 08 '13 at 16:04
  • Yes, you can use a brute force cast too. And the 'that allocate a single contiguous block of data' rider in my answer excludes 'loop-based array allocation with more than one call to new, malloc, etc'. – Jonathan Leffler Nov 08 '13 at 16:04
1

Yes, most platforms will indeed pack the elements of an N-dimensional array in such a way that linear addressing on a pointer to the first element will find all of the elements.

It is actually hard (as in, I cannot figure it out) to come up with a standards compliant implementation that does not do this, as an array of arrays must pack said arrays, and the size of the array of arrays is the size of each sub array times the number of arrays of arrays. There does not seem to be room for it not to work. Even the ordering of each element seems to be well defined.

Despite this, no clause in the standard I am aware of lets you actually reinterpret the pointer to the first element of a multi dimensional array as a pointer to an array of the product. Many clauses talk about how you can only access the elements of the array, or one-past-the-end.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Hmm, the only thing I could think was something about "what if 8 byte boundaries" and each array for some reason "had" to be aligned on one of those boundaries. But then the memory block wouldn't be sizeof(type)*m*n*... it would actually be bigger. I guess I'll go back to my gut feeling: Just do anything important with single dim arrays. –  Nov 08 '13 at 15:58
  • @ebyrob yep, inter-array padding is illegal. Reordering the elements in strange ways at different dimensions is probably illegal. I cannot even think of how segmented memory could get in the way (which is usually my go-to for this kind of insanity), as the array-of-arrays needs to all be in the same segment... Maybe a pointer memory model where objects up to a certain size are positioned one way in memory, and larger the opposite way, with `pointer+integer` reversing the addition if the size of the pointed to type is large enough -- that pathological case *might* actually be standard-legal? – Yakk - Adam Nevraumont Nov 08 '13 at 16:03
  • Wow yes, big and little endian on steroids combined in one architecture might break it! Brilliant. –  Nov 08 '13 at 16:52
0

As the previous person said, there's a type error in your code. You're trying to use an int ()[X] type actual argument for an int formal argument. So to make your code work, you should use type casting.

C++/C uses the same memory layout for data types not depending on what section of memory is used for allocating an object so that the same code can be used for values where they are. So the answer to your second question, is if your code is working on stack-allocated values, it is going to work with a heap-allocated value too.

Don Jang
  • 9
  • 1
  • You're talking about his line: `answer(&pData[0][0], 50*10);`? So I need to cast pData? –  Nov 08 '13 at 15:46