[Powered by Google Translate] [セクション5 - より快適]
[ロブボーデン - ハーバード大学]
[これはCS50です。 - CS50.TV]
>> 私は私の電子メールで述べているように、あなたが使用できるものがたくさんあり​​ます
実際問題セットを実行するアプライアンス以外。
我々は、我々はより簡単にあなたを助けることができるという理由だけでは、アプライアンスでそれを行うことをお勧めします
そして我々は、すべてが動作するように起こっているか知っています。
しかし、言う場合は、物事を行うことができます場所の一例としては、アクセス権を持っていない
アプライアンスへのか、科学センターの地下で仕事をしたい -
その実際に彼らはあまりにもアプライアンスを使用している -
あなたがどこでも仕事をしたい場合。
一例は、SSHの見て/聞いたことがあるのですか？
SSHは、ちょうど何かに接続するように基本的にです。
実際に、今私は、アプライアンスにSSHedよ。
私は、アプライアンスで直接作業することはありません。
ここアプライアンスがあり、ここでダウンして見てみると、このIPアドレスを参照してください。
私は、アプライアンス自体では動作しません;
私はいつもiTerm2ウィンドウ/ターミナルウィンドウにやって来る。
あなたは、そのIPアドレス、SSH jharvard@192.168.129.128へのSSHができます。
それはこのような素敵なパターンなので、私は非常に簡単にその番号を覚えています。
しかし、それは私のパスワードを私に尋ねるでしょう、そして今私は、アプライアンスにいるよ。
基本的に、この時点では、場合は、アプライアンス自体の内部端子を開放
このインタフェースは、しかし、あなたがそれを使用するでしょう、まったく同じです
インターフェイスとして、私はこっちに使っていますが、今はSSHedいる。
アプライアンスへのSSHをする必要はありません。
そこにSSH可能性がある別の場所の一例は、私はあなたがデフォルトで持っているかなり確信している -
ああ。ビガー。
あなたのすべては、FASのサーバーでデフォルトのFASのアカウントである必要があります。
私にとって、私はrbowden@nice.fas.harvard.eduへのSSHだろう。
それはあなたが初めて聞いて起こっている、とあなたは "はい"と言う。
私のパスワードは私のFASのパスワードであることを行っている。
それで今、私は素敵なサーバーにSSHedている、と私は私はここにしたい何かを行うことができます。
あなたが取るかもしれない多くのクラスは、124のように、あなたがここにコンテンツをアップロードする必要があるとしている
実際にあなたの問題セットを提出する。
しかし、あなたがお使いのアプライアンスへのアクセスを持っていないと言う。
それは言うだろう、ここでのように、あなたは、物事を行うことができます -
これはただの質問の私達のセクションです。
これは、アプライアンスでこれを行うよう求めてきます。
代わりに私は、サーバー上でそれを行うだけでしょう。
私はそれを解凍するつもりです。
問題は、あなたが、geditのようなものを使用するために使用していることになるだろう
アプライアンスのまたは任意の内部。
あなたは、FASのサーバー上のそのを持っているつもりはない。
これは、すべてのちょうどこのテキストインターフェースになるだろう。
だから、どちらか1、彼らが持ってないことをテキストエディタを習得しようとするかもしれません。
彼らは、ナノを持っています。
ナノは、通常、かなり使いやすいです。
あなたの矢印を使用して、正常に入力することができます。
だからそれは難しいことではありません。
あなたが本当に空想取得したい場合は、Emacsを使うことができ、
私もEmacsを終了する方法がわからないので、これは私はおそらく開かれているべきではありません。
コントロールのX、コントロールC？うん。
またはあなたは、私が使用しているものですVimを使用することができます。
そしてそうそれらはあなたのオプションは次のとおりです。
あなたが見れば、することができ、また、そうしたくない場合はmanual.cs50.net- -
ああ。
PCでは、SSHは、PuTTYを使用することができます
そのシステムとは別にダウンロードする必要があるとしている。
Mac上で、あなただけのデフォルトでターミナルを使用するか、または、iTerm2をダウンロードすることができます
これは良い、空想ターミナルのようなものです。
あなたはmanual.cs50.netに行く場合は、メモ帳+ +へのリンクが表示されます
これは、あなたがPC上で使用できるものです。
それはあなたのメモ帳+ +は、基本的にSSHのであるから、SFTPをすることができます。
これは何をあなたが行うようになると、ローカルにあるファイルを編集
その後、あなたがそれらを保存したい時はいつでも、それは、nice.fasに保存されます
どこでそれらを実行することができます。
およびMac上で同等のTextWranglerになるだろう。
だから、あなたが同じことを行うことができます。
それは、あなたがローカルにファイルを編集し、nice.fasにそれらを保存することができます
どこでそれらを実行することができます。
あなたがこれまでアプライアンスずに立ち往生している場合は、それで、あなたは、これらのオプションを持っている
それでも問題セットを行う。
1問題は、CS50ライブラリを持っているつもりはないことになるだろう
nice.fasはデフォルトであることを持っていないため。
あなたはどちらCS50ライブラリをダウンロードすることができます -
私はこの時点ではその必要はないと思う。
あなたはどちらか、CS50ライブラリをダウンロードしてnice.fasにそれをコピーすることができます
または私はこの時点で我々はとにかくそれをもう使用しないと思います。
我々が行う場合、または、あなたは時間に置き換えていることができます
とにかくCS50ライブラリ内の関数の実装。
だから制限の多くはないはずです。
そして、それはそれだ。
>> 私は今、アプライアンスに戻って行くよ、我々は、アプライアンスに全力を尽くします。
私は私の電子メールの中で述べたように、初めに、質問の私達のセクションを見てみると、
我々はあなたが見ることになっていた短い1の話をしなければなりません。
我々は、リダイレクトとパイプと、これらの3つの質問があります。
>> するストリームのような関数は、printfデフォルトで書くのですか？
だからストリーム。ストリームとは何ですか？
それは単にいくつかのような流れは、基本的には -
それも、1と0のソースではありません。
それがここに求めているストリームは標準外です。
それで、標準出力は、あなたがそれに書き込むことストリームです
それが画面に表示されます。
標準出力は、ストリームによって、それはあなただけで、それには、1と0書き込みを意味
と標準出力のもう一方の端は、まさにそれをストリームから読み込みます。
それはちょうど1と0の文字列です。
あなたは、ストリームに書き込むこともできますし、ストリームから読み込むことができます
ストリームが実際に何であるかによって異なります。
他の二つのデフォルト·ストリームは、標準的なエラーに標準装備されています。
あなたがgetStringんいつで標準的であり、それはあなたのための入力のものを待っています。
だから、それはあなたを待って、それは実際には規格に待っている、
これは、あなたがキーボードでタイプしたときに取得されるものは本当にです。
あなたはインチ規格に入力している
標準エラー出力は、標準出力と基本的に同等である
あなたが標準エラー出力に印刷するとき、それは、それを専門の
あなたはそれだけにエラーメッセージを出力することになっている
ので、画面に出力通常のメッセージを区別することができます
彼らは標準出力または標準エラー出力に行ったかどうかに応じてエラーメッセージ対。
あまりにファイル。
標準標準入力、出力、標準エラー出力は、単に特別なストリームです
しかし実際には、任意のファイルは、ファイルを開いたときに、バイトのストリームになる
どこにあなたはちょうどそのストリームから読み込むことができます。
あなたは、ほとんどの部分は、単にバイトストリームとしてファイルを考えることができます。
だから彼らは、デフォルトではストリームに何を書くのですか？標準出力。
>> >と>>の違いは何ですか？
誰もが事前にビデオを見ましたか。オーケー。
>は、あなたがファイルにリダイレクトする方法であることを行っている
と>>また、ファイルに出力をリダイレクトしようとしている
それは代わりに、ファイルに付加するだろう。
たとえば、みましょう私は、右ここに辞書を持って起こると言う
とdictの内側だけのものは、猫、犬、魚、犬です。
あなたがコマンドラインで持っていることを1つのコマンドで、猫です
これは、単にファイルに何があるか印刷しようとしている。
だから私は、猫のdictを言うとき、それは猫、猫、犬、魚、犬を印字することになっている。つまり、すべての猫が何だ。
それは猫、猫、犬、魚、犬標準出力に出力することを意味します。
私が代わりにファイルにあることをリダイレクトしたい場合は、私は>を使用して、ファイルが何であれ、それをリダイレクトすることができます。
私は、ファイルのファイルを呼ぶことにします。
私は、ls場合だから今、私はファイルと呼ばれる新しいファイルを持って表示されます。
私はそれを開く場合、それは猫には、コマンドラインで入れて正確に何を持っているために起こっている。
私は再びそれを行う場合、だから今、それは、出力をファイルにリダイレクトするために起こっている
と私は、まったく同じものを持っているつもりです。
だから、技術的に、それは完全に我々が持っていたものを覆した。
そして、私は辞書を変更した場合は私たちが表示されます、私は犬を取り出した。
ここでもう一度ファイルに我々は猫のdictならば、我々は犬が除去された新しいバージョンを持っているつもりです。
だから、それを完全に上書きされます。
我々は>>を使用する場合は、代わりに、ファイルを追加するようになるだろう。
さて、ファイルを開いて、我々は、我々は2回印刷だけ同じものを持って参照してください。
それはかつてあったので、我々は元に追加されます。
だからそれは何>と>>行う。
次回は頼むん - それはそれについて尋ねることはありません。
>> 我々が持っているもう一つは、標準出力をリダイレクトIF <、>、である
<は標準をインチリダイレクトされようとしている
我々は例があれば見てみましょう。
私は、簡単な本当の自分を書くことができます。
の任意のファイル、hello.cを見てみましょう。
比較的簡単なファイル。
私はちょうど私が先ほど入力した文字列が何であったかにかかわらず "こんにちは"を印刷し、文字列を取得しています。
だからハローハロー、次に作る。/。
今では、何かを入力するように私を求めている
それはそれはインチ標準に入力する事で待っていることを意味
だからロブ、私達はちょうどこんにちは言おうとしているインチ私は標準的にほしいと思うものは何でも入る！
それは、ハローに標準出力にロブを印刷しています！
私は、。/ helloとその後リダイレクトをするのであれば、
今のあなただけのファイルからリダイレクトすることができます。
私はいくつかのファイル、txtファイルに入れて、私は、ロブを置くのであれば
私はハロー実行し、その後にファイルtxtをリダイレクトした場合、。/こんにちは、それはロブ、こんにちはと言うつもりだ！直ちに。
それは最初のGetStringメソッドを取得し、それは、内標準を待っているとき
における標準は、もはや入力を、取得するデータは手動でキーボードの上で待機されていません。
その代わりに、我々はファイルtxtファイルからの読み込みに標準でリダイレクトしている。
そしてそれは、単にラインロブあるファイルtxtファイルから読み取るために起こっている
そして、次に、それはこんにちは、ロブを印字することになっている！
そして、私が望んでいたならば、私も行うことができます。/こんにちは<TXT
その後こんにちはです、それの印刷、ロブ、その標準出力！、
私は、独自のファイルにそれをリダイレクトすることができます。
私はまさしくこんにちはファイルを呼ぶことにします - いや、私はしません、それは実行可能だから - txt2。
さて、txt2はHelloになるだろう。/こんにちは<txtなど、ロブの出力を持っているとしている！
>> 質問はありますか？
>> オーケー。それでは、ここではパイプラインを持っています。
パイプは、リダイレクションの最後の単位です。
>> ああ。私は、リダイレクションの1以上のユニットがあれば代わりにだと思います>あなたは2点を行う>
それは標準エラーをリダイレクトだ。
何かが標準エラーに行きそうだとすれば、それはtxt2に入れ得られないだろう。
しかし、私は2をすれば気付く>、それはまだこんにちは、ロブを印刷しています！コマンドラインに
私は唯一の標準エラー出力をリダイレクトしているので、私は標準をリダイレクトしていないよ。
標準エラーおよび標準出力が異なっている。
あなたは、実際には標準エラー出力に書きたい場合は、
それから私はstderrにfprintfのようにこれを変更することができます。
だからprintfは、デフォルトでは、標準出力に出力します。
私は手動で標準エラー出力に出力したい場合は、私はfprintfを使用する必要があります
と私が印刷したいものを指定します。
代わりに私はfprintfを標準出力（stdout）を行った場合は、そのは、printfと基本的に同等です。
しかし、標準エラー出力にfprintfを。
だから今、私はtxt2にこれをリダイレクトする場合は、こんにちは、ロブ！まだコマンドラインで印刷されたばかり
は標準エラー出力に出力さなってきたと私は唯一の標準をリダイレクトしているから。
私は今、標準エラー出力をリダイレクトする場合は、ここでは印刷されませんでした、とtxt2こんにちは、ロブになるだろう！
だから今、あなたは、標準エラー出力に、実際のエラーを印字することができます
および標準への定期的なメッセージをプリントアウトする。
それで、あなたがプログラムを実行すると、次のようにそれを実行することができます/こんにちはこのタイプを2で>
ので、あなたのプログラムが正常に実行しようとしていること、
しかし、あなたはあなたを取得したすべてのエラーメッセージは、エラー·ログで後で確認することができます
エラーのように、後に見て、あなたのエラーファイルは、発生したエラーを持つことになります。
>> 質問はありますか？
>> 最後のものは一つのコマンドから標準を取るように考えることができますパイプ、ある
それ次のコマンドの中で標準となっています。
ここでの例では、echoは、コマンドラインの事です
それはちょうど私がその引数として置くものは何でもエコーしようとしている。私は引用符を置くことはありません。
エコー何とか、何とか、何とかはただ何とか、何とか、何とかを印刷しようとしている。
前に、私が言ったとき、私はtxtファイルにロブを入れていた
私はロブをエコーし​​ている場合私は/、代わりに、txtファイルをリダイレクトすることができますので、
その後パイプそれ。/こんにちは、また同じタイプのものを行いますに。
これは、このコマンドの出力は、エコーロブを取っている
とするための入力としてそれを使用して、。/ helloです。
あなたは、最初のファイルにエコーロブをリダイレクトと考えることができます
し、ただ出力されました。/こんにちは、そのファイルに入力。
しかし、それは、画像の一時ファイルを取り出す。
>> その上で質問がありますか？
>> 次の質問は、これを含むとしている。
あなたはnames.txtと呼ばれるファイルに一意の名前の番号を見つけるためにどのようなパイプラインを使用することができます？
次に我々はここで使用したいとしているコマンドは一意であるため、uniqの、トイレ。
あなたは、実際にそれが何をするかを見たい場合は、man uniqを行うことができます
とそれだけで入力から隣接一致する行をフィルタリングするために起こっている。
そして男wcは改行、単語、および各ファイルのバイト数を出力しようとしている。
そして、我々が使用したいとしている最後の1つは、ソートされ
それはちょうどtxtファイルの行をソートしようとしている。
私はいくつかのtxtファイル、names.txtを作り、それはロブ、トミー、ヨセフ、トミー、ヨセフ、RJ、ロブ、なら
私はここでやりたいことは、このファイル内でユニークな名前の数を見つけることです。
だから答えは何をすべきですか？ >> [生徒] 4。 >>うん。
ロブ、トミー、ヨセフ、RJは、このファイル内で一意の名前だけなのでそれは4でなければなりません。
最初のステップは、私はちょうどnames.txt上のワードカウントを行う場合、
これは実際に私にすべてを語っている。
これは、実際に印刷である - 改行、単語、そしてバイト·カウント - 男性トイレ、見てみましょう。
私が行だけを気にしている場合、私はちょうどトイレ - lのnames.txtを行うことができます。
だからステップ1です。
names.txtはちょうどすべての名前が含まれているため、しかし、私は、トイレ - lのnames.txtにしたくない
と私は、すべての非一意のものを除外する。
私はuniqはnames.txtをすればそう、それは非常に私は欲しいものを与えるものではありません
重複する名前がまだ残っているからです。
これはなぜですか？ uniqは私が欲しいものをなぜしてるんじゃない？
[学生]重複ではない[聞こえない] >>うん。
uniqのためのmanページはフィルタ隣接マッチングラインを言うことを覚えています。
彼らは隣接じゃないので、それらをフィルタリングしません。
私が最初にそれらを並べ替える場合、並べ替えnames.txtは一緒にすべての重複行を入れることになるだろう。
だから今ソートnames.txtはということです。
uniqは|私はあるuniqは、への入力としてそれを使用するつもりです。
それは私のヨセフは、RJ、ロブ、トミーを与える
と私は、トイレ - lへの入力としてそれを使用したい
それは私に4を与えるために起こっている。
それがここで言うように、あなたはどのようなパイプラインを使用することができます？
あなたは、一連のコマンドを使用して同じようにたくさんのことを行うことができます
どこであなたは次のコマンドの入力としてコマンドからの出力を使用しています。
あなたは物事の多くは、巧妙なたくさんのことを行うことができます。
>> 質問はありますか？
オーケー。
パイプとリダイレクト用のそれはそのです。
>> 今、私たちは、実際のものは、コーディングのものに進みます。
このPDFの内部では、このコマンドが表示されます
そして、あなたのアプライアンスでこのコマンドを実行するとよいでしょう。
wgetのは、基本的には、ちょうどインターネットから何かを得るためのコマンドである
そうwgetとこのURL。
お使いのブラウザでこのURLに行ってきました場合は、そのファイルをダウンロードします。
私はちょうどそれをクリックしたので、それは私のためにファイルをダウンロードしました。
しかし、端末の内部にその事のwgetの書き込み
ちょうどあなたの端末にそれをダウンロードしようとしている。
、私はsection5.zip持っていて、section5.zipを解凍したいと思う
あなたにセクション5と呼ばれるフォルダを与えるために起こっている、
これは、我々はその中に今日使用されようとしているすべてのファイルを持っているとしている。
これらのプログラムのファイル名が示唆するように、彼らは少しバギーだ、
ので、あなたの使命は、gdbを使って理由を解明することである。
それらは皆をダウンロードし/それらがダウンロード取得する方法を知っていますか
それらのアプライアンスに？オーケー。
>> ./buggy1実行し、それは、セグメンテーションフォールト（コアダンプ）を言うだろう
そのあなたがセグメンテーションフォルトを取得し、いつでも、それは悪いことだ。
どのような状況であなたはsegfaultを得るのですか？
[学生]はNULLポインタを間接参照。 >>うん。だから、その一例である。
あなたがセグメンテーションフォルトを取得するつもりだNULLポインタを間接参照。
何segfaultを意味することは、あなたが触れるべきではないメモリを触れているである。
だからヌルポインタを間接参照することにより、アドレス0に触れている
そして基本的に、すべてのコンピュータは最近アドレス0は触れるべきではないメモリであると言う。
セグメンテーションフォルトでNULLポインタを逆参照の結果、なぜようだ。
あなたはポインタを初期化しないために起こるとき、それは、ゴミの値を持つ
ので、あなたがそれをデリファレンスしようとすると、十中八九、メモリを触れている
それは、辺ぴな所にあります。
あなたは幸運とゴミ値を取得してしまった場合
スタックまたは何かのどこかをポイントするように起こった、
その後、ときにポインタを初期化していないことを間接参照するとき、
何も間違って行くことはありません。
しかし、それはどこかでスタックとヒープの間、と言う、を指している場合、
またはそれだけでどこかに、まだあなたのプログラムで使用されていないために、その指している
次にあなたが触れるべきではないメモリに触れていてはsegfault。
再帰的な関数を書いて、それが何回も再帰した場合
そしてあなたのスタックが大きくなりすぎたとの事にスタックが衝突
それはと衝突してはならないこと、あなたが触れるべきではありませんメモリを触れている、
ので、あなたはsegfault。
つまりsegfaultをするものです。
>> それはまた、あなたのような文字列を持っている場合と同じ理由だ -
のは、前のプログラムに戻りましょう。
hello.cの - は - 私にちょうど何か他のものを作るつもり。
char *型S = "こんにちは、世界！";
私が使用している場合* S =何か、s [0] = 'X';を
そうこんにちは作る、。/こんにちは、なぜそれはsegfaultしましたか？
なぜこのようなことがsegfaultをしましたか？
何が起こると思いますか？
私が行った場合のprintf（ "％s \ n"が、秒）、あなたは何を印刷したいと思いますか？
[学生]×ハロー。 >>うん。
問題は、あなたがこのような文字列を宣言するときにということである
sは、スタック上に行くために起こっているポインタです
とどのようなsが指しているのは、読取り専用メモリに格納されているこの文字列です。
名前だけで、読み取り専用メモリによりだから、あなたのアイデアを取得する必要があります
それは、読み取り専用メモリ内容変更しようとすると、
あなたはメモリでやってされるべきではない何かをやっているとあなたはsegfault。
これは実際にはchar * sとcharの[]の間には大きな違いです。
だからcharの[]は、今、この文字列はスタックに置かれようとしている、
およびスタックは、これは完全に正常に動作する必要がありますことを意味し、読み取り専用ではありません。
そしてそれはありません。
私は何のchar * S = "こんにちは世界！"、S自体がスタック上にあることを覚えておいてください
が、sどこかを指し、それはどこかに読み取り専用であることを起こる。
しかし、charの[]はスタック上の何かである。
だからそれは起こってセグメンテーション違反の別の例です。
>> 我々は./buggy1がセグメンテーション違反になったことを見た。
理論的には、直ちにbuggy1.cで見てはいけない。
代わりに、私たちは、gdbを介してそれを見てみましょう。
あなたがセグメンテーションフォールトを（コアダンプ）を取得したときにすることに注意して、
あなたはここに呼ばれるコアの上でこのファイルを取得します。
我々は、ls-l場合には、当社はそのコアは通常かなり大きなファイルで表示されます。
これは、ファイルのバイト数ですので、250代のキロバイトのように見えます。
この理由は、コア·ダンプが実際に何であるということです
あるとき、プログラムがクラッシュすると、あなたのプログラムのメモリの状態
ただ、このファイルにコピー＆ペーストされます。
なお、ファイルにダンプされます。
このプログラムは、それが実行されている状態で、約250キロバイトのメモリ使用量がたまたま
となるように、このファイルにダンプされてしまったものだ。
我々はgdb buggy1コアをすれば今度はそのファイルを見ることができます。
私達はちょうどGDB buggy1を行うことができます、そしてそれはちょうど、定期的にgdbを起動します
その入力ファイルとしてbuggy1を使用しています。
gdbの使い方buggy1コアにした場合には、それが具体的にgdbを起動するために起こっている
そのコアファイルを見ることによって。
そして、あなたはbuggy1手段gdbを言ってと、そのコアファイルがbuggy1プログラムから来ていることを知っている。
だからGDB buggy1コアがすぐに私たちをもたらすために起こっている
プログラムが終了することを起こった場所へ。
我々はここで、信号11、セグメンテーションフォルトで終了したプログラムを参照してください。
我々は、おそらく非常に参考にされていないアセンブリの行を参照してくださいに起こる。
あなたはBTまたはバックトレースを入力した場合でも、それは関数になるだろう
それが私たちの現在のスタックフレームのリストを与える。
だからバックトレース。我々は2つ​​だけのスタックフレームを持っているように見えます。
第一は、私たちのメインスタックのフレームです
2つ目は、我々はにたまたまいるこの関数のスタックフレームです
我々は唯一のアセンブリコードを持っているように見えている。
それでは、私たちのメイン関数に戻りましょう
そして、我々はフレーム1を行うことができない、と私は、我々はまた、ダウンできると思うために
アップまたは - しかし、私はほとんどダウンして行うことはありません。うん。
上下。アップダウンスタックフレームをあなたをダウンさせ、1つのスタックフレームをあなたが表示されます。
私はそれを使用しない傾向にあります。
私は具体的には1のラベルが付いたフレームに移動されているフレーム1を、言う。
フレーム1は、メインスタックフレームに私たちをもたらすために起こっている
そしてそれは我々がであることが起こるのコード行を右ここに述べています。
私たちはコードのカップル以上の行を検索したい場合、我々はリストを言うことができる、
そしてそれは私達にそれを回避してコードのすべての行を与えるために起こっている。
我々はsegfaultedラインは6であった：
するif（strcmp関数（ "CS50岩"は、argv [1]）== 0）。
それがまだ明確でない場合、あなたはそれがsegfaultedなぜ考えることによって、ここからまっすぐにそれを得ることができます。
しかし、我々はさらに一歩それを取ると、 "なぜ、argvは[1] segfaultを起こすだろうか"、と言うことができます
プリントargv [1]にしてみましょう、それがnullポインタであるそれの0x0の、のように見えます。
我々は、CS50岩やnullをstrcmpingしていて、そのためにsegfaultを起こすために起こっている。
そして、なぜですargv [1]をヌル？
[学生]我々はそれをすべてのコマンドライン引数を与えていないので。
うん。我々はそれをすべてのコマンドライン引数を与えなかった。
だから./buggy1はargv [0]のこと./buggy1を持っているとしている。
それは、argv [1]が、その結果は、セグメンテーション違反になるだろう持っていることはないだろう。
しかし、代わりに、私はちょうどCS50行う場合、それはあなたがDを得ると言うために起こっている
それはそれが行うことになっているものだからです。
buggy1.cを見て、それを印刷することになっている "あなたは、Dを得る" -
argvは[1] "CS50岩"は、他に、 "あなたは、Dを取得"されていない場合は "あなたが得る！"
私たちが望むのであれば、我々は、真と比較するためにこれが必要
これは、それが0に比較することを意味します。
だから、argvは[1] "CS50岩"である必要があります。
あなたは、コマンドラインでその処理を行いたい場合、スペースをエスケープするには\を使用する必要があります。
だからCS50 \岩やあなたが取得！
バックスラッシュを行わない場合は、なぜこれが動作しませんか？
[学生]それは、2つの異なる引数です。 >>うん。
argv [1]にはCS50になるだろう、とargv [2]は、岩になるだろう。オーケー。
>> 今すぐ./buggy2は再びsegfaultをしようとしている。
代わりに、そのコアファイルとそれを開くのでは、我々だけで、直接buggy2を開くよ
gdbのbuggy2そう。
私達はちょうど私達のプログラムを実行する場合、今、それはシグナルSIGSEGVを受信したプログラムを言おうとしている、
それはセグメンテーションフォルト信号であり、それが起こることを起こった場所です。
私たちのバックトレースを見ると、我々は、我々は関数oh_noにあったことがわかり
関数BINKYによって呼び出された関数のちっぽけな、、によって呼び出された
どちらがメインで呼ばれていた。
我々はまた、これらの関数に引数を見ることができます。
ちっぽけとBINKYへの引数は1であった。
我々は関数oh_noをリストする場合は、我々はoh_noはただのchar ** S = NULLをやっていることがわかります。
* S = "BOOM";
なぜそれが失敗していました？
[学生]あなたはNULLポインタを逆参照することはできません？ >>うん。
これは単に、それはchar **であることを起こるかどうかに関係なく、sがNULLであると言っている
あなたがそれをどう解釈するかに応じて、それは文字列へのポインタへのポインタの場合もある、
または文字列の配列。
それはsがNULLですので、* sは、NULLポインタを間接参照している
ので、これがクラッシュしようとしている。
これはあなたがおそらくセグメンテーションフォルトができる最も簡単な方法の一つです。
それはちょうどヌルポインタを宣言してすぐにセグメンテーションフォルトだ。
それはoh_noがやっていることだ。
我々は1つ上のフレームに行くなら、私たちはoh_no呼び出された関数に取得するつもりだ。
私がダウンしていることを実行する必要があります。
次のコマンドを入力しないと、あなただけ再度Enterを押すと、
それはちょうどあなたが実行したことを前回のコマンドを繰り返すことになります。
我々は、フレーム1にあります。
このフレームの一覧表示、我々の関数であるここを参照してください。
あなたは再びリストをヒットしたり、リスト20を行うことができますし、それはより多くのリストが表示されます。
関数ちっぽけなiが1である場合、その後、oh_noの機能に行くと言う
他こそこそ機能にアクセスしてください。
そして、我々は我々がここまで見ることが起こるので、私は1知っている
そのちっぽけな、引数1で呼び出されました。
それとも、ただ私をプリント行うことができますし、それは私が1であると言うだろう。
私たちはちっぽけで現在、我々は別のフレームを上がると、我々はBINKYで終わるでしょうね。
アップ。今、私たちはBINKYにしている。
この関数をリストする - 半分は私を断つ前からリスト -
iが0であるかのようにそれは始まったし、我々は、それoh_no呼び出していくつもりですが、他のちっぽけな呼び出し。
我々は、私が1であったことがわかっているので、ちっぽけと呼ばれる。
そして今、我々は、メイン、メインに戻ってきただけます。int i = RAND（）％3であることを行っている。
それはちょうどあなたに0,1、または2のいずれかの乱数を与えるために起こっている。
それは数字でBINKYを呼び出すために起こっている、それは0を返します。
これを見ると、
ただ、すぐにそれを実行せずに手動でプログラムを歩く
あなたは私たちがプログラムを実行するときにすることを意味メイン、目にブレークポイントを設定します
それがブレークポイントに達するまで、プログラムが起動実行されます。
プログラムを実行しているので、それが実行され、それが主な機能にヒットし、実行を停止します。
今、私たちは主の中にいると、stepやnextのコードの次の行に私たちを持って来るために起こっている。
あなたは、stepやnextを行うことができます。
次回打つ、今私は、RAND（）％3、私たちは、iの値を印刷することができます、に設定されている
そしてそれは私が1であると言うだろう。
今では、私たちが次のまたはステップを使用するかどうかに関係ありません。
私はそれ以前のもので大事だっと思いますが、我々は次の使用するとよいでしょう。
我々はステップを使用する場合、我々は現物を見てみつまり、関数にステップインする
それはBINKYの内側に起こっている。
我々は次を使用している場合、それは関数を通すことを意味
そして、弊社のメイン関数のコードの次の行に進みます。
右ここでは、この行には、私はそれは、rand（）％3言ったところであった;
私は一歩をした場合、それは、randの実装に行くだろう
そしてそこに何が起こっているかを見て、私は、rand関数をステップ実行することができます。
しかし、私は、rand関数を気にしないでください。
私はメインのコードの次の行に移動したいので、私は次の使用します。
しかし、今私はBINKY機能について気にしないので、私はそれに足を踏み入れたいと思います。
今私はBINKYにいるよ。
コー​​ドの最初の行は、（i == 0）場合に言おうとしている、私は、一歩を踏み出す
私たちはちっぽけで終わるを参照してください。
我々はリストの事をした場合、我々はそれがi = 0であることを確認してください。
、iは0に等しいではないので、それは他の条件に行ってきました
そのちっぽけな（i）を呼び出すために起こっている。
あなたは混乱してしまうでしょう。
あなただけの直接これらの行を見れば、あなたは、（i == 0）場合と思うかもしれない
大丈夫、私は一歩を踏み出した、今私はちっぽけな（i）によ
あなたはそれがi = 0のか何かを意味しな​​ければならないと思われるかもしれません。
いいえ、それはちょうどそれがラインちっぽけな（i）に直接貼ることができます知っていることを意味します。
iが0ではないので、次のステップでは、他で終了するつもりはない。
そうでなければで停止するように起こっているラインがありません。
それだけでは、（i）貧弱である、それが実際に実行することができます次の行に移動するだろう。
ちっぽけな（i）にステッピング、我々は、（i == 1）かどうかを確認します。
我々は、i = 1のため、我々はステップするとき、我々はoh_noで終わるつもりだ知っている知っていますか
i = 1であるあなたが足を踏み入れることができます関数oh_noを呼び出すため、
はchar ** sは= NULLとすぐに "ブーム"に設定しようとしている。
そして、実際にbuggy2の実装を見て、
0,1、または2 - - 通話BINKY、これは、私だけで乱数を取得している
iが0である場合、それは他のoh_no、それがここに来るちっぽけを呼び出し、呼び出されます。
私は、コールoh_no 1であれば、そうでなければ、ここまで来れた、しなやかで優雅を呼び出す
iが2である場合、oh_noを呼び出します。
私も方法があるとは思わない -
誰もがこのsegfaultをされないプログラムの作り方を見ていますか？
私は何かが欠けている限り、私が0であれば、あなたはすぐにセグメンテーション違反になるため、
他には、私はあなたがsegfaultを1であれば機能に行く
他にはiが2である場合は、セグメンテーションフォルト機能に行く。
だから、あなたが何をするかに関係なく、あなたはsegfaultしていません。
>> 私は、それが代わりにchar ** S = NULLを行うのであろう固定させる方法の一例を推測
あなたは、その文字列のためのスペースをmalloc関数可能性があります。
sizeofのか - 我々は、malloc（sizeof演算）を行うことができます？
[学生]（char型）* 5？ >>これは右の見えるのですか？
私は実際にそれを実行した場合これがうまくいくと仮定しているが、それは私が探しているものではありません。
sの型を見てみましょう。 int *を追加してみましょうので、int型* xになります。
私はmalloc（sizeof（int））を行うだろう。
または私は5の配列を検索したい場合、私は（sizeof（int）を* 5）するだろう。
私は、int **を持っている場合はどうなりますか？
私は、mallocう？
[学生]ポインタのサイズ。 >>うん。 （はsizeof（int *）を）;
ここで同じことをダウン。
私は（sizeof（char *）は）したい;
これは "ブーム"を指すポインタに領域を割り当てるために起こっている。
私は "ブーム"自体に領域を割り当てる必要はありません。
これは私が前に言ったことと基本的に同じであるため、
char型の* X = "ブーム"。
"BOOM"はすでに存在しています。これは、メモリの読み出し専用領域に存在すると発生します。
sはchar **型であれば、それはすでに、次のコード行を意味し、存在
次に* sはchar *型であり、あなたが "ブーム"を指すように、このchar *を設定しています。
私はsに "BOOM"をコピーしたい場合は、私は、sのためのスペースを割り当てる必要があります。
私がやります* S =のmalloc（sizeofの型（char）* 5）;
なぜ5？
なぜいけないの4？ "BOOM"は4文字であるように見えます。 >> [学生]がnull文字。
うん。あなたのすべての文字列は、ヌル文字を必要としています。
今私は、strcatのような何かを行うことができます - 文字列をコピーするための機能とは何ですか？
[学生] CPY？ >> strcpyの。
男strcpyの。
だから、strcpyをstrncpyをや。
あなたが正確にどのように多くの文字を指定できますので、strncpyは、少し安全です
私たちが知っているので、しかし、ここでは重要ではありません。
だからstrcpyおよび引数に見える。
最初の引数は、私たちの目的地です。
二番目の引数は、私たちの情報源です。
我々は先の* sのポインタ "ブーム"にコピーしようとしている。
なぜあなたは私たちが前に持っていただけで何の代わりにstrcpyのでこれをしたいと思うかもしれません
* S = "ブーム"の？
そこにあなたがこれをしたいと思うかもしれません理由があるが、その理由は何ですか？
[学生]は "ブーム"の中で何かを変更したい場合。 >>うん。
今私はSのような何かを行うことができます[0] = 'X';
のポイントは、ヒープ上のヒープとその空間にsは、を指しているので、
"BOOM"が格納されているヒープ上に多くのスペースへのポインタです。
だから "ブーム"のこのコピーは、ヒープに格納されています。
我々のプログラムで "ブーム"の2つのコピーが技術的にあります。
ちょうどこの "ブーム"文字列定数で与えられている最初のものは、あります
と "ブーム"の2番目のコピーは、strcpyのは "ブーム"のコピーが作成されます。
しかし、 "ブーム"のコピーは、ヒープ上に格納され、ヒープあなたは自由に変更しているされています。
ヒープが読み取り専用ではないので、ことはつまり、S [0]
あなたは "ブーム"の値を変更できるようにする予定です。
それはあなたがそれらの文字を変更できるようになるだろう。
>> 質問はありますか？
オーケー。
>> レッツGDB buggy3、buggy3に移る。
私達はちょうどそれを実行し、我々は我々がsegfaultを取得してください。
我々はバックトレースする場合は、唯一の2つの機能があります。
私達が私達の主な機能にまで行けば、私たちはこのラインでsegfaultedていることがわかります。
だから、（ためには、この行を見てint型の行= 0; fgetsはこのようなものと等しくない場合はNULLをします;
行+ +）。
私たちの前のフレームが_IO_fgetsと呼ばれていました。
組み込みのC関数とそのロットがわかります、
あなたがセグメンテーションフォルトを取得するときに、本当に不可解な関数名が存在すること
このような_IO_fgets。
しかし、それはこのfgetsのコールに関連するだろう。
どこか内部ここで、我々はセグメンテーションフォルトしています。
我々はfgetsに引数を見れば、我々はバッファを印刷することができます。
として印刷してみましょう - いや、ああ。
プリントはまさに私はそれがしたいように仕事に行くのではない。
実際のプログラムを見てみましょう。
バッファは文字配列です。それは、128文字の文字配列です。
だから私は、プリントバッファと言うとき、それは、それらの128文字を印字することになっている
これは私が推測するには、期待されているものです。
私は何を探していたとすると、バッファのアドレスを出力している
それは本当に私に多くを教えてくれない。
だから私はここでxのバッファを開くと言うことが起こるとき、それは、私に0xbffff090を示しています
以前のまたはいくつかのポイントを覚えていれば、これ、Oxbffffはスタックっぽい地域になる傾向がある。
スタックはちょうど0xC000から下のどこかを開始する傾向がある。
ただ、このアドレスを見て、私は、バッファはスタック上に起こっていることを知っています。
アップ、実行、私のプログラムを再起動し、我々が見たバッファは、この文字シーケンスであった
それはかなり無意味です。
次に、ファイルを印刷する場合、ファイルをどのように見えるか？
[学生]はNull。 >>うん。
、ファイルはFILE *型のなので、ポインタである
そのポインタの値はnullになります。
だからfgetsが、間接的な方法でそのポインタから読み取ろうとしている
しかし、そのポインタにアクセスするためには、逆参照する必要があります。
または、それが指すべきかをアクセスするためには、それを間接参照。
だからそれはヌルポインタとセグメンテーションフォルトを間接参照だ。
私はそこに再起動した可能性があります。
私達は私達の主なポイントと実行時に中断した場合、
コー​​ドの最初の行は、char *ファイル名= "nonexistent.txt"です。
これは、このプログラムが失敗した理由として、かなり大きなヒントを与える必要があります。
私はこのファイルを開く場所を次のように入力すると、次の行にいってみましょう
その後、私はすぐに、かつて私は、次のヒット我々の行、入る、それはsegfaultになるだろう。
誰も我々はセグメンテーションフォルトかもしれない理由をスローするようにしたいのですか？
[学生]ファイルが存在しません。 >>うん。
これがヒントであることになっている
あなたがファイルをオープンするたびに、ファイルが実際に存在していることを確認する必要がある。
そこでここでは、 "nonexistent.txt";
我々読書はfopenのファイル名は、我々はそれから言う必要があるとき
場合（ファイル== NULL）やprintf（ "ファイルが存在しません！"と言う
または - まだ良い - ファイル名）;戻り値1;
だから今我々はそれがNULLであるかどうかを確認してください
実際に継続して、そのファイルから読み取ろうとする前に。
我々は、ちょうどそれがはたらくことを確認するためにそれをリメイクすることができます。
私は、新しい行を含むことを意図する。
だから今nonexistent.txtは存在しません。
あなたは、常にこの種のことをチェックする必要があります。
あなたは、常にfopenがNULLを返しているかどうかを確認する必要があります。
あなたはいつも、mallocがNULLを返していないことを確認すべきです
さもないとあなたはsegfault。
>> 今すぐbuggy4.c。
ランニング。私はこれが入力またはおそらく無限ループを待っていると推測している。
はい、それは無限ループです。
buggy4そう。我々が無限ループしているように見えます。
我々は、主に破ることができる、私たちのプログラムを実行します。
gdbで、限り、あなたは使う略語があいまいであるとして
彼らはあなたのために提供したり、特殊な略語、
その後はずっと次のOUT入力するのではなく、次のを使用する場合は、nを使用することができます。
そして今、私は一度ヒットNできたので、私はちょうど隣続けるためにEnterキーを打つことができる
代わりに、Enterキーは、nを入力し、nはnを入力しヒットする必要がなくなります。
私は0に[i]の配列を設定してforループのいくつかの種類の中にいるように見えます。
それは私がこのforループを抜け出したことがないように見えています。
私は私の印刷なので、iが2であれば、私は次行くよ。
私は、i、iが3である場合、私は次行くよ刷る。
私は、私が印刷だろうと私は3です。次に、iを印刷し、私は4です。
実際に、印刷はsizeof（配列）であるため、配列のサイズは20です。
いくつかの特別なGDBコマンドは何かが起こるまで行くためにそこのようですが、それが見えます。
これは、変数の値に条件を設定するようなものだ。しかし、私はそれが何であるか覚えていません。
- 私たちは前進し続けるのであれば
何を言ったのか？あなたは何を持ってきたの？
[学生]が表示されていますか私が追加 - >>うん。だから私は助けることができるが表示されます。
私達はちょうど私が表示された場合は、iの値が何であるかをここでお付けいたします
ので、私は毎回それをプリントアウトする必要はありません。
私たちはすぐ隣続けるなら、私たちは0、1、2、3、4、5、0、1、2、3、4、5、0、1、2、3、4、5を参照してください。
何かがひどく間違っている、と私は0にリセットされています。
buggy4.cを見てみると、起こることすべてがintの配列[5]を参照してください。
（のは、i <=はsizeof（配列）; i + +はi = 0のとき）のために
配列[I] = 0;
我々はそれがここで間違って何が見えますか？
ヒントとして、私は、gdb buggy4をしていたとき - メインは、実行を中断してみましょう -
私はちょうど条件が私はようやく抜け出すべき場所であるかを確認するには、printはsizeof（array）をしました。
どこまで話しましたか？私が実行したのですか？
私はまだ宣言していませんでした。
だからプリントはsizeof（配列）と20代、
、私の配列のサイズが5であり、それは5つの整数のだから期待されている
ので、全体のことは、sizeof（int）は4になりがち5 * sizeof（int）をバイトでなければなりません。
だから、はsizeof（配列）は20です。
これは何をすべきか？
[学生]はsizeof（int）を割ったものである。 >>うん、/ sizeof（int）を。
ここでの問題は依然として存在しているように見えます。私はこれがちょうどされるべきだと思う<
それはかなり常になので<、決して<=。
それでは、これは実際に壊れていた理由について考えてみましょう。
誰もがなぜ私はループの各反復を通じて0にリセットされたと推測していますか？
ここで起こっているの内側に唯一のものは、[i]は0に設定されている配列です。
だから何とかして、このコード行ではiが0にセットされている私たちのintを引き起こしている。
それが私のこの部分のメモリを上書きしているため[学生]それは次のようになります。
それは配列の次の要素だと思っているとき？ >> [ボーデン]はい。
我々は、配列の終わりを越えているとき、
我々がオーバーライドしていることをどうにかして、そのスペースは、iの値をオーバーライドしています。
我々はbuggy4に見ればそれで、メイン破る実行、
iのアドレスを印刷してみましょう。
それはbffff124ているように見えます。
今度は配列のアドレスを出力してみましょう[0]。 110。
何について[1]？ 114。
[2] 118。
11cは、120。配列[5] bfff124です。
だから配列[5]私は、その配列[5]は、iであることを意味すると同じアドレスを持っています。
彼らは同じアドレスを持つ場合、それらは同じものです。
だから我々は配列[5]を設定した場合は0に、我々は0にiを設定しています。
そして、あなたは、スタックの観点からこのことについて考えるならば、
int型iがiがスタック上にいくつかのスペースを取得つまり、最初に宣言されています。
次に配列[5]に割り当てられているため、その後20バイトがスタックに割り当てられます。
私が最初に割り振られますので、これらの20バイトが割り当てられ得る。
だから私は、右側の配列の前に起こる
と方法のため、私は、スタックは下方に広がりどこに技術的には、先週言ったように
もし配列へのインデックス、我々は、配列の0番目の位置にあることが保証されている場合
常に配列内の最初の位置より前に発生します。
これは私が先週それを描いた方法の一種です。
一番下に我々はアドレス0を持ち、上部に我々はアドレスマックスを持っていることに注意してください。
スタックは常に下に成長しています。
それでは、例としては、iを割り当てると言う。
私達はちょうど私が割り振られますここで整数までとしましょう​​つまり、iを整数に割り当てます。
その後、我々はその下のことを意味し5つの整数の我々の配列を割り当て、
スタックがダウンして成長しているので、それら5つの整数が割り当てられ得る。
しかし、配列がどのように働くかのために、私たちは保証されている、その配列内の最初の位置
常に配列の2番目のものよりも小さいアドレスを持っています。
だから、配列の位置0は、常にメモリに最初に起こる必要があり、
配列の位置1は、後に起こる必要があるのに対し、
と配列位置2は、その後起こることがあります
これは配列の位置0はここのどこかダウンが起こるかということ、
配列の位置1はその上に起こるだろう
最大アドレスはここにアップしているので、上に移動すると、上位アドレスを意味するので。
ダウンここ配列[0]だから、array [1]はここまで、配列[2]ここまで、配列[3]ここまで。
私たちはここで私はすべての方法を、整数を割り当て方法前に気付く
我々は配列にさらに、さらに移動すると、私達は私達の整数iに近づくと近づいている。
それはちょうど、その配列は、我々の配列のほかに、一つの位置である、[5]のように起こる
iが割り当てられることが起こった場所を正確に整数です。
だから我々は、スタック上にスペースを打つことが起こる点だ
それは整数iのために割り当てられた、と我々は0に設定している。
>> それはそれはどのように動作します。質問はありますか？うん。
気にしないで[学生]。オーケー。
[学生]はどのようにこれらのエラーのソートを回避するには？
これらのエラーの一種？プログラミング言語としてC言語を使用しないでください。
配列境界チェックを持っている言語を使用しています。
限り、あなたは気をつけているとして、あなたは自分の配列の境界を越えて行くことは避けねばならない。
そこでここでは[学生]我々はあなたの配列の境界を越えて行きました -
[ボーデン]物事がうまく行き始めるところですね。 >> [生徒]ああ、大丈夫。
あなたが配列に割り当てられたメモリ内にとどまる限り、あなたは大丈夫です。
しかし、Cは、エラーチェックを行いません。私は配列[1000]をすれば、それは喜んでちょうど起ころう変更されます -
それは配列の先頭に行く、それは後に1000年のポジションを行き、それを0に設定します。
それは、ああ、これは実際にそれで1000年のものを持っていない任意のチェックは行いません。
1000は、方法私は変化すべきかを超えています
一方、Javaやあなたが境界のインデックスの配列を取得しますか
または境界外のインデックスの例外。
高水準言語の多くは、これらのものを持っている理由です
あなたが配列の境界を越えて行けば、どこに、あなたは失敗する
あなたは下から物事を変更できないように
その後の事はただの例外を取得するよりもはるかに悪い行く
あなたが配列の終わりを越えて行ったことが書かれています。
[学生]そして、私たちはちょうど変更されているはずです<=にだけ<？ >> [ボーデン]うん。
それは、<はsizeof（配列）/ sizeof（int）をでなければなりません。
はsizeof（配列）は20ですが、我々は唯一の5をしたいので。 >> [生徒]右。
多くの質問？オーケー。
>> [学生]私は質問があります。 >>うん。
[学生]実際の配列変数とは何ですか？
[ボーデン]のような配列は何ですか？
配列自体はシンボルである。
それはちょうど私たちが参照している20バイトの先頭のアドレスです。
あなたはポインタとして考えることができますが、それは一定のポインタです。
物事がコンパイルされるとすぐに、配列変数はもう存在しません。
[学生]だからそれはどのように配列のサイズを見つけるのですか？
配列のサイズは、そのシンボルが参照して、そのブロックのサイズを指します。
私はprintfのような何かを（ "％P \ n"の配列）を行うと、
それを実行してみましょう。
私は間違った何をしたのか？
配列 '配列'はここに宣言した。
ああ、ここまで。
Clangのは賢いです、そして、それは、私は5つの要素として配列を宣言されたことに気づくことを起こる
しかし、私は位置1000にインデックス化しています。
それは、これらは単なる定数であるため、それを行うことができます。
それだけで私は配列の範囲を超えていることに気付いつもりでこれまで行くことができます。
しかし、私たちは、私が間違っている持っていたときに前に気付く
それはおそらく、私がかかることがありますどのように多くの値を決定することはできません
ので、私は、配列の末尾を超えていたことを判断することはできません。
それはちょうど巧妙であるClangのだ。
>> しかし、今buggy4を作る。だから、私は間違って他に何をやっている？
暗黙のうちにライブラリ関数 'printfの'を宣言。
私は＃を入れようと思っています。
オーケー。今すぐbuggy4を実行している。
私はポインタとしてそれを印刷し、ここで行ったように配列の値を出力する
このようなものを出力します - bfb8805c - いくつかのアドレスです。
それはスタックっぽい地域であります。
、配列自体はポインタのようですが、それは実際のポインタではありません
通常のポインタ以来、我々は、変更することができます。
アレイは、単にいくつかの定数である。メモリの20ブロックは、アドレス0xbfb8805cから始まります。
このアドレスを使用してそうbfb8805c +20- - または私は-20を推測 -
このアレイに割り当てられているメモリのすべてです。
配列は、変数自体はどこにも格納されません。
あなたは、コンパイラをコンパイルしているとき - それで手の波 -
それがために配列を知っている場所が、コンパイラは単に使用されます。
その配列が始まるところか知っており、
ので、それは常にちょうどその先頭からのオフセットの観点で物事を行うことができます。
これは配列を表す変数自体を必要としません。
しかし、私は、int * pを=配列のような何かをするとき、今pは、その配列を指すポインタである
そして今、pは、実際にスタック上に存在しません。
私はpを変更することが自由だ。私は、p = mallocを行うことができます。
だから、もともと配列が指すが、現在それは、ヒープ上にいくつかのスペースを指しています。
私は配列= mallocを行うことはできません。
Clangのが利口だ場合、それは右のバットから私に向かって怒鳴ります。
実は、私はgccがあまりにもこれを行うだろうと確信しています。
だから、配列型のint [5] 'は代入できません。
あなたは、配列型に何かを割り当てることはできません
配列は、定数だけであるためです。
それは、それらを参照する20バイトのシンボルです。私はそれを変更することはできません。
>> [学生]配列の大きさがどこに保存されますか？
[ボーデン]それはどこにも保存されていない。それはコンパイル時だそれは。
だから、配列のサイズはどこに保存されますか？
あなただけの配列自体が宣言された関数の内部ではsizeof（array）を使用することができます。
だから私は、いくつかの関数fooをやると私が行う場合（int型の配列[]）
のprintf（ "％d個\ n"ではsizeof（配列））;
その後ダウンして、ここで私は、foo（array）を呼び出します。
この関数の内部 - のは、それを実行してみましょう。
これは再び巧妙であるClangのです。
それは私に言って、その配列関数のパラメータにはsizeof
'int型*'のサイズを返します。
それは何が起こることを望んでいないなら、これはエラーになります。
実際にWerrorをオフにしてみましょう。
警告。警告は罰金です。
それはまだ限り、それは警告があるとしてコンパイルされます。
。/ a.outは4をプリントしようとしている。
生成された警告は何が悪かったのかの明確な指標である。
このint配列はただのsizeof（int *）を印刷しようとしている。
私はここで、配列[5]を入れた場合でも、それはまだただのsizeof（int *）を印字することになっている。
だから、できるだけ早くあなたには、この関数に渡すと配列とポインタの区別
存在しません。
これは、スタック上に宣言された配列であることを起こる
しかし、すぐに我々は、その値を渡していることのみを返す何とか、何とか、この関数に何とか、
このポインタは、スタック上にその配列を指しています。
sizeof演算子は、配列が宣言された関数に適用することを意味しますので、
これは、この関数をコンパイルしているときにあることを意味
Clangのは、この関数を通過するとき、それは配列のサイズが5のint型の配列であることを認識します。
だからそれは、sizeof（array）を見ている。まあ、それは20だ。
それはsizeofは基本的にほぼすべてのケースのためにどのように動作するかを実際にです。
sizeofは関数ではありません、それはオペレータだ。
あなたは、sizeof関数を呼び出すことはありません。
はsizeof（int）は、コンパイラはちょうどその4に変換されます。
分かった？オーケー。
>> [学生]だからメインでとfooのsizeof（配列）の違いは何ですか？
我々はint *型であるとsizeof（配列）、と言っているためです
ダウンここ配列がint *型ではないのに対し、これはint型の配列です。
>> [学生]だからあなたは配列[]の代わりにint *の配列にパラメータを持っている場合は、
それが今ではそれがポインタだからあなたはまだ配列を変えることができることを意味するでしょう？
[ボーデン]これ、気に入りましたか？ >> [生徒]うん。あなたは今、関数内の配列を変更することはできますか？
[ボーデン]あなたはどちらの場合も、配列を変更することができます。
これらの例の両方では、[4] = 0アレイを言うことは自由です。
[学生]しかし、あなたが何か他のものに配列ポイントを作ることができますか？
[ボーデン]ああ。うん。どちらの場合では - >> [生徒]うん。
[ボーデン]配列[]とint *の配列の間の区別は、何もない。
また、ここでいくつかの多次元の配列を得ることができます
いくつかの便利な構文については、それはまだ単なるポインタだ。
これは、私は配列=に、malloc（sizeof（int））を自由に行うことだということを意味し、そして今ではどこか別の場所を指す。
しかし、これは永遠に、常にどのように動作するかだけが好き、
それを作ることで、この配列を変更すると何か他のものを指す
それは、引数のコピーであるため、ここでは、この配列を下に変更されることはありません
その引数へのポインタではありません。
そして、実際に、それは全く同じだということ以上を指標として -
我々はすでに何を印字配列印刷物を見た -
私たちは、配列のアドレスや配列のアドレスのアドレスを印刷する場合
それらのいずれかに？
この1を無視してみましょう。
オーケー。これは問題ありません。それが今では。/ a.outを実行している。
印字配列は、その配列のアドレスを印刷して、同じものです。
アレイは、単に存在しません。
それはあなたの配列を表示しているとき、あなたはそれらの20バイトを指す記号を印刷している知っている。
配列のアドレスを印刷して、まあ、配列は存在しません。
これは、アドレスを持っていないので、それはちょうどそれらの20バイトのアドレスを出力します。
できるだけ早くあなたがダウンしてコンパイルすると、コンパイルされたbuggy4のように。/ a.outを
配列は存在しません。
ポインタが存​​在しています。配列はありません。
配列を表すメモリのブロックは、まだ存在している
しかし、その型の変数配列と変数は存在しません。
それらは、配列とポインタの間の主な違いのようなもの
できるだけ早くあなたが関数呼び出しを行うようですが、違いはありません。
しかし、配列自体が宣言された関数の内部で、sizeofが異なる動作を
あなたが代わりに型のサイズのブロックのサイズを印刷しているので、
それはシンボルだから、あなたはそれを変更することはできません。
事の印刷と実物のアドレスは同じものを出力します。
そして、それはそれはかなりです。
[学生]は、その1つのより多くの時間を言ってもらえますか？
私は何かを見逃していたかもしれない。
配列の印字配列とアドレスは同じものを出力し、
一方、あなたはポインタのアドレスに対するポインタを印刷する場合、
一つのことはあなたが指しているもののアドレスを出力し、
もう一つは、スタック上のポインタのアドレスを出力します。
あなたは、ポインタを変更することができ、あなたは配列のシンボルを変更することはできません。
とsizeofポインタはポインタ型のサイズで印刷しようとしている。
だからます。int * pはsizeof（p）は、4をプリントしようとしている
しかし、int型の配列[5]プリントはsizeof（配列）は20をプリントしようとしている。
[学生]だからint型の配列[5]は20を出力します？ >>はい。
なぜ内部buggy4のそれはsizeof（配列）になるように使用されるときだ
これは、i <20をやっていた、それは私たちが望んだものではありません。
我々は、i <5が欲しい。 >> [生徒]オーケー。
[ボーデン]そして、できるだけ早くあなたが関数に渡して起動するように、
私たちがやってint * pを=配列;
この関数の内部で、我々は基本的には、まったく同じ方法でpと配列を使うことができます。
sizeofの問題と変化問題を除いて。
しかし、pはa [0] = 1;配列[0] = 1を言うと同じです。
とすぐに我々は、foo（array）が言うように、または、関数foo（p）を;
foo関数の内部では、これは二度同じ呼び出しです。
以下の二つの呼び出しの間に違いはありません。
>> その上で良い誰？オーケー。
我々は10分を持っています。
>> 我々は、このハッカータイパープログラムを介して取得しようとするでしょう
去年か何か出てきたこのサイト。
それはちょうどあなたがランダムに入力し、それをプリントアウトのようなことになっている -
それが読み込まれていることを起こるどんなファイルあなたが入力しているように見えるものです。
これは、オペレーティング·システムのコードのいくつかの種類のように見えます。
それは我々が実装したいものだ。
あなたはhacker_typerという名前のバイナリ実行ファイルがあるはずです
それは、ファイル、単一の引数を取り、 "ハッカータイプ。"
実行可​​能ファイルを実行すると、画面をクリアする必要があります
その後、ユーザーがキーを押すたびに、渡されたファイルから1文字を出力します。
ですから、どんなキーを押し、それは捨てて、代わりにファイルから文字を印刷する必要があります
それは引数です。
私はかなり私たちが知っておく必要があるとしているものが何であるかを教えてあげる。
しかし、我々はtermiosライブラリをチェックアウトしたい。
私は私の生涯でこのライブラリを使用したことがないので、それは非常に最小限の目的を持っています。
しかし、これは、我々はあなたが打つ文字を捨てるために使用できるライブラリであることを行っている
あなたはインチ規格に入力しているとき
だからhacker_typer.c、我々は＃を含むようにするつもりだ。
は、termiosのmanページを見て - それの端末のOSや何かを推測 - 私 -​​
私はそれを読む方法を知りません。
これを見ると、それは、これらの2つのファイルを含めるように言うので、私たちはそうするだろう。
>> 最初のものは、最初に、私達は私達が開くべきファイルである単一の引数に取りたい。
だから私は何をすべきかをしたいですか？どのように私は、私は単一の引数を持っているかを確認するのですか？
[学生] argcはそれに等しい場合。 >> [ボーデン]うん。
もしそうなら（argcは= 2！）のprintf（ "使い方：％s [ファイル開くには]"）。
だから今、私は2番目の引数を提供せずに、これを実行する場合 - ああ、私は、新しい行を必要とする -
あなたはそれが言う用法がわかります。/ hacker_typer、
し、2番目の引数は、私は開きたいファイルである必要があります。
今私は何をすればいいですか？
私は、このファイルから読みたい。どうすれば、ファイルから読み込むのですか？
[学生]あなたが最初に開いた。 >>うん。
だから、fopenの。 fopenはどのように見えますか？
[学生]ファイル名。 >> [ボーデン]ファイル名はargv [1]になるだろう。
[学生]そして何がそれで何をしたいので、 - >> [ボーデン]うん。
あなたは覚えていなかった場合、だから、あなたは、男のfopenを行うだけでした
それはパスがファイル名であるconst char *のパスになるだろうここで、
const char *のモード。
あなたはモードとは何か覚えていないために起こる場合は、モードを探すことができます。
manページの内部では、スラッシュ文字は、物事を検索するために使用できるものです。
だから私は、モードを検索する/モードを入力します。
nとNを使用すると、検索がマッチを循環するために使用できるものです。
ここでは文字列に引数modeポイントを語る
次のいずれかのシーケンスで始まる。
だからrを、読み込み用にオープンしたテキストフ​​ァイル。それは我々が何をしたいです。
読書のための、と私はそれを保存したい。
事は、FILE *になるだろう。今私はどのように過ごしたいですか？
私に第二を与える。
オーケー。今私はどのように過ごしたいですか？
[学生]がNULLの場合にチェックします。 >> [ボーデン]うん。
ファイルを開くときはいつでも、あなたはそれを正常に開くことができるしていることを確認してください。
>> 今私は私が最初に私の現在の設定を読みたいtermiosのものをやってみたい
と何かにそれらを保存し、私は私の設定を変更したい
私が入力した任意の文字を捨てることができ、
そして私はそれらの設定を更新する必要があります。
そして、プログラムの最後に、私は元の設定に戻って変更したいと思います。
だからstructはtermios型になるだろう、と私はそれらのうちの2つをしたいつもりです。
一つ目は、私のcurrent_settingsになるだろう
その後、彼らは私のhacker_settingsことになるだろう。
まず、私は、私の現在の設定を保存するつもりです
それから私は、hacker_settingsを更新するつもりです
そしてその後、私のプログラムの終了時にせよ、私は現在の設定に戻したい。
だから、私たち人間のtermiosを動作する方法は、現在の設定を保存する。
我々はこのintのtcsetattr、int型tcgetattrを持っていることを参照してください。
私は、そのポインタによっては、termios構造体に渡します。
これは見ていきます方法です - I'veは既に関数が呼び出されたか忘れてしまった。
コピーと貼り付けます。
tcgetattrので、それから私は、私は情報を保存していることを構造体に渡したい
current_settingsになるだろうされている、
最初の引数は、私がの属性を保存したいもののためにファイル記述子です。
どのようなファイル記述子があると、ファイルを開く、任意の時間のようですが、それはファイル記述子を取得します。
ときに私のfopen argv [1]が、それはあなたが参照しているファイル記述子を取得します
あなたがそれに読み取りまたは書き込みをしたいとき。
それは私がここで使用するファイル記述子ではありません。
あなたがデフォルトで持っている3つのファイル記述子がありますが、
これは、標準で標準出力、標準エラーです。
デフォルトでは、私はそれが0で標準だと思うが、標準出力は1であり、標準誤差は2です。
だから私は、設定を変更したいのですか？
私は、文字を打つたびに設定を変更したい
私はそれが、それを画面に出力する代わりに離れて、その文字をスローするようにしたい。
何ストリーム - - 標準出力、または標準エラーで標準
私はキーボードで入力するときに物事に反応？ >> >>うんインチ[学生]スタンダード。
だから私は、0を行うことができますか私は、stdinを行うことができます。
私はインチ規格のcurrent_settingsを取得しています
>> 今私は、これらの設定を更新する
ので、最初私はcurrent_settingsが何であるかhacker_settingsにコピーします。
と構造体の仕事がどのようにそれだけがコピーされます。
ご想像のとおり、これは、すべてのフィールドをコピーします。
>> 今、私はいくつかのフィールドを更新したい。
termiosのを見ると、この多くを通読しなければならないでしょう
ちょうどあなたが見たいものを見るために、
しかし、あなたが見てみたいとしているフラグは、エコーです
そうエコー入力文字はエコー。
最初に私が設定したい - フィールドが何であるかもう忘れI've。
これは、構造体がどのように見えるかです。
入力モードだから私たちは変更したいと思います。
我々はそれを私たちが変えたいと思っているのだと確信するために解決策を見てみましょう。
我々は、すべてのこれらに目を通す必要がないようにするためにlflagを変更したい。
我々は地元のモードを変更したい。
あなたはすべてのものが属するのかを理解するために、この全体の事を通読しなければならないでしょう
我々は、変更したい。
しかし、それは我々がそれを変更したいとしているローカルのモードの内部です。
だからhacker_settings.cc_lmodeは、それが呼ばれるものです。
c_lflag。
我々はビット演算子に入るところです。
我々は時間のうちの​​一種だが、我々はそれで実際に素早く通過するでしょう。
我々はビット演算子に入るところであり、
私はあなたが起動するたびにフラグを扱うことをずっと前に一度だけ言ったと思う場合には、
あなたは、ビット演算子をたくさん使うことになるだろう。
フラグの各ビットは、行動のいくつかの並べ替えに対応しています。
そこでここでは、このフラグは、それらのすべてが別の何かを意味し、さまざまなものの束を持っています。
しかし、私がやりたいことだけエコーに対応するビットをオフにされています。
だからオフに私が＆=¬ECHOを行うことをオフにします。
実際に、私はそれは手帳か何かのようだと思う。私は再度確認するつもりです。
私はそれをtermiosにすることができます。それはちょうど、ECHOです。
ECHOは、単一のビットになるだろう。
¬ECHOは全てのフラグがtrueに設定されていることを意味し、すべてのビットが1にセットされていることを意味しようとしている
エコービットを除く。
これで私の地元のフラグを終了することによって、それが現在trueに設定されているすべてのフラグを意味します
まだtrueに設定されます。
私のエコーフラグがtrueに設定されている場合、これは必ずしもechoフラグをfalseに設定されています。
だから、このコード行は、単にechoフラグをオフにします。
コー​​ドの他の行は、私はちょうど時間の関係でそれらをコピーして、それらを説明するでしょう。
溶液中では、彼は0を言った。
これは、明示的にstdinを言って良いでしょう。
>> ここICANON |私は、エコーをやっていることに注意してください。
ICANONはカノニカルモードを意味する別の何かを指しています。
あなたがコマンドラインを入力しているときに何カノニカルモードが意味するものは、通常は
あなたは改行を打つまでで標準では何も処理しません。
だからあなたがgetStringないとき、あなたは改行をヒットしてから、物事の束を入力します。
それはインチ標準に送信されたときだ
これはデフォルトです。
私はあなたを押し、すべての文字今、カノニカルモードをオフにすると
、それはこれらの事を処理するのが遅いですので、通常は悪いの一種である、処理されるものです
それは全体のラインにそれをバッファリングするために良いことだ理由である。
しかし、私は、各文字が処理されるようにしたい
私は私が改行にヒットするのは待ちたくないので、
それはすべての文字を処理する前に、私が入力してきた。
これはカノニカルモードをオフにします。
それは実際に文字を処理するときにこのようなものはただ意味します。
できるだけ早く私はそれらを入力していますので、それらを処理しますが、これはすぐに処理することを意味する。
そして、これは、内標準に自分の設定を更新している関数です。
とTCSA手段は今それを行う。
ストリーム上に現在あるすべてのものが処理されるまで、他のオプションは待機しています。
それは本当に問題ではありません。
ちょうど今hacker_typer_settingsに現在あるものは何でもであることが私の設定を変更します。
私はそれhacker_settings呼ば思われるので、それを変更してみましょう。
hacker_settingsにすべてを変える。
>> 現在、私たちのプログラムの最後に、我々は元に戻したいとしている
現在normal_settingsの内側にあるもの、
これは、単に＆normal_settingsのように起こっています。
私はもともとそれを得るので、私のnormal_settingsのいずれかを変更していないことに注意してください。
それからちょうどそれらを戻すために、私は年末に戻ってそれらを渡す。
これはアップデートしました。オーケー。
>> 内部ここから今私はちょうど時間の関係でコードを説明します。
それは多くのコードではありません。
我々は、ファイルから文字を読み取ってください。我々は、それfを呼んだ。
今、あなたは男fgetcはできますが、どのようにfgetcは、仕事に行くのです
ただ、それはあなたがちょうど読んまたはEOFという文字を返すために起こっており、
どのファイルまたはいくつかのエラーが起こっての終了に対応しています。
我々は、ファイルから1文字を読むことを続けて、ループしている
我々は、読むために文字を使い果たしたまで。
我々はそれをしている間と、我々は、インチ規格から1文字を待つ
毎回あなたは、コマンドラインで何かを入力します
インチ規格から文字で読んだ
その後、putcharは、ただファイルから標準出力にここまで読んでchar型を置くとしている。
あなたは男のputcharことができますが、それは単に標準出力に入れていると、その文字を印刷している。
同じ考え方、また、単にのprintf（ "％c"は、c）を行うことができます。
それが私たちの仕事の大半をするつもりだ。
>> 私たちがやりたいとしている最後のことは、弊社のファイルをfclose関数である。
あなたはfcloseをしない場合、それはメモリリークだ。
我々は、我々が最初に開いたファイルをfcloseをしたい、と私はそれだと思う。
我々はそれを行う場合、私はすでに問題になった。
見てみましょう。
それは何を文句でしたか？
'int'の期待が、引数の型は '構造_IO_FILE *'である。
それが動作するかどうかを我々が表示されます。
C99でのみ許可されて。キャーッ。さて、hacker_typerを作る。
今、私たちは、より有用な説明を取得します。
そう宣言されていない識別子 'normal_settings'の使用。
私はそれnormal_settings呼び出していませんでした。私はそれcurrent_settings呼ばれる。
だから、すべてのことを変更してみましょう。
今の引数を渡す。
私は今のところ、この0を作ってあげる。
オーケー。 。/ hacker_typer cp.c.
私も初めに画面をクリアしていませんでした。
しかし、あなたは画面をクリアする方法を確認するために設定された最後の問題を振り返ることができます。
それはちょうど、いくつかの文字を印刷している
これは私がやりたいことをやっている間に。
オーケー。
そして、これは0の代わりに標準入力であることが必要となった理由を考える
＃0を定義すべき
これがあることを不平を言っている -
私は、ファイル記述子があることを述べたが、その後、また、あなたのFILE *を持っているときに前に、
ファイル記述子は、ただ一つの整数である
のFILE *のに対し、それに関連付けられているものの全体の束を持っています。
我々は標準入力の代わりに0を言う必要がある理由
そのstdinがファイルディスクリプタ0を参照しているものを指すのFI​​LE *です。
そうであってもここまで私はfopenを行うとき（argv [1]を、私は戻ってFILE *を取得しています。
しかし、どこかにそのファイル*に、そのファイルのファイル記述子に対応するものです。
あなたが開いているのmanページを見れば、私はあなたが開いて男3を行う必要があるでしょうと思う - いや -
男2オープン - ええ。
あなたが開いているのためのページを見れば、オープンは、下位レベルのfopenのようなものです
そしてそれは実際のファイル記述子を返している。
fopenはオープンの上に原料の束を行い、
ファイル記述子は、全体のFILE *のポインタを返すことだけを返すのではなく、どの
の内部は私たちの小さなファイル記述子です。
のFILE *の事を指しますので、標準で、
一方0は、それ自体は単なるファイル·ディスクリプタの規格を指します。
>> 質問はありますか？
[笑]はなってしまった。
かしこまりました。我々はおしまいです。 [笑]
>> [CS50.TV]