Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is two dimensional array's memory representation?

Tags:

arrays

slice

go

In Java, two dimensional array is multi one-dimensional array. That means those one-dimensional arrays not consecutive on memory.

In contrast, in C, two dimensional array in fact is one-dimensional array with size is total_row * total_column. Because Go language uses many concepts from C.

So my question is: does two dimensional array's memory representation in Go look like C or Java?

like image 750
Trần Kim Dự Avatar asked Sep 18 '16 18:09

Trần Kim Dự


People also ask

How is a two dimensional array represented?

Often data come naturally in the form of a table, e.g., spreadsheet, which need a two-dimensional array. Two-dimensional (2D) arrays are indexed by two subscripts, one for the row and one for the column. Each element in the 2D array must by the same type, either a primitive type or object type.

How is a 2 dimensional array stored in memory?

A 2D array is stored in the computer's memory one row following another. The address of the first byte of memory is considered as the memory location of the entire 2D array.

What is memory representation of array?

Memory allocation of an arrayThe name of the array represents the base address or the address of the first element in the main memory. Each element of the array is represented by proper indexing.

How 2D arrays are stored in memory explain with example?

The data items in a multidimensional array are stored in the form of rows and columns. Also, the memory allocated for the multidimensional array is contiguous. So the elements in multidimensional arrays can be stored in linear storage using two methods i.e., row-major order or column-major order.


1 Answers

In Go, slices are often mistaken for arrays, so I answer regarding both.

Arrays

Quoting from the spec: Array types:

Array types are always one-dimensional but may be composed to form multi-dimensional types.

There you have your answer plain and clear. But the answer is not just that as arrays are values in Go, they are not descriptors (headers) like slices.

See this simple example:

x := [5][5]byte{}
fmt.Println(&x[0][3])
fmt.Println(&x[0][4])
fmt.Println(&x[1][0])

Output (try it on the Go Playground):

0x10432203
0x10432204
0x10432205

As you can see, the memory allocated and used for the array is contiguous: the second row starts at a memory address that is the subsequent to the address of the last element of the first row.

Checking size of arrays:

fmt.Println(unsafe.Sizeof([4][6]int{})) // 96
fmt.Println(unsafe.Sizeof([6][4]int{})) // 96

It doesn't matter if you switch rows and columns, its size is the same.

Slices

The same applies in case of slices: a multidimensional slice is a slice of slices. Spec: Slice types:

A slice is a descriptor for a contiguous segment of an underlying array and provides access to a numbered sequence of elements from that array.
...
Like arrays, slices are always one-dimensional but may be composed to construct higher-dimensional objects.

Slices are descriptors, a slice header contains a pointer to an element of an underlying (backing) array, a length and a capacity. So the number of total slices matters in terms of memory usage.

See this example:

x := make([][]byte, 2)
for i := range x {
    x[i] = make([]byte, 1000)
}
fmt.Println(len(x), len(x)*len(x[0]))

y := make([][]byte, 1000)
for i := range y {
    y[i] = make([]byte, 2)
}
fmt.Println(len(y), len(y)*len(y[0]))

Output (try it on the Go Playground):

2 2000
1000 2000

Both x and y multidimensional slices have 2000 elements total (2000 bytes), but x stores 2 slices only, each having 1000 elements, while y stores 1000 slices, each having 2 elements.

This means x requires 2 slice headers while y requires 1000 slice headers (for the elements, +1 for x and y themselves)!

A slice header is represented by reflect.SliceHeader:

type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

The size of a slice header on 32-bit architectures is 12 bytes, on 64 bit architectures its 24 bytes. So in case of 32-bit arch elements of x require 2,000 bytes plus 2x12 bytes in memory which is 2,024 bytes, while elements of y require 2,000 bytes plus 1,000*12 which is 14,000 bytes.

Also note that elements of a multidimensional slice may contain slices with different lengths:

With arrays of arrays, the inner arrays are, by construction, always the same length; however with slices of slices (or arrays of slices), the inner lengths may vary dynamically. Moreover, the inner slices must be initialized individually.

Like in this example:

x := make([][]byte, 2)
x[0] = []byte{1, 2}
x[1] = []byte{1, 2, 3, 4}
fmt.Println(x[0])
fmt.Println(x[1])

Output (try it on the Go Playground):

[1 2]
[1 2 3 4]

If you haven't read, recommended: The Go Blog: Arrays, slices (and strings): The mechanics of 'append'

like image 83
icza Avatar answered Nov 16 '22 01:11

icza