1

I can create a two dimensional array in c++ in the following way. But I'm having trouble understanding the memory addressing.

(Please note the last line of my code where I try to print the decimal values of the memory locations.)

#include <cstdio>
#include <iostream>

using namespace std;

#define rowSize 3
#define colSize 4


int main(){
    int ** p;

    p = new int*[rowSize];

    for(int i = 0; i < rowSize; i++){
        p[i]= new int[colSize];
    }

    printf("the size of int**: %d\n", sizeof(int**));
    printf("the size of int*: %d\n", sizeof(int*));
    printf("the size of int: %d\n\n", sizeof(int));



    printf("%d %d", p[0], p[1]);
    return 0;
}

I used gcc version 4.7.1 (tdm-1) compiler and ran my program on my windows 10- 64 bit machine.

Here is a sample output:

the size of int**: 4

the size of int*: 4

the size of int: 4

8135000 8135024

So, here are my two questions:

  1. Why do the addresses differ by 24 instead of 16 (= 4*4) ? The size of int is 4 and there are 4 columns in a row. So shouldn't they differ by 16? I know about byte padding in structure in c++. Is something like this the reason behind it?

  2. I tried changing the colSize to 5:

    #define colSize 5 and recompiled and ran the program again.

    A sample output:

the size of int**: 4

the size of int*: 4

the size of int: 4


7151960 7151992

This time the addresses differ by 32. If byte padding was the reason, the 5 columns would require 5*4 = 20 bytes. A padding of 4 bytes would be sufficient in this case, and the addresses should differ by 24 in this case too.

So why are they differing by 32 in this case?

Ahsan Tarique
  • 581
  • 1
  • 11
  • 22
  • What kind of answer(s) do you expect? Explaining the implementation details of the gcc? Or would "The way the question is layed out those are impl.details which are not assured, you should not make predictions about them; but if you have to rely on X and Y, use this...." suffice? – VolkerK Apr 28 '16 at 07:34
  • Try the same with a real 2d array: int p[3][4]; – Bob__ Apr 28 '16 at 07:44
  • Yes, then their difference can be calculated. But I was more interested in understanding whether the `new int[colSize]` returns the address in some pattern. – Ahsan Tarique Apr 28 '16 at 07:57

3 Answers3

3
  1. Result of memory allocation operations is alignof(std::max_align_t)-aligned. In your case alignof(std::max_align_t) is probably 8.
  2. In most implementations there is an invisible amount of sizeof(std::max_align_t) bytes allocated alongside array for some internal bookkeeping. In your case it is probably have size of 8.

So in first case: 4*4 + 8 = 24, already a multiple of 8.
In second: 4*5 + 8 = 28, rounded up to nearest multiply of 8 = 32.

Compiler is not obliged to return increasing adressess or follow some pattern. It just happened that it is the easiest thing to do in your case.

Revolver_Ocelot
  • 8,609
  • 3
  • 30
  • 48
  • I used `printf("%d", size_t);` and got 4 in the output. But thanks, I was curious after finding the same difference everytime. – Ahsan Tarique Apr 28 '16 at 08:09
  • @AhsanTarique slightly fixed my answer to be more precise. I forgot that size_t is not maximum aligment type for 32bit machines – Revolver_Ocelot Apr 28 '16 at 08:12
1

The addresses in your p[i] arryas cells are defined by the new operator

p[i]= new int[colSize];

This operator can return any address from the heap and this is independent of the arrays sizes.

You may create one big one dimensional array (as compiler does array[][]) and map two dimensions to one dimension.

int* arr2d = new int[colSize*rowSize];
//Retrieve value from Row3 Col2
int nRow3Col2 = arr2d[2 + 3 * colSize];
dgrine
  • 702
  • 6
  • 15
Dmitriy Zapevalov
  • 1,357
  • 8
  • 13
  • They seem to differ by the same length on every run (though the addresses vary). So I thought there might be a pattern instead of the addresses being random. – Ahsan Tarique Apr 28 '16 at 07:49
  • It depends on `new` operator implementation (which can be overloaded BTW). Anyway addreses are not guaranteed. Also try to compile in `Release` mode and observe the difference. – Dmitriy Zapevalov Apr 28 '16 at 07:55
  • I'm afraid I didn't understand what you said about the Release mode. I tried to google it and found this in one of the resutls. [link](http://stackoverflow.com/questions/11253334/how-to-debug-in-release-mode) Should I try the method answered in the question? – Ahsan Tarique Apr 28 '16 at 08:21
  • You certainly should try it to understand it. It is the most simple and compact way of storing square 2D arrays. The more significant question is should you use it or not. It depends on your particular task. Read more about different types of arrays. – Dmitriy Zapevalov Apr 28 '16 at 08:25
-1

You are not writing C++ but C. As you tagged this as C++, I will assume you want C++...

Modern C++ uses RAII and greatly simplifies the sort of things by using the library standard containers. Although I am aware this isn't really an answer to your question, I would suggest you rewrite your code:

#include <vector>
#include <cstdio>
int main()
{
   int rowsize = ...;
   int colsize = ...;

// allocating
   std::vector<std::vector<int>> vec(rowsize);
   for( auto e: vec )
      e.resize(colsize);

// filling with values
   vec.at(row).at(col) = 123;
// printing values
   std::cout << vec.at(row).at(col) << std::endl;
}
kebs
  • 6,387
  • 4
  • 41
  • 70