---
# System prepended metadata

title: malloc在dynamic 2d array
tags: [cpp]

---

###### tags: `cpp`

# malloc在dynamic 2d array

dynamic產生2d array，為什麼不能使用memset來設定初始值

```cpp
int N = 3, M=5; // row, col
int **table = (int **)malloc(sizeof(int *) * N);

memset(table, 0, N * M * sizeof(int));
```
:::    danger
**segmentation fault**
:::


##  fixed array

先看一般的固定陣列
```cpp
int arr[3][5];
memset(arr, 0, 3 * 5 * sizeof(int));

printf("arr [ptr]: value\n");
for (int i = 0; i < N; i++) {
    for (int j = 0; j < M; j++)
        printf("[%d]: %d\t", &arr[i][j], arr[i][j]);
    printf("\n");
}
```

```
output:
arr [ptr]: value
[6421920]: 0    [6421924]: 0    [6421928]: 0    [6421932]: 0    [6421936]: 0
[6421940]: 0    [6421944]: 0    [6421948]: 0    [6421952]: 0    [6421956]: 0
[6421960]: 0    [6421964]: 0    [6421968]: 0    [6421972]: 0    [6421976]: 0
```
arr是在程式執行時就被配置在heap/stack記憶體中，所以可以看到記憶體空間是連續的，每4Byte`(int)`為一格

而memset的作用則是為一段連續空間賦值，所以能讓`fixed array`透過`memset`的方式填0


## 回到dynamic

`malloc`作用是請求一段連續的空間，並回傳ptr位置，但並不保證每次malloc都會是接續上次的位置，詳細看附圖與code

![img](https://i.imgur.com/wOT5Lcd.png)

```cpp
int N = 3, M = 5;
int **table = (int **)malloc(sizeof(int *) * N);
for (int i = 0; i < N; i++) table[i] = (int *)malloc(sizeof(int) * M);

for (int i = 0; i < N; i++)
        for (int j = 0; j < M; j++) table[i][j] = 0;

printf("table [ptr]: value\n");
for (int i = 0; i < N; i++) {
    for (int j = 0; j < M; j++)
        printf("[%d]: %d\t", &table[i][j], table[i][j]);
    printf("\n");
}
```

```
output:
table [ptr]: value
[11081184]: 0   [11081188]: 0   [11081192]: 0   [11081196]: 0   [11081200]: 0
[11081264]: 0   [11081268]: 0   [11081272]: 0   [11081276]: 0   [11081280]: 0
[11081344]: 0   [11081348]: 0   [11081352]: 0   [11081356]: 0   [11081360]: 0
```

可以看到`table[0][4]`最後一個元素的位置是[11081200]，但是下一個元素`table[1][0]`元素卻跳到[11081264]

:::    danger
在這種非連續配置的空間，使用memset就有可能不小心覆蓋到table[i]的pointer，導致
**segmentation fault**
:::

> 我認為這error是這樣跳出的，但沒有很確定，不過方向應該是對的

像是這段code，嘗試存取非法空間，也會導致一樣的問題
```cpp
int *qwe = (int *)10;
printf("%d\n", *qwe);
// Exception has occurred. Segmentation fault
```



## 所以該如何配置dynamic 2d array

最普通的方法
```cpp
int N = 3, M = 5;
int **table = (int **)malloc(sizeof(int *) * N);
for (int i = 0; i < N; i++) table[i] = (int *)malloc(sizeof(int) * M);

for (int i = 0; i < N; i++)
        for (int j = 0; j < M; j++) table[i][j] = 0;
```
透過[calloc][calloc]來分配，會在分配時值就初始為0
```cpp
int N = 3, M = 5;
int **table = (int **)malloc(sizeof(int *) * N);
for (int i = 0; i < N; i++) table[i] = (int *)calloc(M, sizeof(int));
```
如果要用`memset`的話，就是要分別對每一個table[i]指標做`memset`
```cpp
int N = 3, M = 5;
int **table = (int **)malloc(sizeof(int *) * N);
for (int i = 0; i < N; i++) table[i] = (int *)malloc(sizeof(int) * N);

for (int i = 0; i < N; i++) memset(table[i], 0, M * sizeof(int));
```

## 為甚麼memset對int賦值時只能0或-1

因為[memset][memset]，是以char(1byte)為單位，一個一個byte去賦值

```cppp
void * memset ( void * ptr, int value, size_t num );
```

> Value to be set. The value is passed as an int, but the function fills the block of memory using the unsigned char conversion of this value.


如果想賦值為10，可能會想這樣寫，但結果並不是這樣
```cpp
int test[5];
memset(test, 10, 5 * sizeof(int));
for (int i = 0; i < 5; i++) {
    printf("%d\n", test[i]);
}
```
```
output:
168430090
168430090
168430090
168430090
168430090
```
## 為什麼會這樣?

前面提到是以byte為單位賦值，而int為32bit(4byte)，賦值時其實是這樣的
```
dec:10 = bin:1010
00001010 00001010 00001010 00001010
```
這串二進制轉成10進制，10 << 24 | 10 << 16 | 10 << 8 | 10，就是**168430090**

所以想把動態int陣列初始化為任意number的話，只能用迴圈

畢竟memset原本的用處就是拿來產生n個char，所以這func才會在string.h中

## 補充:

[Getting value from a dynamic allocated 2d array by pointers](https://stackoverflow.com/questions/8122320/getting-value-from-a-dynamic-allocated-2d-array-by-pointers)

[Is the memory allocation done by malloc always contiguous?](https://stackoverflow.com/questions/66739598/is-the-memory-allocation-done-by-malloc-always-contiguous)

[Does malloc() allocate a contiguous block of memory?](https://stackoverflow.com/questions/625270/does-malloc-allocate-a-contiguous-block-of-memory)

[calloc]: https://www.cplusplus.com/reference/cstdlib/calloc/

[memset]: https://www.cplusplus.com/reference/cstring/memset/