C言語のポインタについて（1章〜2章）

# はじめに
C言語のポインタについて理解を深めるため、この本を読み備忘録としてまとめる
[C言語ポインタ完全制覇](https://www.amazon.co.jp/C%E8%A8%80%E8%AA%9E%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF%E5%AE%8C%E5%85%A8%E5%88%B6%E8%A6%87-%E6%A8%99%E6%BA%96%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%BC%E3%82%BA%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA-%E5%89%8D%E6%A9%8B-%E5%92%8C%E5%BC%A5/dp/4774111422/ref=pd_sbs_14_1/356-1543581-5839563?_encoding=UTF8&pd_rd_i=4774111422&pd_rd_r=99ef5424-127c-4ce2-9ee4-a653746dde39&pd_rd_w=t3Lij&pd_rd_wg=gz6EY&pf_rd_p=1585d594-d9d0-474b-8a4e-69eca1566911&pf_rd_r=2F0Q3T3B4ZM8G0F18W1B&psc=1&refRID=2F0Q3T3B4ZM8G0F18W1B)

結論から言えば、この本は間違いなく良書と言える。
私は、ポインタの使い方を意味が分からず記憶していたが、
この本で何故そうなるのかという点がわかり、大変感謝している。

# 1章
## C言語について
・もともとUNIX系のOS開発用の言語

## ポインタについて
### 「ポインタ型」というのが存在する
・つまり、int型の変数や値があるように、
　ポインタ型の変数や値も存在する

### 変数のアドレスの確認
・変数に「&」を適用すると変数のアドレスを表す
・変数に「*」を適用するとポインタ（アドレス）の指す先の値を表す

```c
    int hoge = 5;
    int piyo = 10;
    int *pointer = &hoge;

    printf("&hoge..%p\n", &hoge);
    printf("&piyo..%p\n", &piyo);
    printf("pointer..%p\n", pointer);
```
・以下のような図で考えると分かりやすい

| アドレス | 変数名 | 値 |
|:-------|:-----|:----|
| 0x7ffee27a4b38| pointer | 0x7ffee27a4b48|
| 〜|||
| 0x7ffee27a4b44| piyo | 20| 
| 〜|||
| 0x7ffee27a4b48| hoge | 10|

## 配列
・式の中では、配列名は「その配列の先頭要素へのポインタ」に読み替えられる
・以下の値はすべて同じである。
　配列hogeの先頭配列のアドレスの&hoge[0]
　配列hogeの先頭を表す配列名hoge
　変数名hogeのアドレスを表す&hoge

### p[i] は *(p + i) と同義である

```c
    int hoge[5] = {1,2,3,4,5};
    int *pointer = hoge;

    printf("hoge[0]...%p\n", &hoge[0]);
    printf("hoge...%p\n", &hoge);
    printf("hoge...%p\n", hoge);
    printf("hoge[1]...%p\n", &hoge[1]);
    printf("hoge[2]...%p\n", hoge + 2);
```

## void型のポインタ変数はどこまで取り出せば良いか分からない
・アドレスの代入時は開始場所の代入なので問題ないが、
　実際にアドレスから取り出す場合は、メモリから取り出す範囲を指定するため、
　型の定義をする必要がある

```c
    int hoge = 5;
    void *pointer;

    pointer = &hoge;
//  printf("%d\n", *pointer);        //？？型のポインタ　→　取り出せない
    printf("%d\n", *(int *)pointer); //int型のポインタを指す変数
```


## ポインタ変数のバイト数の確認
```c
    int hoge = 5;
    int *pointer = &hoge;

    printf("pointer: %ld", sizeof(pointer));
```

## ポインタ変数の「+n」
・ポインタにn加算すると、ポインタの指す型のサイズ×n進む
・int型は基本的に4バイト(32bit)である

## NULLポインタ
・何も指していないことを保証する
・変数を宣言しただけでは、値は不定となるため、
　初期化時に宣言すること

```c
int *pointer;  
int *pointer2 = NULL;
```

## 仮引数では int func (int *a) と int func (int a[]) は同じ
・次の書き方は同じ意味を指す

```c
int get_word(char *buf, int buf_size, FILE *p)
int get_word(char buf[], int buf_size, FILE fp[])
```

# 2章
## 仮想アドレス
・同じソースコードを別窓で実行すると、hogeのアドレスが同じだが、
　値はそれぞれで異なる。

・アプリケーション実行時のアドレスは、物理的な領域のアドレスではない。
　アプリケーションはプロセスごとに独立している

```c
    int hoge;
    char buf[256];

    printf("&hoge....%p\n", &hoge);
    fgets(buf, sizeof(int), stdin);
    sscanf(buf, "%d", &hoge);

    for(;;){
        printf("hoge..%d\n", hoge);
        getchar();
        hoge++;
    }

    return 0;
```

・1つめの窓

```
&hoge..0x62cc4c
9
hoge..9 //Enter

hoge..10 //Enter

hoge..11
```
・2つめの窓

```
&hoge..0x62cc4c
5
hoge..5 //Enter

hoge..6 //Enter

hoge..7
```

## Cの変数で記憶領域の寿命は3種類ある
### 1.静的変数（グローバル変数、ファイル内でstatic指定した変数）  
　→　プログラムの開始から終了まで

### 2.動的変数（関数内でstatic指定をしていない変数）
　→　関数のブロックに入った時からブロックを抜けるまで

### 3.malloc()で確保した領域
　→　malloc()関数のコールからfree()関数をコールするまで

## 関数（本体）と文字列リテラルは書き込み禁止領域
・関数はそもそも書き換えることはない
・文字列は「charの配列」となり先頭文字へのポインタに読み替られる。

```c
int main(void){
    char *a = "abc";
    printf("%s\n", a);
    a[0] = 'd';
    printf("%s\n", a);
}
```

・この場合、1回目の文字列表示後
　Segmentation fault (コアダンプ)となり、正しく表示されない

### 関数にもアドレスがある
・関数は式の中では「関数へのポインタに」読み変えられる

```c
    void func1(void){

    }

    void func2(void){

    }

    int main(void){
        printf("func1...%p\n", &func1);
        printf("func2...%p\n", &func2);
    }

```

・メモリに格納される内容の順番

| アドレス | 変数名 |
|:-------|:-----|
| 0x401180| func1 |
| 0x401186| func2 |

### 関数へのポインタの書き方
・使い方の例

```c
int func (int d){
}

int main(void){
 int (*func_p)(int);
 func_p = func;
 func(2);
}
```
・使い方は、関数への配列のポインタなど

```c
int (*func_table[])(double) = {
 func0,
 func1,
 func2,
};

func_table[i](1); 
```
## 静的変数は仮想アドレス上で、固有の領域を持つ
・関数やグローバル変数は名前が同じであれば、ソースファイルをまたいでも同じものっとして扱われる（「リンカ」）

## 自動変数は領域を使いまわしするため、スタックに積む
1. mainで使用される自動変数を宣言順に積む
2. mainから呼び出される関数（関数x）の引数を後ろから順に積む
3. 関数xのリターン用の復帰情報（アドレスなど）を積む
4. 関数xのアドレスにジャンプする
5. 関数xで使用される自動変数を宣言順に積む
6. 関数xの実行中計算途中の値を積む
7. 関数xの終了時、ローカル変数の値を開放する
8. mainで関数xの引数をスタックから除去する

## mallocはヒープ領域に積む
・mallocは指定されたメモリサイズを確保し、先頭へのポインタを返す
・動的にメモリを割り当て、任意の順序で解放できる記憶領域を「ヒープ領域」という

### 1.構造体（メンバを含め）を動的に確保できる
・構造体の作成する個数
・構造体のメンバの要素の長さ

```c
typedef struct BookData_tag{
    char *title;
    int price;
    char isbn[32];
    struct BookData_tag *next;
}BookData;

int main(void){
    BookData *book_data_p;
    book_data_p->title = malloc(sizeof(char) * 32);
    
    strcpy(book_data_p->title, "aaa"); //用意したアドレスに文字を代入
    //book_data_p->title = "aaa"; 文字列aaaを確保してそのアドレスを入れている
    // そのため、確保したメモリは永久に参照されない（メモリリーク）
    book_data_p->price = 32;
    book_data_p->isbn[0] = 'a';

    printf("%s\n",book_data_p->title);    
    printf("%d\n",book_data_p->price);    
}
```

### 2.mallocの仕組みはOSから一括して大きなメモリを取得して分ける
・freeした領域は、すぐにメモリを解放されるわけではないが、参照してはいけない
・malloc,freeを繰り返すと、フラグメンテーション（断片化）する。
・対策はメモリコンパクション

### 3.calloc,cfreeは使わないほうが良い
・callocで確保した領域はすべてのビットがゼロに初期化されるが、浮動小数点ゼロ、
　または NULL ポインタ定数の表現と同じであるとは限らないため、再初期化が必要なことがある。
・cfreeに関しては、通常のfree関数と同じ仕様のため、私は特別使用しようとおもいませんでした。

## アラインメント
・型のサイズの都合上、どうしても埋め込み必要な領域
・下記の構造体は計21バイトだが、charの箇所に3バイト分アラインメント
　があり、計24バイトになっている。

```c
typedef struct{
    int int1;       //4バイト
    double double1; //8バイト
    char char1;     //1バイト
    double double2; //8バイト 
} Hoge;
```

# あと書き
1.2章の読破時間・・・6h