#c++の注意点をまとめておく
学んでいる中で、気を付けなければいけないと思った点をまとめておく。
##cin.get()
の振る舞い
int a = cin.get();
cout << a << endl;
で、4
を入力すると
52
と出力された。おそらく、ASCII文字として入力されているはず。一方、
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)より)
###※追記
Windows 10環境では<ctrl>z
でEOF
の-1
が出力されました。
なお、<crtl>d
だとEOT
の4
が出力されました。
##switch
構文
switch
構文は、ほかの制御構造と違い、case
節の中に複数のアクションを書いても、それらを{}
でくくる必要はない。
また、switch
構造の複数の条件に対して同じ命令をしたい場合は次のように表記できる。
int input = cin.get();
switch (input) {
case 'A': case 'a':
cout << "Input is A or a." << endl;
break;
}
##引数を取らない関数の[C]と[C++]の違い
C++で引数を取らない関数の宣言は二通りある。
void f1();
void f2(void);
しかし、C++における空の関数パラメータリストの意味はCの場合とは全く異なる。
- 空の関数パラメータの意味
- Cの場合
- 引数チェックが何も行われないことを意味する(つまり、関数呼び出しのときにどんな引数でも渡すことができる)
- C++の場合
- その関数が引数を取らないことを意味する(つまり、引数を渡すとコンパイルエラーになる)
- Cの場合
##::
scope resolution operator(単項スコープ特定演算子)
単項スコープ特定演算子::
の挙動を確認しておく。
#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()
内のローカル変数にはアクセスできない!!!
###呼び出し元関数内のローカル変数を直接変更するには関数パラメータの型の後に&
(アンパサンド)をつけて参照渡しにする
呼び出し元のローカル変数を直接変更する方法は&
を用いて次のようにすればいい。
#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
での初期化がよく使われます。
int y = 5;
int *xPtr, *yPtr;
xPtr = 0;
yPtr = &y;
また、*
と&
は対照的な関係になっているので、
#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;
}
a = 7
*aPtr = 7
&a = 0x61fe1c
aPtr = 0x61fe1c
&*aPtr = 0x61fe1c
*&aPtr = 0x61fe1c
&aPtr = 0x61fe10
###整数への定数ポインタの初期化
整数への定数ポインタはint * const
型で定義する。
初期化は整数にアドレスを意味する&
をつけて、ポインタとして渡す。
int x;
int * const ptr = &x;
整数への定数ポインタはポインタptr
の値は変更できないが、ポインタ先の整数*ptr
は変更可能。
###整数型定数への定数ポインタの初期化
整数型定数への定数ポインタはconst int * const
型で定義する。
初期化は定数変数に&
をつけてアドレス(ポインタ)で渡す。
int x = 5;
const int * const ptr = &x;
整数型定数への定数ポインタはポインタptr
もポインタ先の整数*ptr
も変更できない。