こんにちは､ そしてお帰りなさい｡
この講義では､ cでプログラミングをしているときによくある間違いについてお話したいと思います｡
中には､ これまでのチャレンジでおなじみで､ すでに実際に遭遇したことのあるエラーもあるかもしれませんが､
これらは最も多いタイプのエラーです｡
1つ目は､ とてもとてもわかりやすい｡ セミコロンが抜けています｡
cのすべての文はセミコロンで終わることを忘れないでください｡
それがないと､ コンパイラが文句を言うんです｡
だから､ セミコロンの位置を間違えるか､ 完全に欠落させるかは､
本当によくあるミスなんだ｡ この場合､ セミコロンの位置を間違えているのです｡
if文があります｡ if文の最後にセミコロンをつけています｡
そして､ これによって､ 実はプログラムの動作が全く違ってくるのです｡
これで実際にコンパイルされます｡
セミコロンを見逃して､ それさえも入っていないときは､ コンパイルされません｡
しかし､ この場合､ if文のセミコロンが置かれているため､
jの値は常に0になることになる｡
ですから､ セミコロンはif文の後につけても全く問題ありません｡
実際にはnull文を表しています｡
したがって､ コンパイラによるエラーは発生しませんが､
jが0になることは絶対にないので､ これは問題が発生します｡
そして､ このような間違いは､ ルーピングでもよくあることなのです｡
ループがあり､ forループの最後にセミコロンを置き､
その後にブラケットを付ける場合があります｡ ブラケットを付けるとエラーになるので､
ブラケットを付けない場合が非常に多いです｡
もう一つは､ イコール演算子と等号演算子を混同していることです｡
具体的には､ equals演算子が文字列の比較をしていないことに言及しました｡
だから､
文字列を比較するときにイコールequalを使うと､ それは有効ではない｡ リファレンスを比較するだけです｡
しかし､ 実際に変数に値を代入するつもりで､ 代わりにイコールを使うと､
コンパイラが困ります｡
もし､ if文の中で2つの項目､ 例えば2つの整数を比較しようとして､
代わりに代入演算子を使った場合､ 実際にはコンパイラーエラーは発生しませんが､
この式は常にtrueと評価されることになります｡
ですから､ イコールを使う場合と使わない場合､ これは通常､
if while do文の中で､ ブール式の内側で作られます｡
そしてこれは､ 何かを実行するのとは対照的に､
何かに割り当てるという効果を持つことを除けば､ 有効です｡
つまり､ この例では､ if
a equals 2とあれば､ aに2が代入されていることになります｡
常にtrueに設定されるのは､ アサインメントを実行しているときに失敗することがないからです｡
それでprintfは常に実行されることになる｡
ここであなたが本当に言いたかったことは､ aがequals toに等しい場合ということです｡
ですから､ イコールとイコールの使い分けはよくあることで､ コンパイラーエラーが発生することはないのです｡
イコールの使い方を間違えると､
同様に予期せぬ動作をする可能性がありますが､
間違って代入に使っているとコンパイラエラーになります｡
しかし､ イコールの代わりにイコールでこれには注意が必要です｡
プロトタイプの宣言を省略する｡
関数を使う前に､ 必ずファイルの先頭で宣言することが本当に重要であると述べました｡
しかし､ これは必ずしもそうではなく､ 非常によくある間違いです｡
そして､ 通常､ コンパイラで暗黙の宣言エラーが発生することになります｡
この例では､ プログラムの中で平方根を呼び出している場所よりも後に定義していたり､
別のファイルで定義していて､ それを明示的に宣言していない場合､
いくつかの警告が表示されることになります｡
コンパイラは､ この関数がintを返すと仮定しています｡
このプロトタイプ宣言は､ 明示的に､ あるいは暗黙のうちに正しいヘッダーファイルをプログラムに含めることによって､
呼び出すすべての関数の先頭に含めることが常に最も安全です｡
しかし､ このプロトタイプ宣言がない場合､ エラーが発生する可能性があります｡
プログラムで使用されるcプログラミングライブラリ関数の定義を含むヘッダーファイルのインクルードを失敗した｡
この場合､ あるコードを再利用したいわけです｡ 例えば､ printf関数で出力を表示したいが､
標準のlibヘッダーファイルが含まれていない場合｡
それは間違いです｡ そして､ それは通常､ コンパイラが教えてくれることでしょう｡
その機能には､ リンクの問題があります｡
ですから､ この場合､ 二重の答えは平方根の値1に等しいのです｡
このプログラムに数学が含まれていない場合｡ ヘッダファイルでは､
平方根が未定義であるとのエラーが発生します｡
オブジェクトファイルのリンクを試しに行きます｡ 数学はないでしょう｡ o.
そして､ 「おい､ 平方根を呼び出しているが､ そのための実装はない」と言われるでしょう｡
ですから､ 特に標準ライブラリの関数を呼び出す際には､
必ず正しいヘッダを含めるようにしてください｡
文字列の中の文字定数を混同している｡
つまり､ 一重引用符の中にtextと同じaがあれば､ それはtextに割り当てられた1文字ということになります｡
textという変数があり､ 二重引用符で代入すると､
それは文字列へのポインタになります｡
それは1文字では無効です｡
そして､ これは実際に文字列定数や文字配列への代入について話してきました｡
そして､ イコールではダメで､ 実際にスターコピーでやらなければいけないということです｡
この場合､ text equals aと言うと､ ポインタを代入していることになるので､
実はこれも有効ではなく､ このように直接代入したくない場合は､ star text
equals aまたはstar copyを行う必要があります｡
でも､ 要点はわかってもらえたと思います｡
シングルクォートの中のaを使うのと､ ダブルクォートの中の文字を使うのとでは､
文字と文字列とが全く異なる｡
最初のケースでは､ textは通常char変数として宣言されます｡
また､ 2番目のケースでは､ charへの型ポインタであることを宣言する必要があります｡
そして､ そのポインタにポインタ以外の値を代入したい場合は､
ポインタの参照を解除する必要があります｡
これは､ アドレスを代入するのではなくポインタであれば､
文字列を代入することになるので､ 実は意味がないのです｡
配列に間違った境界を使用すると､ 配列の境界外例外が発生します｡
ここでは､ 100サイズの整数配列と､ いくつかの変数Iとsumを宣言して､
一部だけを初期化しています｡
そして､ ループの中で､ Iが1に等しい場合､ Iは100に等しいよりも小さいと言うのです｡
100というサイズは､ 配列の中に100個の要素があることを意味するので､
それは誤りです｡ しかし､ アレイはゼロベースです｡
つまり､ 最初の要素はゼロなのです｡ a配列に代入またはアクセスできる最大インデックスは99です｡
これはイコール以下になりそうです｡
ここでアウトオブバウンズのミスが発生するわけですね｡
このループは100まで行くので､
これは有効な添え字ではありません｡
また､ 1からのスタートなので不正解でしょう｡
もし本当にこの配列の最初の要素が欲しいのであれば､ 0から始めるでしょう｡
また､ 文字列の終端であるヌル文字のために配列の余分な場所を確保するのを忘れるのもよくある問題です｡
文字配列を宣言する際には､ 終端となる単独文字を含むのに十分な大きさが必要です｡
このため､ 配列を初期化する場合は､
作成時にサイズを指定しないことをお勧めします｡
サイズを入れるのは､ 初期化しない場合だけでしょう｡
同じ行で初期化する場合は､ cに任せておけば､ 自動的に正しいサイズが入力され､
ヌル文字ターミネーターも含まれます｡
例えば､ helloという文字列があったとして､ これはメモリロケーションが5つ以上あり､
最後にヌルターミネーターがあるので6つになってしまいます｡
アレイのサイズも忘れてはいけません｡
これはポインタの一般的な問題で､ これまであまり議論されてきませんでしたが､
非常によくあることなので､ 一応触れておきます｡
ポインターでは､ アクセスするとき､ あるいは指示するとき､
ポインターで何かにアクセスしたいときは､
ダッシュの大なり記号を使わなければならない｡
ポインター要素にアクセスするときに使うんだ｡
つまり､ 構造体を指すポインタがあれば､ それにアクセスする方法です｡
構造体があってもポインタでないなら､
ドット演算子を使ってアクセスする｡
このドット演算子やダッシュの使い方が間違っていることが多いのです｡
非ポインタのドット､ ポインタのダッシュはより大きい､ これは我々のより多くの例で明らかになるであろう｡
scanf呼び出しでポインタでない変数の前のアンパサンドを省略する｡
つまり､ scanfの呼び出しは第2引数としてポインタを期待し､ それはアドレスを意味することを忘れないでください｡
データ型としてint型の変数を宣言した場合､ それはポインタではありません｡
そこで､ scanfがint変数にデータを格納できるようにするために､ アンパサンドを渡して､ それがアドレスであることを示す必要があるのです｡
つまり､ 番号の前にアンパサンドを入れず､
第2引数としてfをスキャンするのは不正解です｡
アンパサンドを付けないのは､
文字配列のようにポインタを使用する場合だけです｡
フォーマット文字列とscanfの後に現れるすべての引数はポインタでなければならない｡
初期化される前のポインタ変数を使用すること｡
そこで､ ポインターを作成し､ それに代入しようとする例です｡
そして､ これは正しい割り当てで､ 値を割り当てる場合は参照を解除します｡
しかし､ ここでやっていないのは､ 実際にメモリが割り当てられたポインタを初期化することで､
これはcではできません｡
アスタリスクbeforeのような間接演算子は､
変数をどこかに設定した後でないと適用できない｡
つまり､ どこかを指しているはずなのですが､ 今はNULLで､ メモリを割り当てていないので､
どこも指していないのです｡
そのため､ charポインタは何かを指すように設定されることはなく､ 代入は意味を持ちません｡
これは実際にはセグメンテーションフォールトの原因となる｡
また､ switch文のcaseの末尾にあるbreak文の省略もよくあるミスです｡
ケースの最後にブレークが含まれていない場合は､ 次のケースに実行が継続されます｡
このように､ 案件があれば評価される､ ということですね｡
そして､ もしこのブレークがなければ､ すぐに次のケースに進み､
その次のケースの中のコードを実行することになるのです｡
だから､ case文の中には必ず区切りを入れておきたい｡
他のケースへのフォロースルーをしたいときに､ 全く同じことをされる場合がありますが､
その場合はケースステートメントの中に何も入れないことになります｡
プリプロセッサー定義の最後にセミコロンを挿入する｡
プリプロセッサー定義は､ 数字､ ポンド記号で始まることを記憶しています｡
プリプロセッサーは､
通常､ 最適化のためにコンパイラーの前に実行されます｡
プリプロセッサー定義の正しい構文は､ セミコロンを含めないことです｡
ただし､ c youでは､ すべてのものの後に必ずセミコロンをつける習慣をつけてください｡
しかし､ セミコロンが不要な定数データを定義した場合､ これは誤りであることを覚えておいてください｡
これは､ そのような式が使われていると､
シンタックスエラーになります｡
みたいな だから､ 実際にそれを使って検索してみると､
最後にセミコロンがあっても大丈夫そうなんです｡
しかし､ プリプロセッサが実行されると､ その定義された内容を正確に挿入することになる｡
つまり､ データ999のコロンの末尾にサーブされるわけです｡
これはコンパイラが見て､ 実際にエラーになるもので､ 構文エラーになります｡
どんな文でも閉じ括弧や閉じ引用符を省略すること､
非常によくあります｡ これは括弧にも直接関係していて､
中括弧が始まって中括弧が終わらない､ 括弧も同じことです｡
この場合､
開始の左括弧は2つ､ または3つありますが､ 終了の括弧は2つしかないのです｡
エンディングの右括弧が足りません｡
これは､ コンパイラが発見する構文エラーになります｡
ですから､ 式の各部分を区切るために括弧内のembedを使う場合､ より読みやすいコード行になります｡
括弧を使いたいのですね｡
ただし､ 括弧を始めたら､ 最後に閉じる括弧が必要であり､
中括弧も同様である｡
中括弧を始めたら､ 終わりの中括弧が必要です｡
つまり､ 多すぎても少なすぎてもコンパイラに文句を言われるわけで､
これは非常によくあることです｡
つまり､ この2行目には､ このprint文と同様に閉じの引用符がありません｡
エンディングの見積もりはしていない｡
コンパイラから文句を言われる｡
どちらもコンパイルエラーが発生します｡
しかし､ コンパイラはどこでエラーが発生したのか分からないため､
非常に誤解を招きやすい場合があります｡ 後続の行でエラーが発生した可能性があると判断しているのです｡
だから､ エラーを教えてくれるというセリフは､ 誤解を招くかもしれない｡
つまり､ コンパイラが後続の行で括弧を使うか引用符を使うかによって､
実際にその式を完成させることができるのです｡
そのため､ エラーが別の行に移動してしまうのです｡
そして､ そこがエラーだと文句を言ってくるのです｡ しかし､ 実際のエラーは､
あなたが配置しようとした場所よりも上の方にあります｡
これらは､ 多くのC言語プログラマーが犯している共通の間違いです｡
修理も簡単です｡ そして､ それらを理解し､ これを勉強すれば､
作ってはいけないということがわかるはずです｡
初心者のうちは作ってもいいのですが､
どんどんコーディングして練習を積んでいくと､ あれ､ カッコを忘れた､
イコールとイコールを正しく使っていない､ ポインタの使い方が間違っている､
メモリを割り当てていない､ といったことが分かってくるはずです｡
これらはすべて､ 自然に身につくものです｡ ありがとうございます｡