###### 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

```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/