[Powered by Google Translate] [CS50ライブラリ]
[ネイトHardison] [ハーバード大学]
[これはCS50です。 CS50.TV]
CS50ライブラリは、我々は、アプライアンスにインストールされている便利なツールです
あなたがプログラムを書くことを簡単にするために、その入力を求めるユーザ。
このビデオでは、カーテンを引くだろうし、まさにCS50ライブラリにあるものを見てみましょう。
>> Cライブラリでのビデオの中で、我々はあなたが＃ヘッダファイルをインクルードする方法について話
ソースコード内のライブラリの、
そして、あなたはリンクフェーズ中にバイナリライブラリファイルとリンク
コンパイルプロセスの。
ヘッダファイルは、ライブラリのインターフェイスを指定します。
すなわち、彼らは詳細は、使用するためのライブラリが利用できる持っているすべてのリソースを、ある
関数宣言、定数、およびデータ型と同じように。
バイナリライブラリファイルは、ライブラリの実装が含まれています
これらはライブラリのヘッダファイルとライブラリの。cソースコードファイルからコンパイルされます。
>> バイナリライブラリファイルは、そのファイルがバイナリで、まあ、だから見て非常に興味深いものではありません。
それでは、代わりにライブラリ用のヘッダファイルを見てみましょう。
この場合、cs50.h.呼ばただ一つのヘッダファイルがあり
我々は、ユーザーにそれをインストールしたディレクトリを含める
他のシステムライブラリ 'ヘッダファイルと一緒に。
>> あなたが気づく最初の事の一つは、cs50.h＃は他のライブラリのヘッダファイルが含まれていることである -
フロート、限界、標準ブール値、お​​よび標準lib。
繰り返しになりますが、車輪の再発明をしないの原則に従って、
我々は他の私たちのために提供されているツールを使用してCS0ライブラリを構築しました。
>> あなたがライブラリに表示されます次のことは、我々はと呼ばれる新しいタイプ定義することである "という文字列を"。
この行は、実際には単なるchar *型のエイリアスを作成し、
ので、それは魔法のように属性を持つ新しい文字列型を鼓吹していません
一般的に、他の言語で文字列オブジェクトに関連付けられている
長さなど。
我々はこれをやった理由は、血みどろの詳細から新しいプログラマを保護することです
ポインタの彼らは準備が整うまで。
>> ヘッダファイルの次の部分は、関数の宣言です
CS50ライブラリはドキュメントとともに提供している。
ここにコメントの詳細レベルに注意してください。
人々はこれらの関数を使用する方法を知っているので、これは超重要です。
私たちは、順番に、関数がユーザとリターン文字、倍精度、浮動小数点数、整数を求めるように、宣言
長いlong、および文字列、私たち自身の文字列型を使用しています。
情報隠蔽の原則に従い、
私たちは別のCの実装ファイルに我々の定義を入れている - cs50.c- -
ユーザーソースディレクトリにある。
あなたがそれを見てとることができるように、我々は、そのファイルを提供してきました
そこから学ぶこと、そして必要に応じて別々のマシン上でそれを再コンパイルし、
我々はそれがこのクラスのアプライアンス上で動作するように良いことだと思うのに。
とにかく、今それを見てみましょう。
>> 機能GetCharなどgetDoubleは、getFloatは、場合、getInt、およびGetLongLong
すべてのGetString関数の上に構築されています。
それは、彼らはすべて基本的に同じパターンに従っていることが判明した。
彼らは、入力の1行の入力をユーザーに求めるwhileループを使用しています。
彼らは、空行がユーザ入力する場合は、特別な値を返します。
彼らは、適切な型として、ユーザーの入力を解析しよう
char型、倍精度、浮動小数点などのそれである
入力が正常に解析された場合、その後、彼らはどちらかの結果を返す
またはそれらがユーザーを求めるプロンプトを表示。
>> 高レベルでは、本当に難しいものはここにはありません。
あなたは過去にも同様に構造化されたコードを自分で書かれている場合があります。
おそらく最も不可解に見える部分は、ユーザの入力を解析sscanf関数呼び出しです。
sscanfは入力フォーマット変換ファミリの一部です。
、これは、標準的なio.hで生きており、その仕事は、C言語の文字列を解析することです
特定のフォーマットに従って、変数に解析結果を格納
発信者によって提供されます。
入力フォーマット変換機能は非常に有用で、広く使われている機能があるので
最初は超直感的でないこと、
我々は、sscanfがどのように動作するかをみることにします。
>> 文字へのポインタ - sscanf関数の最初の引数はchar *である。
正しく動作させる機能のために、
その文字は、C言語の文字列の最初の文字でなければなりません
ヌル\ 0文字で終了しました。
これは、解析する文字列です
sscanf関数の二番目の引数は書式文字列であり、
一般的に、文字列定数として渡さ
そしてあなたは、printfを使用するときに前にこのような文字列を見たことはあるかもしれない。
フォーマット文字列内のパーセント記号は、変換指定子を示します。
文字はすぐに、パーセント記号に続く
我々はに変換するのはsscanfたいC言語の型を示します。
場合、getIntでは、％dと％cが存在することを参照してください。
％d個 - - とchar - ％cのこれはsscanfが進intに試みることを意味します。
フォーマット文字列内の各変換指定子については、
sscanfは、後でその引数リスト内の対応する引数を期待しています。
その引数が適切に型付けされた場所を指している必要があり
変換の結果を格納するためインチ
>> これを行うための一般的な方法は、sscanf関数呼び出しの前に、スタック上の変数を作成することです
あなたは文字列から解析したい項目ごとに
ポインタを渡す - アンパサンド - そして、アドレス演算子を使用する
これらの変数にはsscanfコールへ。
あなたは場合、getIntで我々が正確にこれを行うことがわかります。
右sscanf関数呼び出しの前に、我々は、スタック上にnと呼ばれるintとcharコールcを宣言し、
そして我々はsscanfコールにそれらへのポインタを渡します。
スタックにこれらの変数を置くことは、割り当てられた領域を使用する上で好ましい
mallocでヒープ上に、あなたはmalloc呼び出しのオーバーヘッドを回避するため
そしてあなたは、メモリリークが発生して心配する必要はありません。
パーセント記号によって前に置かれていない文字は変換を求めるプロンプトは表示されません。
むしろ彼らはただフォーマット仕様に追加。
>> たとえば、場合、getIntのフォーマット文字列ではなく％dのだったら、
sscanfは、intが続く文字を探したい
それはint型に変換しようと試みながら、それは、aと他に何もしないだろう。
これに対する唯一の例外は、空白です。
書式文字列内の空白文字は、空白の任意の金額を一致させる -
まったくさえなし。
コメントは先頭および/または末尾の空白を持つ可能性に言及なぜだから、それだ。
だから、それは私たちのsscanf関数呼び出しのようになり、この時点では、ユーザの入力文字列を解析しよう
可能な先頭の空白をチェックすることによって、
int型の変数nに変換されて格納されるintが続く
空白のいくつかの量が続くと、文字が続く
char型の変数cに格納されている。
>> 戻り値についてはどうですか？
sscanfは、開始から終了までの入力行を解析します
それが終わりに達したときに停止したりする場合、入力中の文字
フォーマット文字と一致しないか、それは変換を行うことができないとき。
それの戻り値は、それが停止する場合、単一のために使用されます。
それは入力文字列の末尾に達したため、それが停止した場合
どんな変換を行う前に、書式文字列の一部を一致に失敗するまで、
その後、特殊な定数EOFが返されます。
それ以外の場合は、成功したコンバージョン数を返します
我々は2つ​​の変換のために求めてきましたので、それは、0,1、または2である可能性があります。
我々の場合では、ユーザは、intとint型のみで入力したことを確認したい。
>> そこで、我々は、sscanfが1を返すようにしたい。理由を参照してください？
sscanfが0を返した場合は、変換は行われませんでした、
したがって、ユーザーは入力の先頭にint型以外のものを入力しました。
sscanfが2を返す場合、そのユーザーは、適切に、入力の開始時にそれを入力した
しかし、彼らはその後、その後、いくつかの非空白文字で入力
％cの変換が成功したからである。
うわー、それは一つの関数呼び出しのために非常に長い説明だ。
とにかく、あなたはsscanfとその兄弟の詳細情報が必要な場合、
manページは、Google、または両方をチェックアウト。
フォーマット文字列のオプションがたくさんあり​​ますが、
C言語で文字列を解析しようとしたときに、これらを使用すると、手作業を大幅に節約することができ
>> 見て、ライブラリ内の最後の関数は、GetStringメソッドです。
それは、GetStringメソッドを正しく書くためのトリッキーな関数であることが判明
それはそのような単純な、一般的な作業のように見えても。
なぜこのような場合ですか？
さて、それでは、例としては、ユーザがタイプインチその行を格納しようとしているかを考える
文字列は文字の配列であるため、
我々は、スタック上の配列に格納したい場合があり
しかし、我々は我々がそれを宣言するときに配列があることを行っているどのくらい知っている必要があります。
同様に、我々は、ヒープ上にそれを置きたい場合、
我々は、malloc関数に我々が確保したいバイト数を渡す必要があります
しかし、これは不可能です。
我々は、ユーザーが入力しますどのように多くの文字全く分からない
ユーザが実際にそれらを入力する前に行います。
>> この問題に対する解決策は、素朴な、と言う、単にスペースの大きな塊を予約することです
ユーザーの入力のために1000文字のブロック、
ユーザーがその長い文字列を入力することはないと仮定します。
これは2つの理由のために悪い考えです。
まず、ユーザーは、通常、その長い文字列で入力しないと仮定
あなたは多くのメモリを無駄でした。
あなたがこれを行う場合、最近のマシンでは、これは問題ではないかもしれません
1つまたは2つの孤立した事例では、
しかし、あなたは、ループ内でユーザーの入力を取って、後で使用するために保存している場合、
あなたはすぐにメモリのトンを吸うことができます。
さらに、もしあなたが書いているプログラムが小さいコ​​ンピュータ用です -
限られたメモリを搭載したスマートフォンや他の何かのようなデバイス -
このソリューションは多くの高速化の問題が発生します。
これをしないための第二は、より深刻な理由は、それが脆弱なプログラムを残すということです
バッファオーバーフロー攻撃と呼ばれるものに。
プログラミングでは、バッファは、一時的に入力または出力データを格納するために使用されるメモリです
この場合には当社の1000-charのブロックどちらです。
データブロックの末尾を超えて書き込まれたときにバッファオーバーフローが発生します。
>> たとえば、ユーザーが実際に1000以上の文字でタイプをしている場合。
配列を使用してプログラミングをするときに、誤ってこれを経験しているかもしれません。
あなたは10 intの配列を持っている場合は、何も読み込みまたは書き込みしようとしているからあなたを止めるものはありません
第十五intです。
全くコンパイラの警告やエラーはありません。
プログラムはただ直進失策とメモリにアクセス
それが思うところ第十五int型は次のようになりますが、これはあなたの他の変数を上書きすることができます。
最悪のケースでは、あなたのプログラムの内部の一部を上書きすることができます
制御機構は、実際には別の命令を実行するようにプログラムを引き起こす
あなたが意図したよりも。
>> さて、それは誤ってこれを行うのが一般的ではないが、
しかし、これは悪者がプログラムを破るために使用することはかなり一般的な技術である
そして他の人のコンピュータ上で悪意のあるコードを置く。
したがって、私達はちょうど私達の素朴なソリューションを使用することはできません。
我々は、脆弱性があるから我々のプログラムを防止するための方法が必要
バッファオーバーフロー攻撃へ。
これを行うには、我々が読んとして私達のバッファが成長できることを確認する必要があります
ユーザからの入力。
解決法は？私たちは、ヒープに割り当てられたバッファを使用します。
我々はそれがサイズ変更を使用してrealloc関数のサイズを変更することができるので、
バッファ内の次の空きスロットのインデックス - と我々は2つ​​の番号を追跡
とバッファの長さや容量。
我々は、fgetc関数を使用して、一度に1ユーザから文字を読み取ります。
STDIN - - fgetc関数が取る引数は、標準入力から文字列への参照である
これは、ユーザの入力を転送するために使用される事前接続入力チャネルです
端末からプログラムへ。
>> 新しいキャラクターでユーザータイプは、我々は、インデックスかどうかを確認するたびに
次の空きスロットに1を加えたバッファの容量を超えています。
1は、次の空いているインデックスが5の場合、入ってくるので、
その後、私たちのバッファの長さは0〜6インデキシングおかげでなければなりません。
我々はバッファ内の領域を使い果たしてしまったなら、私たちはそれのサイズを変更しようとすると、
我々はリサイズした回数を減らすようにそれを倍増
ユーザーは本当に長い文字列で入力された場合。
文字列が長すぎたどっているか、我々は、ヒープ·メモリーが不足した場合場合、
私達は私達のバッファーと戻りnullを解放します。
>> 最後に、我々はバッファにchar型を追加します。
一旦ユーザヒットは、EnterキーまたはReturn、新しい行をシグナリング
または特別CHAR - 制御d - 入力の終了を通知し、
我々は、ユーザーが実際にはまったく何もで入力しているかどうかを確認を行う。
そうでなかったら、私達はnullを返します。
そうでなければ、私たちのバッファは、おそらく我々は必要以上に大きくなるので、
最悪の場合、それは我々が必要とほぼ二倍だ
私達は私達がサイズ変更する​​たびに倍増以来、
我々は我々が必要とするスペースの量だけを使用して、文字列の新しいコピーを作成します。
我々は、malloc呼び出しに余分な1を追加
そんなに特別なヌル終端文字のためのスペースがあること - \ 0は、
我々は残りの文字でコピーかつて我々は文字列に追加している、
strncpyを使用する代わりにstrcpyの
我々は我々がコピーしたい正確にどのように多くの文字を指定できるようにします。
それは\ 0に達するまでは、strcpyをコピーします。
その後、我々は我々のバッファを開放して、呼び出し元にコピーを返す。
>> 誰がこのような単純な見せかけの機能を知っていたので複雑なのだろうか？
今、あなたはCS50ライブラリに入るか知っている。
>> 私の名前はネイトHardisonであり、これはCS50です。
[CS50.TV]