[C++] 注意点 まとめ (初心者)

#c++の注意点をまとめておく

学んでいる中で、気を付けなければいけないと思った点をまとめておく。

##`cin.get()`の振る舞い

```cpp
int a = cin.get();
cout << a << endl;
```

で、`4`を入力すると

```
52
```

と出力された。おそらく、ASCII文字として入力されているはず。一方、

```cpp
int a;
cin >> a;
cout << a << endl;
```

で、`4`を入力すると、

```
4
```

と出力される。

あと、これはシステム依存らしいが、`EOF`と入力しても初めの`E`しか読み込まず、

```
69
```

と出力される。`get()`メソッドが`char`型で`unsigned int`型で読み込んでいるのか、`EOF`を一文字と認識していないので`EOF`のASCIIコードの`-1`が出力されない。

他にも、`unsigned int`型に収まる`EOT`や`CAN`なども頭文字の`E`と`C`に対するASCIIコードが出力されてしまう。

当然、`-1`を入力しても`-`に対するASCIIコードが出力される。

また、ANSI規格によると`EOF`は負の整数値となっていて必ずしも`-1`であるとは限らないらしい。(1998年出版の本[C++プログラミング〈Vol.1〉 (Computer Science Textbook)](https://www.amazon.co.jp/C-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%80%88Vol-1%E3%80%89-Computer-Science-Textbook/dp/489471115X)より)

###__※追記__

Windows 10環境では`<ctrl>z`で`EOF`の`-1`が出力されました。

なお、`<crtl>d`だと`EOT`の`4`が出力されました。



##`switch`構文

`switch`構文は、ほかの制御構造と違い、`case`節の中に複数のアクションを書いても、それらを`{}`でくくる必要はない。

また、`switch`構造の複数の条件に対して同じ命令をしたい場合は次のように表記できる。


```cpp
int input = cin.get();

switch (input) {
    case 'A': case 'a':
        cout << "Input is A or a." << endl;
        break;
}
```

##引数を取らない関数の[C]と[C++]の違い

C++で引数を取らない関数の宣言は二通りある。

```cpp
void f1();
void f2(void);
```

しかし、C++における空の関数パラメータリストの意味はCの場合とは全く異なる。

- 空の関数パラメータの意味
    - Cの場合
        - 引数チェックが何も行われないことを意味する(つまり、関数呼び出しのときにどんな引数でも渡すことができる)
    - C++の場合
        - その関数が引数を取らないことを意味する(つまり、引数を渡すとコンパイルエラーになる)

##`::` scope resolution operator(単項スコープ特定演算子)

単項スコープ特定演算子`::`の挙動を確認しておく。

```cpp

#include <bits/stdc++.h>
using namespace std;

void f(int a);

int n = 10; //global number n initialezed 10

int main() {
   
    f(0);

    cout << "incremented global n in main() = " << n << endl;

    return 0;
}

void f(int a) {
    int n=1; // initialize local number n

    cout << "local n in f() = " << n << endl;

    cout << "scope resolution operator ::n = " << ::n << endl;

    ::n++;

    cout << "incremented scope resolution operator ::n in f() = " << ::n << endl;

    return;
}
```

結果は次のようになった。

```
local n in f() = 1
scope resolution operator ::n = 10
incremented scope resolution operator ::n in f() = 11
incremented global n in main() = 11
```

単項スコープ特定演算子`::`を使えば、ローカル関数内で同じ変数名を定義してもグローバル変数にアクセスできる。

グローバル変数と同じ名前の変数がなければ直接アクセスできる。

__※注意：ただし、ローカル関数`f()`から`main()`内のローカル変数にはアクセスできない！！！__

###呼び出し元関数内のローカル変数を直接変更するには関数パラメータの型の後に`&`(アンパサンド)をつけて参照渡しにする

呼び出し元のローカル変数を直接変更する方法は`&`を用いて次のようにすればいい。

```cpp
#include <bits/stdc++.h>
using namespace std;

void f(int &a);

int main() {
    int n = 10;

    cout << "local n = " << n << endl;

    f(n);

    cout << "new n = " << n << endl;
    
    return 0;
}

void f(int &a) {
    a++;

    cout << "incremented a = " << a << endl;

    return;
}
```

結果は次のようになり、`main()`内のローカル変数`n`が更新されているのがわかる。

```
local n = 10
incremented a = 11
new n = 11
```

##`*`pointer(ポインタ)

C++では`NULL`ポインタは`0`と等価である。

`0`は単なる整数値だが、ポインタ型にキャストしなくても直接代入することができる。

C++では`0`での初期化がよく使われます。

```C++
int y = 5;
int *xPtr, *yPtr;

xPtr = 0;
yPtr = &y;
```

また、`*`と`&`は対照的な関係になっているので、

```c++
#include <bits/stdc++.h>
using namespace std;

int main() {
    int a;
    int *aPtr;

    a = 7;
    aPtr = &a;

    cout << "a = " << a << endl;
    cout << "*aPtr = " << *aPtr << endl;
    cout << endl;
    cout << "&a = " << &a << endl;
    cout << "aPtr = " << aPtr << endl;
    cout << endl;
    cout << "&*aPtr = " << &*aPtr << endl;
    cout << "*&aPtr = " << *&aPtr << endl;
    cout << endl;
    cout << "&aPtr = " << &aPtr << endl;

    return 0;
}
```

```console
a = 7
*aPtr = 7

&a = 0x61fe1c
aPtr = 0x61fe1c

&*aPtr = 0x61fe1c
*&aPtr = 0x61fe1c

&aPtr = 0x61fe10
```

###整数への定数ポインタの初期化

整数への定数ポインタは`int * const`型で定義する。

初期化は整数にアドレスを意味する`&`をつけて、ポインタとして渡す。

```c++
int x;

int * const ptr = &x;
```

整数への定数ポインタはポインタ`ptr`の値は変更できないが、ポインタ先の整数`*ptr`は変更可能。


###整数型定数への定数ポインタの初期化

整数型定数への定数ポインタは`const int * const`型で定義する。

初期化は定数変数に`&`をつけてアドレス(ポインタ)で渡す。

```cpp
int x = 5;

const int * const ptr = &x;
```

整数型定数への定数ポインタはポインタ`ptr`もポインタ先の整数`*ptr`も変更できない。