[Powered by Google Translate] [セクション4 - より快適] [ロブボーデン - ハーバード大学] [これはCS50です。 - CS50.TV] 私たちは、あなたたちがいることを知らなかった場合には、明日クイズを持っています。 それはあなたのクラスで見てきたか、クラスで見てきたことがすべてでは基本的にです。 つまり、彼らは非常に最近のトピックいるにもかかわらず、ポインタが含まれます。 少なくとも、それらの高レベルを理解しておく必要があります。 あなたはクイズのために理解しておく必要がありますクラスでオーバー消えていた何か。 あなたがそれらの質問を持っているなら、あなたは今、それらを求めることができます。 しかし、これはあなたたちが質問をして、非常に学生主導のセッションであることを行っている、 ので、できれば人々は質問があります。 誰もが疑問を持っていますか? はい。 >> [学生]は、ポインタを介して再度行くことはできますか? 私はポインタを介して行くつもりです。 あなたのすべての変数は、必ずしもメモリに住んでいる が、通常はそんな心配はありませんし、あなただけのX + 2とy + 3言う とコンパイラ、物事はあなたのための生活を送っている場所を理解します。 一度ポインタを扱っている、今、あなたは明示的にそれらのメモリアドレスを使用しています。 だから、単一の変数はこれまで、任意の時点で単一のアドレスに住むことになります。 我々はポインタを宣言する場合は、どのような種類は次のようにするつもりですか? 私はポインタpを宣言したいと思います。タイプがどのように見えますか? 【学生】int * pを。 >>うん。だからint型の* pを。 そして、どのように私はそれをxにポイント作るのですか? >> [生徒]アンパサンド。 [ボーデン]だからアンパサンドは文字通りアドレス演算子と呼ばれています。 だから私は言う&Xときには、変数xのメモリアドレスを得ている。 だから今は、ポインタpを持っており、どこでも私のコードで私は、* pを使用することができます または私はxを使用することができ、それはまったく同じものになるでしょう。 (* p)である。これは何をやっている?あの星は何を意味するのか? [学生]それはその時点での値を意味します。 >>うん。 我々はそれを見ればそう、それは図を引き出すために非常に役立つことがあります 場合は、この値が4であることを起こるのx、、のためのメモリの箱のようだ 次に我々は、pのメモリの小さな箱を持っている のでxにp個の点は、私たちはpからxへの矢印を描きます。 だから私たちが言うとき、* pは、我々はpであるボックスに行くと言っている。 スターは、矢印に従っており、その後、右がこのボックスに欲しいものは何でも。 だから私は、* P = 7と言うことができます、そしてそれは、xとその7への変化であるボックスに移動します。 または私は言うことができるint型Z = * P * 2;それは星、星ため混乱し。 1つは、pを間接参照すると、他の星は2を乗じている。 私はちょうど同様にxで* pを交換した可能性に注目してください。 あなたは同じようにそれらを使用することができます。 そして、後に、私は完全に新しいものにpポイントを持つことができます。 私はちょうど言うことができますP = &z; だから今、xにはもはや点をP;それは、zを指しています。 そして、私は* pを行う任意の時間は、それは、zを行うのと同じです。 我々は関数になって始めると、だから、これに関する有益な事です。 何かを指し示すポインタを宣言するために無用のようなものだ その後、あなたはそれを間接参照している するときは、初めに元の変数を使用することもできました。 しかし、あなたが関数に入るとき - それでは、我々はいくつかの関数は、int fooを持っているとしましょう それがポインタを取り、ちょうど* P = 6をします; 我々はスワップと前に見たように、あなたは効果的なスワップと独立した機能を行うことはできません Cのすべてが常に値渡しされるため、整数だけを通過させることによって。 あなたは値渡ししているポインタを渡している場合でも。 それはちょうどので、それらの値がメモリアドレスであることを起こる。 だから私は、foo(p)を言うとき、私は関数fooへのポインタを渡している とfooは* P = 6をやっている。 だから内部のその関数の場合、* pがまだXに相当し、 それは、その関数内のスコープ付きではないので、私はその関数内でxを使用することはできません。 だから* P = 6は、私は別の関数からローカル変数にアクセスすることができる唯一の​​方法です。 または、よく、ポインタが、私は別の関数からローカル変数にアクセスできる唯一の​​方法です。 [学生] Let 'sは、あなたがポインタを返すしたいとしましょう​​。どのように正確にそれを行うのですか? [ボーデンは】int y = 3のような何かのようにポインタを返します。リターン&Y? >> [生徒]うん。 [ボーデン]オーケー。あなたはこれを行うべきではありません。これはまずいです。 私はあなたが、このメモリーの全体図を見始め、これらの講義のスライドで見たと思う ここまでは、メモリアドレス0を持っている場所 上下ここでは32にメモリアドレス4ライブまたは2を持っています。 だから、あなたはいくつかのものといくつかのものを持っていると、あなたはあなたのスタックを持っている とあなたがちょうど育っについて勉強し始めたあなたのヒープを持っている。 [学生]はスタックの上ヒープはありませんか? うん。ヒープが上にあるではないですか? >> [生徒]まあ、彼が上に0を入れます。 [学生]ああ、彼は上に0を入れます。 >> [生徒]ああ、大丈夫。 免責事項:どこでもCS50とあなたはこのようにそれを参照するつもりです。 >> [生徒]オーケー。 それは、あなたが最初のスタックを見ている時というだけです あなたが互いの上に物事を考えるスタッキングスタックを考えるときが好きです。 だから我々は、スタック、スタック、通常と同じように育っているので、周りにこれを反転する傾向がある 代わりに、スタックの下にぶら下がっている。 >> [生徒]ヒープは、技術的に、しかし、あまりにも育ちませんか? それはあなたが成長することによって何を意味するかに依存します。 スタックとヒープは常に反対方向に成長します。 スタックには、常にそれが育っているという意味で育っている 上位のメモリアドレス、およびヒープがダウンして成長している方に という点では、下位のメモリアドレスに向かって成長している。 だからトップは0であり、底はハイメモリアドレスです。 彼らはちょうど反対方向に、成長している両方。 [学生]あなたが底にスタックを置くと言ったので、私はちょうどそれを意味 スタック用にヒープの先頭から開始するので、それは、より直感的なようですので、 ヒープは、あまりにも、それ自体の上にそうthat'sだ - >>うん。 また、より多くのようにアップすると大きいが、スタックの成長としてヒープのだと思います。 だからスタックは、我々は一種の育って見せたいものです。 しかし、どこでも、あなたがそうでなければ見ては、上部のアドレス0を表示しようとしている そして下部に最高のメモリアドレスが、これはメモリの通常のビューです。 あなたは疑問を持っていますか? [学生]あなたは私たちにヒープについての詳細を教えていただけますか? うん。私は2番目のそれに得るでしょう。 まず、&yを返す理由に戻ってことは悪いことでは、 スタックには、すべての関数を表すスタックフレームの束を持っている これらは呼ばれています。 以前の事を無視だから、あなたのスタックのトップは常にメイン機能であることを行っている 呼び出されている最初の関数だからです。 そして、あなたは別の関数を呼び出すときに、スタックはダウン成長しようとしている。 私はいくつかの機能は、fooを呼び出すと、それはそれ自身のスタックフレームを取得するのであれば、 それが、バーをいくつかの関数を呼び出すことはできますが、独自のスタックフレームを取得します。 と、バーは再帰的であること、それは自分自身を呼び出すことができます などバーの2回目の呼び出しでは独自のスタックフレームを取得しようとしていること。 そして、これらのスタックフレームに入りますので、何のローカル変数のすべてである その関数の引数のすべて - この関数のローカルスコープされているすべてのものはこれらのスタックフレームに移動します。 だから私はバーのようなものが関数であると言った時を意味し、 私はちょうど整数を宣言し、その整数へのポインタを返すつもりです。 だからyはどこに住んでるんだろう? [学生] yはバーに住んでいます。 >> [ボーデン]うん。 どこかでメモリのこの小さな広場にそれでyを持っているのlittlerの正方形である。 私が戻るとyと、私はメモリのこの小さなブロックへのポインタを返すよ。 しかし、その後、関数から戻るときは、そのスタックフレームがスタックからポップされます。 それがスタックと呼ば​​れる理由だ。 あなたはそれが何であるか知っていればそれは、スタックデータ構造のようなものだ。 あるいはトレーのスタックのように常に一例であって、 メインが下に行くつもりされている場合、あなたが最初に呼び出す関数は、その上に行くつもりです あなたが呼ばれてきたすべての関数から戻るまで、あなたがメインに戻って取得することはできません それはそれの上に置かれています。 あなたは&Yを返しやった場合は、[学生]だから、その値は、予告なしに変更することがあります。 はい、it's - >> [生徒]それは上書きされる可能性があります。 >>うん。 それは完全です - あなたがしようとした場合 - それがポインタを返すだので、これはまた、int *のバーであろう ので、その戻り値の型はint *である。 この関数の戻り値を使用しようとするなら、それは未定義の動作です そのポインタが不正なメモリを指しているからです。 >> [生徒]オーケー。 だからどのような場合、たとえば、あなたが宣言したint型* Y =のmalloc(sizeof(int))を? よろしい。はい。 [学生]私たちはごみ箱に物事をドラッグしたときに我々はどのように語ら それらは実際に消去していない、我々はちょうど彼らのポインタを失う。 したがって、この場合、我々は実際にそれがメモリに残っていた値を消去するか、あるのですか? ほとんどの部分については、それはまだそこになるだろう。 しかし、ここでは我々はいくつかの他の機能、bazを呼び出すことが起こるとしましょう​​。 バズは、ここに独自のスタックフレームを取得する予定です。 それは、このようなもののすべてを上書きすることになるだろう その後は、後であなたが前に持ってポインタを試してみて、使用している場合、 それが同じ値であることを行っていない。 それはあなたが関数bazを呼ばれるという理由だけで変​​更されたために起こっている。 [学生]は、しかし、我々は、我々はまだ3を取得することになりませんでした? [ボーデン]十中八九、あなたはそうするでしょう。 しかし、あなたはそれに頼ることはできません。 Cは単に未定義の動作を言います。 [学生]ああ、それはありません。オーケー。 mallocが使用中で出番ですから、ポインタを返すようにしたいときに、これはです。 私は実際に書いているだけmalloc関数を返す(3 * sizeof(int))を。 我々は、第二​​に、よりmallocの上に行くだろうが、mallocのアイデアはあなたのすべてのローカル変数 常にスタック上に行く。 mallocされているものは、ヒープ上に行き、それは永遠に、常にヒープ上になります それを明示的に解放するまで。 だから、これはときにmallocを何かを、それは関数が戻った後に生き残るために起こっていることを意味します。 プログラムの実行を停止した後、[学生]それが生き残るだろうか?ナンバー>> わかりましたので、それはプログラムがすべての方法が実行完了するまでそこになるだろう。 >>はい。 我々は、プログラムの実行が停止したときに何が起こるかの詳細は上に行くことができます。 あなたは私を思い出させる必要があるかもしれませんが、それはまったく別のものです。 [学生]だから、malloc関数はポインタを作成しますか? >>うん。 malloc関数 - >> [学生]私はmalloc関数は、ポインタが使用できるメモリのブロックを指定すると思います。 [ボーデン]私は再びその図が欲しい。しかし>> [生徒]だからこの機能は動作しますが、? [学生]ええ、mallocが使用できるメモリのブロックを指定し、 そしてそれはそのメモリの最初のブロックのアドレスを返します。 [ボーデン]うん。だからときに、malloc関数は、メモリの一部のブロックをつかんでいる それはヒープで現在です。 ヒープが小さすぎる場合は、ヒープだけで育つために起こっている、そしてそれはこの方向に生えています。 それでは、ヒープが小さすぎると言うことができます。 それは少し成長し、ちょうど育ったこのブロックへのポインタを返すようなのです。 もし無料のものには、ヒープ内のより多くの部屋を作っているときは、 ので、その後のmallocを呼び出すには、以前に解放されたことがそのメモリを再利用することができます。 mallocとfreeについて重要なことは、それはあなたに完全な制御を与えるということです これらのメモリ·ブロックの生涯。 グローバル変数は、常に生きている。 ローカル変数は、その有効範囲内で生きている。 できるだけ早くあなたが括弧を過ぎて行くように、ローカル変数は死んでいる。 あなたはそれが生きているようにしたいときにmallocされたメモリは生きている あなたは解放されるということを教えたときに、その後リリースされています。 それらは本当に、実際にメモリのわずか3種類があります。 スタックで自動メモリ管理は、ありません。 物事が自動的にあなたのために起こる。 あなたがint xを言うとき、メモリはint xに対して割り当てられている。 xがスコープの外に出ると、メモリがxに再利用されます。 その後、動的なメモリ管理、malloc関数とは何かですが、そこ あなたがコントロールを持っているときにです。 あなたは、動的にメモリを割り当てることとすべきでないかを決める。 そして、それは永遠に生きることを意味し、静的あり これは、グローバル変数が何であるかです。 彼らは、メモリ内でだけ常にね。 質問はありますか? [学生]は、あなただけの中括弧を使ってブロックを定義できます しかし、if文またはそのようなwhile文か何かを持っている持っていない? これは、関数のようにブロックを定義することができますが、それはあまりにも中括弧を持っています。 [学生]だからあなたは自分のコードの中で中括弧のランダムなペアのように持つことができません ローカル変数を持っている? >>はい、できます。 int型のバーの内部では{int型のy = 3;}可能性があります。 それはここにいることになっている。 しかし、それは完全にint型のyの範囲を定義します。 その第二波括弧の後、yはもう使用することはできません。 とはいえ、あなたはそれを行うことはほとんどない。 は、プログラムが終了したときに何が起こるかに戻りましょう 我々だけで物事を簡単にするために与えるという誤解/ハーフ嘘の種類があります。 私たちはあなたを伝えることは、メモリを割り当てるとき あなたは、その変数のためにRAMの一部のチャンクを割り当てています。 しかし、あなたは本当に直接プログラムで、これまでのRAMに触れていない。 あなたがそれについて考える場合、どのように描きました - あなたは、GDBにおける通過する場合と、実際には、同じものを見ます。 関係なく、あなたのプログラムまたは現在実行されているプログラムを実行する回数の スタックには、常に開始する予定です - あなたは、常にアドレスoxbffff何かを周りの変数を参照しようとしている。 それはその地域のどこかに通常です。 しかし、どのように2つのプログラム可能であれば同じメモリへのポインタを持つことができますか? [学生] oxbfffがRAM上にあることになっている場所のいくつかの任意の指定があります それは実際に関数が呼び出されたときに応じて異なる場所にすることができます。 うん。この用語は、仮想メモリです。 アイデアは、あなたのコンピュータ上で実行されている一つ一つのプログラムが、その一つ一つのプロセスである 独自のを持っています - 完全に独立したアド​​レス空間 - レッツは32ビットを前提としています。 これは、アドレス空間です。 それは、使用するための独自の完全に独立した4ギガバイトを持っています。 ですから、2つのプログラムを同時に実行した場合、このプログラムは、自身に4ギガバイトを見 このプログラムは、自身に4ギガバイトを見 そしてそれは、このプログラムのためにポインタを間接参照することは不可能だ そして、このプログラムからのメモリで終わる。 そして、どのような仮想メモリがあると、プロセスのアドレス空間からマッピングです RAM上で実際のものに。 だから、それを知るために、ご使用のオペレーティング·システムにかかっている、 ねえ、ときに、この男は本当に意味ポインタ逆参照oxbfffを、 彼はRAMバイト1000、望んでいる 一方、このプログラムを逆参照のoxbfffば、彼は本当にRAMバイト万を望んでいる。 彼らは遠く離れて勝手にすることができます。 これは、単一のプロセスのアドレス空間内であっても物事の真実である。 のようにそれ自体にすべての4ギガバイトが表示されますが、言ってみましょう - [学生]一つ一つのプロセスをしない - Let 'sは、あなたがRAMしか4ギガバイトを搭載したコンピュータを持っていると言う。 一つ一つのプロセスは全体4ギガバイトを参照していますか? >>はい。 しかし、それは見て4ギガバイトは嘘です。 それはちょうど、それは、他のプロセスが存在することを知っていないので、それがすべてこのメモリを持っていると思っている。 それは実際に必要なだけ多くのメモリを使用します。 オペレーティング·システムは、このプロセスにRAMを提供するつもりされていません それは、この地域全体の任意のメモリを使用していない場合。 それはそれに、その領域のためのメモリを与えることはないだろう。 しかし、アイデアはある - 私は考えるようにしようとしている - 私はアナロジーを考えることはできません。 アナロジーは難しいです。 仮想メモリの問題の一つまたはそれが解決だことの一つ プロセスが互いに完全に気づかなければならないということです。 そしてあなたは、それだけで、任意のポインタ逆参照する任意のプログラムを書くことができます ただ、*(ox1234)と言うプログラムを書きたい そしてその逆参照のメモリアドレス1234。 しかし、それは次に何1234手段を翻訳するために、オペレーティング·システムにお任せします。 もしそうなら1234は、このプロセスのために有効なメモリアドレスであることを起こる それはスタックまたは何か上にあるように、これはそのメモリアドレスの値を返します 限りプロセスが知っている。 しかし、それが土地を起こるように1234は、有効なアドレスではない場合、 スタックを超えていますここでメモリのいくつかの小さな作品とヒープを超え あなたがセグメンテーション違反のようなものを取得するときに、あなたが本当にそれを使用していないが、その後、それはだ あなたは触れてはならないことを記憶に触れているので。 また、これは本当です - 32ビットシステムで、32ビットを使用すると、メモリアドレスを定義するには、32ビットを持っていることを意味します。 または4バイト - 32ビットは8バイトなので、ポインタは8バイトである理由です。 ポインタは4バイトです。 ですからoxbfffffようなポインタを参照するとき、それはです - あなただけの、任意のポインタを作成することができます任意のプログラム内 どこox0から牛8 f'sへ - FFFFFFFF。 [学生]あなたは彼らが4バイトだと言ったではありませんか>>うん。 [学生]それから各バイトがあります - >> [ボーデン] 16進数。 16進数 - 5、6、7、8。ポインタので、常に16進数で表示するつもりだ。 それは、我々はポインタを分類する方法だけです。 進数の各2桁が1バイトです。 だから4バイトの8桁の16進数があるように起こっている。 だから、32ビットシステム上のすべての単一のポインタは4バイトであることを行っている それはあなたのプロセスでは、任意の4バイトを構築することができることを意味します そして、それのポインタを作る これは、限り、それは認識してだとして、それがメモリの32バイト全体の2に対処できることを意味します。 それは実際にへのアクセス権を持っていなくても、 お使いのコンピュータにのみ512メガバイトを持っている場合でも、それはそれは多くのメモリを持っていると考えている。 およびオペレーティング·システムはそれだけで、あなたが実際に必要なものを割り当てるように十分スマートです。 4ライブ:それはちょうど、ああ、新しいプロセスを行っておりません。 うん。 >> [生徒] oxはどういう意味ですか?なぜあなたはそれを書くのですか? それはちょうど進のためのシンボルです。 あなたは牛と番号の開始を参照してくださいすると、連続したものは16進数です。 [学生]あなたは、プログラムの終了時に何が起こるかについて説明しました。 >>はい。 どのようなプログラムが終了したときに起こることは、オペレーティング·システムです ただ消去し、それがこれらのアドレスを持っていることをマッピングし、それだ。 オペレーティングシステムは今ちょうど使用する別のプログラムにそのメモリを与えることができます。 [学生]オーケー。 ですから、ヒープまたはスタックまたはグローバル変数か何かで何かを割り当てるときに、 それらはすべて同じようにすぐにプログラムが終了すると消えてしまう オペレーティングシステムは現在、他のプロセスにそのメモリを与えるために自由であるためです。 [学生]で記述された値は、おそらくまだあるにもかかわらず? >>うん。 値はまだありそうです。 それはちょうどそれは、それらを取得することは困難になるだろうだ。 それが削除されたファイルを取得するよりも、それは彼らを得るためにはるかに困難だ 削除されたファイルの種類のは、長い時間のためにそこに座って、ハードドライブがはるかに大きいからです。 だからそれはメモリのさまざまな部分を上書きするために起こっている それは、そのファイルがにあったことをメモリチャンクを上書きする起こる前。 しかし、メインメモリ、RAM、かなり速くを通してあなたのサイクルを、 ので、非常に急速に上書きになるだろう。 このまたは他の何かについての質問? [学生]私は別のトピックについての質問があります。オーケー。>> 誰もがこれについて質問がありますか? オーケー。別の話題。 >> [生徒]オーケー。 私は、模擬試験の一部を通過した そのうちの一つには、sizeofについて話していた それは変数の型を返すか、または異なっていること、および値。 >>はい。 そしてそれは、intとlong両方のリターン4の両方と言ったので、彼らは両方とも4バイト長だ。 intとlongの間に違いはありますか、またはそれは同じことですか? はい、違いがあります。 C標準 - 私はおそらく台無しにするつもりです。 C標準では、C言語が何であるかをCの公式ドキュメントを同様です これは、言っていることです。 だから、C標準では、単にcharは永遠に、常に1バイトだろう、と話している。 後のすべて - 短期は常にちょうどより大きいまたはcharに等しいものとして定義されています。 これは厳密にはより大きいが、肯定的ではないかもしれません。 intはちょうどより大きいか、またはショートに等しいものとして定義されています。 と長いだけより大きいまたはintに等しいものとして定義されています。 とlong longより大きいか、または長いと等しくなります。 だから、C標準で定義されて唯一のものは、すべてのものの相対的な順序です。 物事は取ることを実際のメモリ量は、最大実装に一般的であり、 しかし、それはかなりよく、この時点で定義されている。 >> [生徒]オーケー。 だからパンツはほとんど常に2バイトになるだろうしている。 int型はほとんど常に4バイトになるだろうしている。 ロングlong型は、ほとんど常に8バイトになるだろうしている。 そして、それはあなたが32ビットまたは64ビットのシステムを使用しているかどうかに依存し、待ち望んでいます。 だから長くは、システムのタイプに対応する予定です。 あなたがアプライアンスのように32ビットシステムを使用している場合は、それが4バイトになるだろう。 あなたは、最近のコンピュータの多くのように64ビットを使用している場合、それは8バイトになるだろう。 int型はほとんど常にこの時点では4バイトです。 ロングlong型は、ほとんど常に8バイトです。 過去では、intは2バイトになるように使用されます。 しかし、これは完全に超え、それに等しいこれらの関係のすべてを満たしていることがわかります。 だから長い完全に整数と同じサイズであることが許され、 そしてそれはまた長い長いと同じサイズになるように許可されている。 そして、それはちょうどので、システムの99.999%で、それが等しくなるように起こっていることであることを起こる intやlong longのいずれか。それはちょうど32ビットまたは64ビットに依存します。 >> [生徒]オーケー。 山車では、どのように小数点がビットに関して指定されている? バイナリとして好きですか? >>うん。 あなたはCS50のためにそれを知っている必要はありません。 あなたも61にすることを学ぶことはありません。 あなたはどのコースにも、本当に学ぶことはありません。 それはただの表現だ。 私は正確なビット割り当てを忘れる。 浮動小数点の考え方は、表現するために特定のビット数を割り当てることである - 基本的に、すべてが科学表記法である。 それで、あなたは1.2345のように、数そのものを表すために特定のビット数を割り当てる。 私は5より大きい桁の数を表すことはできません。 それは次のようになる傾向があるように、あなたはまた、特定のビット数を割り当てる あなただけが持つことができる最大の指数だと同じように特定の数、に上がることができます そしてあなただけの、特定の指数にまで行くことができます そのようにあなたが持つことができる最小の指数です。 私はビットはこれらの値のすべてに割り当てられている正確な方法を、覚えていない しかし、特定のビット数は、1.2345に専念しています ビットの別の特定の数は、指数に専念しています そして、それはある程度の大きさの指数を表すためだけに可能です。 [学生]そして二重?それは余分な長いフロートのようなものです? >>うん。 それは今あなたが8バイトの代わりに4バイトを使用している除くfloatと同じことだ。 今、あなたは、9桁または10桁の数字を使用することができるでしょう これは300の代わりに100まで行くことができるようになります。 >> [生徒]オーケー。 や山車も4バイトです。 >>はい。 さて、再び、それはおそらく、一般的な実装上の全体的な依存 しかしフロートは4バイト、doubleは8です。 彼らは二重フロートの大きさなので、ダブルはダブルと呼ばれています。 [学生]オーケー。そしてそこには、二倍にされますか? >>まったくありません。 私は思う - 長いlong型と同様>> [生徒]? >>うん。私はそうは思わない。はい。 [学生]昨年のテストでは、main関数についての質問があった あなたのプログラムの一部にならなくて。 その答えは、あなたのプログラムの一部である必要はありませんということでした。 どんな状況で?それは私が見たものだ。 [ボーデン]それはだ - >> [生徒]何の状況? あなたは問題を持っていますか? >> [生徒]ええ、私は間違いなくそれを引き出すことができます。 それは技術的には、なくてもかまいませんが、基本的にはなるだろう。 [学生]私は別の年の上の1つを見た。 これは、TrueまたはFalseのようだった:有効 - >>ああ、cファイル。? [学生]任意のCファイルが持っている必要があります - [一度に話すの両方 - 不明朗] オーケー。だからそれは別だ。 cファイルはただの関数を含める必要があります。 あなたは、マシンコードにバイナリをファイルをコンパイルすることができ、何でも、 まだそれは実行可能であることなし。 有効な実行は、main関数を持っている必要があります。 あなたは、100 1ファイル内の関数はありませんが、メインを書くことができます して、その下にバイナリにコンパイル、 その後は本体のみ持っていますが、それはこれらの機能の束を呼び出して別のファイルを書き込む こっちにこのバイナリファイルに保存されます。 実行可​​能ファイルを作っているときなど、それはリンカが何をするかだ それは実行可能ファイルにこれらの2つのバイナリファイルを結合しています。 だからcファイルはまったくmain関数を持っている必要はありません。 と大きなコードベース上では、cファイルと1つの主要なファイルの数千が表示されます。 多くの質問? [学生]別の質問がありました。 これは、makeがコンパイラであると述べた。真か偽か と答えが偽であった、そしてそれはClangのようではありませんなぜ私が理解した。 しかし、我々はそれがない場合は、確認を何というでしょうか? メイクは基本的にある - 私はそれを呼び出すかを正確に確認することができます。 しかし、それだけでコマンドを実行します。 ことを確認します。 私は、このプルアップすることができます。うん。 ああ、うん。またことがないことを確認してください。 これは、makeユーティリティの目的は自動的に決定することであると言う 大規模なプログラムの中には、再コンパイルする必要があるもの し、それらをコンパイルするためのコマンドを発行します。 あなたは絶対に巨大なファイルを作ることができます。 メイクは、私たちが前に言ったように、ファイルのタイムスタンプを見て、 あなたがダウンして、個々のファイルをコンパイルすることができます、あなたがリンカに到達するまで、そうではありません 彼らは、実行可能ファイルに一緒に入れているという。 ですから、10種類のファイルがあり、あなたがそれらの1に変更を加えた場合、 次に何を作るには何をしようとしていると、1ファイルだけを再コンパイルすることである その後一緒にすべてを再リンクします。 しかし、それはそれよりはるかに愚かだ。 それは完全にそれはそれは何をすべきかということを定義するのはあなた次第です。 これはデフォルトでは、このタイムスタンプのものを認識する能力を持っている しかし、あなたは何もするmakeファイルを書き込むことができます。 あなたはそれだけで別のディレクトリにCDの作る入力したときになるように作るファイルを書き込むことができます。 私はイライラしました私はタックすべて私のアプライアンスの内側にあるため そして私はMacからPDFを表示。 だから私は、Finderに行くと私は移動を行うことができますが、サーバーへの接続、 と私はサーバーへの接続は私のアプライアンスであり、その後、私は、PDFを開く それは、LaTeXでコンパイルされます。 毎回私はPDFファイルをリフレッシュする必要がありましたので、私は不満になっていた、 私はそれがアクセスできる特定のディレクトリにコピーする必要がありました そしてそれは迷惑になっていた。 だから代わりに私はあなたがそれは、物事を行う方法を定義する必要がmakeファイルを書いた。 どのようにこのようにすると、PDFラテックスである。 ただ、他のmakeファイルのように - または私はあなたが作るファイルを見ていないと思いますが、 しかし、我々は、アプライアンスにだけ言うグローバルmakeファイルを持っている あなたがCファイルをコンパイルしている場合、Clangのを使用しています。 ので、ここで私のmakeファイルで私が言わせること、 このファイルは、PDF LaTeXでコンパイルするつもりだ。 そしてそれはコンパイルをやってPDFをLaTeXのだ。 makeはコンパイルされていません。それはちょうど私が指定された順序でこれらのコマンドを実行している。 だから、それは私はそれがにコピーしたいディレクトリにコピーし、PDF形式にLaTeXを、それを実行します それは、CDのディレクトリに、他のことを行っていて、 しかし、それはないすべては、ときに、ファイルの変更を認識している それが変更された場合と、それはそれが実行するはずのコマンドを実行します ときに、ファイルが変更されます。 >> [生徒]オーケー。 私はグローバルなメークファイルは、私はそれをチェックアウトするためのものか分からない。 その他の質問は?過去から何クイズ?任意のポインタもの? のようなポインタを持つ微妙なものがあります - 私はそれにクイズの質問を見つけることができるようにするつもりはない - しかし、ちょうどこのようなもののような。 私が言うとき、あなたがそれを理解していることを確認します。int * x * yを - これは、まさにここに何もないですが、私は推測する。 しかし、のような* x * yを、それらがスタック上にある2つの変数があります。 私が言うと、x =のmalloc(sizeof(int))を、xは、まだスタック上の変数である malloc関数は、ヒープ内でいくつかのブロックであり、我々は、ヒープにX点を抱えている。 ヒープにスタックポイントで何かそう。 たびにmallocの何かを、あなたは必然的にポインタの中にそれを保存している。 そのポインタがスタック上にあるように、mallocされたブロックは、ヒープ上にある。 多くの人が混乱と言うint型* X = malloc関数であり、xは、ヒープ上にある。 xが指す何号は、ヒープ上にある。 何らかの理由であなたは、xがグローバル変数でなければしていない限り、X自体は、スタック上にある その場合、それはメモリの別の領域にあることを起こる。 を追跡するので、これらのボックスと矢印の図は、クイズのために非常によく見られます。 それはクイズ0ではない場合、または、それはクイズ1日になるでしょう。 あなたはこれらのすべては、コンパイルの手順を知っておくべきこと あなたはそれらの質問に答えなければならなかったので。はい。 [学生]は、我々は、それらのステップ上に行くでした - >>確かに。 手順とコンパイルする前に、我々は、前処理を持た コンパイル、アセンブル、リンクします。 前処理。それは何をしますか? それはで最も簡単なステップです - まあ、しないように - それはそれは明白であるべきという意味ではありませんが、それは簡単なステップです。 あなたたちはそれを自分自身を実装することができます。うん。 [学生]は、あなたの持っているものを取るこのように含まれており、それがコピーしても定義されています。 それは、#includeのようなものを探して#define それらが実際に何を意味するのか、それだけでコピーとペースト。 ですから、#cs50.hを含めると言うとき、プリプロセッサはcs50.hをコピー&ペーストされている その行に。 あなたは第4位であるxを定義すると言う場合、プリプロセッサは、プログラム全体を通過 及び4 xのすべてのインスタンスを置き換えます。 だから、プリプロセッサは、有効なCファイルを受け取り、有効なCファイルを出力 どこのものがコピーされ、貼り付けられています。 だから今コンパイル。それは何をしますか? [学生]これはC言語からバイナリへ行く。 [ボーデン]それはバイナリにすべての道を行くことはありません。 マシンコードにして、[学生]? >>それはマシンコードではありません。 [学生]総会は? >>アセンブリ。 それはCコードへのすべての道を行く前に、それは、国会に行く ほとんどの言語ではこのような何かを。 任意の高水準言語を選んで、あなたはそれをコンパイルするつもりなら、 それはステップでコンパイルすることがありそうです。 最初にそれがCにPythonをコンパイルしようとしている、それは、国会にCをコンパイルするために起こっている [アセンブリをバイナリに変換されるとしている。 だからコンパイルは、Cからアセンブリにそれを持って来るために起こっている。 コンパイルという言葉は、通常より高いレベルからそれを持って来ることを意味し 低レベルのプログラミング言語へ。 ですから、これは高レベルの言語で始まるコンパイルで唯一のステップです と低水準言語で終わる、とステップはコンパイルと呼ばれる理由です。 コンパイル時に、[学生]は、あなたが#includeをやったと言ってみましょうcs50.h. コンパイラは、そこにある関数と同様に、cs50.hを再コンパイルします そして、同様にそのアセンブリコードに変換 またはそれは、事前に組み立ててきている何かをコピーして貼り付けるのでしょうか? cs50.hはかなり議会で終わることは決してありません。 関数プロトタイプや物事のようなものはあなたが注意するだけのためのものです。 これは、コンパイラがあなたのようなものが関数を呼び出して確認することが保証され 右の戻り値の型、右引数やものに。 だからcs50.hはファイルに前処理されます、そして、次に、それはコンパイルしているとき それはすべてが正しく呼び出されていることを確認して落札後は基本的に捨てている。 cs50.hから分離されているCS50ライブラリで定義されているが、関数、 それらは別々にコンパイルされません。 それは実際にリンクステップで降りてくるの​​で、我々は、第二​​に、それを取得します。 しかし、最初に、組み立ては何ですか? [学生]バイナリへのアセンブリ? >>うん。 組み立て。 組立はかなりの純粋なバイナリ変換したものですので、我々はそれがコンパイル呼び出すことはありません。 アセンブリからバイナリへ行くにはほとんどロジックがあります。 それはちょうどテーブルの検索のようなものだ、ああ、私たちはこの命令を持っています。 それはバイナリ01110に対応しています。 一般的に出力がされています。oファイルをアセンブルするファイルそう。 と。oファイルは、我々が前に言っていたものですが、 どのファイルがmain関数を持っている必要はありません。 それは有効なCのファイルだとして任意のファイルであればoファイルにコンパイルすることができます。 それは、Oにコンパイルすることができます。 さて、リンクは実際の束をもたらすものoファイルであり、実行可能ファイルにそれらをもたらす。 それで何のリンクがないと、あなたは。oファイルとしてCS50ライブラリと考えることができています。 それは、すでにコンパイルされたバイナリファイルです。 それで、あなたはあなたのファイルをコンパイルするときに、GetStringメソッド呼び出しあなたのhello.cを、 hello.oにコンパイルhello.cを取得し、 hello.oはバイナリになりました。 、それは、GetStringを使用しているので、cs50.oの所へ行く必要がある とリンカはそれらを一緒にsmooshes、このファイルにGetStringをコピー それが必要なすべての機能を持って実行可能で出てくる。 だからcs50.oは実際にOファイルではありませんが、それは根本的な違いがないことを十分に近いです。 だからリンクは一緒にファイルの束を持って来る それは別に私が使用する必要があるすべての関数が含まれている と、実際に実行され、実行可能ファイルを作成します。 そしてそうそれは我々が前に言っていたものでもあり あなたは1000年を持つことができる場所。cファイルを、あなたは、それらすべてをコンパイルしますoファイルは、 おそらく、しばらく時間がかかるとなる、その後は1に変更します。cファイル。 あなたは、その1 cファイルをコンパイルしてから、他のすべてを再リンクする必要があり、 戻って一緒にすべてのものをリンクします。 我々はlcs50を書くリンクしている[学生]? うん、いわゆるlcs50。あなたがそのライブラリにリンクする必要があることをリンカにそのフラグ信号。 質問はありますか? 我々は最初の講義で、その5秒以外のバイナリを検討してきました? 私はそうは思わない。 あなたは、私たちが見てきましたことは大きなOSのすべてを知っている必要があり、 私たちはあなたに関数を与えた場合、あなたは、することができるはず あなたはそれが大体、大きなOだと言うことができるはずです。またはよく、ビッグOは荒れています。 だからあなたは、物事の同じ数をループネストされたforループが表示される場合は、 >> [学生]はn乗 - int型J、J >それが二乗さnする傾向がある。 あなたが三重にネストされている場合、それはn乗になる傾向がある。 だから、そういったことは、あなたはすぐに指摘することができるはずです。 あなたは挿入ソートとバブルソートを知っていて、ソートし、それらのすべてをマージする必要があります。 彼らはそれらのNの2乗とnログnとすべてのことである理由を理解することは簡単だ 私たちは基本的にあなたを与えた1年はクイズであったと思うので、 バブルソートの実装と "この関数の実行時間は何ですか"と言った。 あなたはバブルソートのようにそれを認識するようなら、あなたはすぐにnの二乗と言うことができます。 しかし、あなたはそれを見れば、あなたも、それはバブルソートを実現する必要はありません。 あなただけの、これはこれとこれをやっていると言うことができます。これは乗nです。 [学生]は、あなたが思い付くことができます任意のタフな例がある 考え出すの同様のアイデアが好きですか? 私たちはあなたに何か厳しい例を与えるとは思わない。 バブルソートの事は、私たちが行くだろうと同じくらい厳しいです さらには限り、あなたは理解するようにして、配列を反復処理していること、という 乗nの何かであることを行っている配列の各要素に対して。 我々が持っているまさにここのような一般的な質問があります - ああ。 先日、ダグは私は配列をソートするアルゴリズムを考案した "と主張 "O(log n)の時間!のn数の" だから我々は不可能だという方法を知っていますか? [聞き取れない生徒の応答] >>うん。 少なくとも、あなたは、配列の各要素をタッチする必要があります ので、それはの配列をソートすることは不可能だ - すべてがソートされていないためである場合は、アレイ内のすべてのものに触れることになるだろう、 そのためには、nのO未満でそれを行うことは不可能です。 [学生]あなたは私たちにn個のOでそれを行うことができるということの例を示した あなたは多くのメモリを使用する場合。 >>うん。 とthat's - 私は何that's忘れる - それはソートをカウントされていますか? うーん。つまり、整数ソートアルゴリズムです。 私は先週、覚えていない可能性があること、このために特別な名前を探していました。 うん。これらは、nの大きなOで物事を達成することができます種類のタイプがあります。 しかし、あなたが特定の番号だけに整数を使用することができますような制限があります。 プラスあなたは何that'sをソートしようとしている場合 - アレイは012、-12、151、400万であれば、 その後、一つの要素が完全に全体のソートを台無しにしようとしていること。 質問はありますか? [学生]再帰的な関数を持っている、それだけで再帰呼び出しを行った場合 末尾再帰のreturn文は、内 となるように、実行時に多くのメモリを使用することはありません 反復解法として、または、それは、少なくとも同程度のメモリを使うのでしょうか? [ボーデン]はい。 それはおそらく本当に多少遅くなることはなくなります。 末尾再帰はかなり良いです。 スタックフレームで再び見ると、みましょう我々はメイン持っていると言う そして我々はintバー(int型x)、または何かを持っている。 これは完全な再帰関数ではありませんが、リターンバー(X - 1)。 だから明らかに、これは欠陥があります。あなたは、ベースケースとスタッフを必要としています。 しかし、ここでの考え方は、これは末尾再帰であるということです これは、そのスタックフレームを得るために起こっているときに、メイン通話バーを意味します。 このスタックフレーム内のメモリの小さなブロックがあるように起こっている それはその引数xに対応しています。 そしてそうしてみましょうすると、メインのバー(100)を呼び出すために起こると言う。 だから、xは100として開始しようとしている。 コンパイラは、これは末尾再帰関数であることを認識した場合、 その後バーはバーへの再帰呼び出しを行ったときに、 代わりに、主に成長しているスタックがどこから始まるかされて新しいスタックフレームを作る、 最終的にはヒープに実行され、その後、セグメンテーションフォルトを取得 メモリは、衝突開始されるため。 代わりに、独自のスタックフレームを作るのはそう、それは、実現することができます ねえ、私は本当に、このスタックフレームに戻ってくる必要はありません ので、代わりに私はちょうど99を使用すると、この引数を交換し、バーをすべてやり直すでしょう。 そして、それは再びそれを行うことになり、それがリターンバー(X - 1)に達すると、 その代わりに新しいスタックフレームを作るのは、それだけで98と現在の引数に置き換えられます その後バーの冒頭にジャンプして戻る。 これらの操作は、スタック上でその1つの値を交換すると最初に戻ってジャンプし、 かなり効率的です。 だからだけではなく、これは反復される別個の関数と同じようにメモリ使用量です あなただけの1スタックフレームを使用していますが、マイナス面を被っていないため 関数を呼び出すする必要がなくなります。 それはすべてこの設定を行う必要があるため、関数の呼び出しは、多少高価になることができます とティアダウンおよびすべてのこのようなもの。 だから、これは末尾再帰は良いです。 [学生]なぜそれは、新しいステップを作成しないのですか? それが実現しているので、その必要はありません。 バーへの呼び出しは単に再帰呼び出しを返しています。 だから、戻り値を使って何かする必要はありません。 それだけで、すぐにそれを返すことになるだろう。 だから、それだけで、独自の引数を交換して、最初からやり直しになるだろう。 そしてまた、あなたは末尾再帰バージョンをお持ちでない場合は、 その後、このバーが返すすべてのこれらのバーを取得 それはバーがすぐに戻りますが、次に、このいずれかにその値を返す必要があります そしてそれはこの1つにその値を返し、それだけですぐに戻るようになるだろう そしてこのいずれかにその値を返します。 だからあなたは、スタックのこれらの事のすべてを飛び出し、これを保存している 戻り値は、とにかく戻ってすべての道を渡されようとしているからです。 それでは、どうしてアップデート引数と共に私たちの引数を交換して、最初からやり直しませんか? あなたのような何かをする場合、この関数は、末尾再帰ではない場合 - バーなら[学生](x + 1)を。 >>うん。 あなたは条件に入れてもしそうなら、あなたは、戻り値を使って何かをやっている。 それとも、ただリターン2を行う場合でも、*バー(X - 1)。 だから今バー(X - 1)は2回、その値を計算するために返す必要があり、 ので、今それはそれ自身の独立したスタックフレームを必要としている、 そして今、あなたは一生懸命やっていても、あなたはする必要があるとしていないしている - これは末尾再帰ではありません。 [学生]私は末尾再帰を目指して再帰を持ってみませんか - [ボーデン]理想の世界では、しかし、CS50にあなたがする必要はありません。 末尾再帰を取得するためには、一般的には、追加の引数を設定 バーは、yにint型のxを取る場所 とyは戻したい究極のものに対応しています。 ( - ×1)、2 * Yだから、これはあなたがバーを返すことになるだろう。 だから、それは、あなたが物事を末尾再帰にする変換方法だけハイレベルだ。 しかし、余分な引数 - そして、最後に、あなたのベースケースに達したときに、あなただけyを返す あなたが望むことを、全体の時間の戻り値を蓄積してきたので。 に、どのような種類の繰り返しそれをやってますが、再帰呼び出しを使用してきました。 質問はありますか? 文字列を使用する場合のようにたぶん、ポインタ演算について[学生]。 >>確かに。 ポインタ演算。 文字列はchar型星であるので、文字列を使用する場合、それは簡単です、 charsは、永遠に、常に単一バイトで あなたは文字列を扱う場合など、ポインタ演算は、通常の算術演算に相当します。 ただのchar * S = "こんにちは"と言ってみましょう。 だから我々はメモリ内のブロックを持っています。 あなたは常にnullターミネータを必要とするので、それは6バイトを必要とします。 とchar * sは、この配列の先頭を指すようになるだろう。 そこのポイントはそう。 さて、これは、基本的に任意の配列がどのように動作するかです かかわらず、それはmalloc関数により、またはそれがスタック上にあるかどうか復帰したかどうかの。 任意の配列は、基本的には配列の先頭へのポインタである し、任意の配列操作、任意のインデックス付けは、単に特定のオフセット、その配列に起こっている。 だから私は、s [3]のような何かを言うとき、これはsに行くとインチ3文字をカウントしている だからsが[3]、[3]は、0、1、2、3、ので、sを持っているこのリットルを参照しようとしている。 [学生]そして我々はS + 3をやって、その後に括弧スターが同じ値に達する可能性がある? はい。 これは*(S + 3)と同等です。 そしてそれは永遠に、常に同等のあなたが何をするかに関係なくはありません。 あなたは、括弧構文を使用する必要はありません。 あなたは、常に*(S + 3)構文を使用することができます。 人々は、しかし、ブラケット構文を好む傾向にある。 [学生]だから、すべての配列は実際には単なるポインタである。 私はと言うと少しだけ違いがあります。int x [4]; >> [学生]はメモリを作成していますか? [ボーデン]ので、16バイト全体的に、スタック上の4個のint値を作成しようとしていること。 これは、スタック上に16バイトを作成するために起こっている。 xはどこにも格納されません。 それだけの事の開始を参照シンボルです。 あなたは、この関数の内部で配列を宣言しているので、 コンパイラは何をするつもりなのか単なる変数xのすべてのインスタンスを置換される それはこれらの16バイトを置くことを選択することが起こった場所である。 sは実際のポインタなので、これはchar * sであることを行うことはできません。 そして、それは他のことを指すように自由である。 xは定数である。は、別の配列にポイントを持つことができません。 >> [生徒]オーケー。 しかし、このアイデア、このインデックスは、それが伝統的な配列であるかどうかにかかわらず同じです。 またはそれは何かへのポインタであるかのまたはそれはmallocされた配列へのポインタましょう。 そして、実際に、それはまた同じ事であるように等価である。 これは、実際には、ブラケットとブラケットのどんな残っているの内側にあるものだけ変換 それらを一緒に追加して、間接参照。 だから、これは*(S + 3)またはs [3]と同じように有効です。 [学生]あなたは2次元配列を指すポインタを持つことはできますか? それが難しくなっています。伝統的に、ない。 2次元配列は、単にいくつかの便利な構文を持つ1次元配列である なぜなら私が言うときます。int x [3] [3]、これは実際に9個の値を持つだけで1アレイです。 そして私インデックスは、コンパイラは、私が何を意味するか知っているとき。 私はx [1] [2]、それは私は2番目の行に移動したい知っているので、それは最初の3をスキップして起こっていると言うなら そしてそれはその中で第二の事を望んでいるので、それはこの1つを得るために起こっている。 しかし、それはまだほんの一次元配列です。 そして私は、その配列へのポインタを代入したい場合 私は言うだろます。int * p = X; xの型はただです - それだけではシンボルであり、それは実際の変数ではないので、それは、xの荒いタイプだと言って それだけでint *になります。 xがちょうどこのの先頭へのポインタです。 >> [生徒]オーケー。 そして、私は[1] [2]にアクセスすることができません。 私は、ポインタを宣言するための特別な構文があると思います int型のようなとんでもない何かが(* P [ - 。絶対にばかげ何か私も知りません。 しかし、括弧や物事とのようなポインタを宣言するための構文があります。 それも、あなたはそれを行うことができない場合があります。 私は私に本当のことを言うだろう何かを振り返ることができます。 ポイントの構文がある場合、私は後でそれを探します。しかし、あなたはそれを参照することはありません。 とさえ構文は、あなたがそれを使用する場合、人々は困惑されるように古風です。 そのままでは多次元配列はかなり稀だ。 かなりあなた - さて、あなたは行列のことをやっている場合、それはまれであることを行っていない、 しかし、C言語では滅多に多次元配列を使用するつもりんだ。 うん。 >> [生徒] Let 'sは、あなたが本当に長い配列を持っていると言う。 だから、仮想メモリには、すべての連続であるように見えるでしょう 互いに右隣の要素のように、 しかし、物理メモリには、分割することは可能でしょうか? >>はい。 それだけで分離する方法、仮想メモリの作品です - 割り当ての単位は、4キロバイトになる傾向があるページです と、プロセスはちょっと、と言うとき、私はこのメモリを使用したいが、 オペレーティングシステムはそれをメモリの小さなブロックのための4キロバイトを割り当てるために起こっている。 あなただけのメモリのブロック全体で単一の小さなバイトを使用している場合でも、 オペレーティング·システムはそれをフル4キロバイトを与えるために起こっている。 だから意味が何であるか、私は可能性があります - これは私のスタックであると言いましょう。 このスタックは、分離することができた。私のスタックはメガバイトとメガバイトである可能性があります。 私のスタックが非常に大きくなることがあります。 しかし、スタック自体は、個々のページに分割する必要があります これが私たちのRAMであると言う私達はこっちを見ればどの聞かせ、 私は2 GBのRAMを持っている場合、これは、私のRAMのゼロ番目のバイトのように実際のアドレス0である そして、これはここにすべての方法2ギガバイトダウンしています。 だからこのページはこっちこのブロックに対応している場合があります。 このページにはこっちこのブロックに対応している場合があります。 この1つはこっちにこのいずれかに対応している場合があります。 オペレーティングシステムは、物理メモリを割り当てることが自由であるように 任意の個々のページに移動します。 そして、それはつまり、この境界線はアレイを跨ぐように起これば、 配列は、この左側れるようなことが起こると右のページのこの注文の その配列は、物理メモリに分割されようとしている。 プロセスが終了すると、その後は、プログラムを終了するとき、 これらのマッピングは消去取得し、それは他のもののために、これらの小さなブロックを自由に使用することです。 多くの質問? [学生]ポインタ演算。 >>そうそう。 文字列は、簡単であったが、int型のようなものを見て そう背中にint X [4]; これが配列されているかどうか、それが4つの整数のmallocされた配列へのポインタであるかどうか、 それは同じように扱われるようになるだろう。 [学生]だから配列はヒープ上にある? [ボーデン]配列はヒープ上にありません。 >> [生徒]ああ。 [ボーデン]配列のこのタイプは、スタック上になる傾向がある あなたがそれをで宣言しない限り - グローバル変数を無視します。グローバル変数を使用しないでください。 関数の内部で私が言います。int x [4]; それは、この配列のスタッ​​ク上の4整数ブロックを作成するために起こっている。 しかし、これはmalloc(4 * sizeofは(int型));ヒープ上に行くつもりです。 しかし、このポイントの後、私は、ほとんど同じ方法で、xとpを使用することができます あなたが電話を再割り当てすることができ、約前に私が言った例外以外。 技術的には、そのサイズは多少異なりますが、それは完全に無関係です。 あなたは実際にそのサイズを使用することはありません。 私が言うことができるP P [3] = 2;またはx [3] = 2; あなたは正確に同じ方法でそれらを使用することができます。 ここで行ってポインタ演算 - はい。 [学生]あなたは括弧を使用している場合p *を行う必要はありませんか? ブラケットは暗黙間接参照されています。オーケー。>> 実際にも、あなたが言っているあなたは、多次元配列を得ることができます ポインタで、何を行うことができますこととしましょう​​、何かに似ていますが、int **にPP =はmalloc(sizeofの(int型*)* 5); 私は最初それを全て書いていきます。 私はそのいずれかをしたくなかった。 オーケー。 私がここで何をしたかは - PP [i]がされるべきであること。 だからppはポインタへのポインタです。 あなたは5つのintの配列へのポインタppのmallocingいる。 だから、メモリには、スタックの頁にあり それは、すべてのポインタそのものである5ブロックの配列を指すようになるだろう。 そして、ときに、ここで私は、mallocダウン、私はmallocそのそれらの個々のポインタの各 ヒープ上に4バイトの別のブロックを指す必要があります。 4バイトを指してこれがそう。 と別の4バイトには、この1点。 それらのすべては、自分の4バイトを指す。 これは私に多次元物事のやり方を提供します。 私は、ppは[3] [4]が、今、これは多次元配列とは、同じではないと言うことができる 多次元配列は、それが[3]翻訳しているため[4] x配列へのオフセットシングルに。 この間接参照pは、デその次に、第三索引にアクセス とアクセス - 4は無効になる - 番目のインデックス。 一方、我々が持っていたときます。int x [3] [4]多次元配列として前 とブラケットをダブルクリックすると、それは、本当に唯一の単一の間接参照です あなたは、単一のポインタとオフセットをフォローしている、 これは本当に2D参照です。 あなたは、2つの独立したポインタに従ってください。 だから、これも技術的には多次元配列を持つことができます 個々の配列は、異なるサイズです。 だから私はギザギザの多次元配列は、それが呼ばれるものだと思う 本当に以来、最初のものは、10個の要素を持つものを指すことが 二つ目は、100個の要素を持っている何かを示すかもしれません。 [学生]あなたが持つことができるポインタの数に制限はありますか 他のポインタを指している?ナンバー>> あなたはint ***** pを持つことができます。 戻るポインタ演算 - >> [生徒]ああ。 >>うん。 [学生]私はその後のint *** pを持っている場合、私は参照外しを行うと、私はP *がこの値と等しいと言う、 それが唯一の間接参照のレベル1をやろうとすると? >>はい。 だから私は、最後のポインタが指しているものにアクセスしたい場合は - その後、*** pを行う。オーケー。>> だから、これは1ブロックにp点、別のブロックを指し、別のブロックを指しています。 あなたは* P =何かを行う場合、あなたはこれを変更している 現在は別のブロックを指すように設定します。オーケー。>> これらはmallocされた場合[ボーデンは]そして、あなたはすぐにメモリをリークしていた あなたは、これらの異なる基準を持って起こる場合を除き あなたはただ捨てたことをこれらのものに戻って取得することができないので。 ポインタ演算。 ます。int x [4]; 4つの整数の配列を割り当てるために起こっている ここで、xは、配列の先頭を指すようになるだろう。 だから私は、x [1]のような何かを言うとき、私はそれが配列の2番目の整数に行くことを意味する、 これは、この1となります。 この整数は4バイトを占有しますので、しかし、実際に、その配列に4バイトです。 1のオフセットは本当に1のオフセットを意味しますので、 回配列の型が何であれのサイズ。 これは、整数の配列であるため、それがオフセットしたい場合、int型の1倍のサイズを行うことを知っています。 他の構文。これは*(X + 1)と等価であることを忘れないでください; 私はポインタ+ 1は、リターンはポインタが格納されているアドレスであることを言うときは ポインタの型のプラス1倍の大きさ。 だから、もしx = OX100の場合、x + 1 = ox104。 そして、あなたはこれを濫用し、charのようなものを言うことができます* C =(char *)のX; そして今Cは、Xと同じアドレスになるだろう。 cは、OX100に等しいことになるだろう が、c + 1 ox101に等しいことになるだろう ポインタ演算は、あなたが追加しているポインタの型に依存しているため。 だからC + 1、それはCを見て、それはchar型のポインタなので、それはcharの1倍の大きさを追加するために起こっている これは、常に1であることを行っているので、101を取得し、 私はまだ100もあるxを行う場合は、x + 1が104であることを行っているのに対し。 [学生]は、C + + 1であなたのポインタを前進させるために使用することはできますか? はい、できます。 あなたは、xを変更することはできませんので、xがただの記号なので、xと、それが一定であることを行うことはできません。 しかし、cは単なるポインタであることを起こるので、C + +は完全に有効であり、それが1ずつ増加します。 cは単にint *にあった場合、C + + 104されるであろう。 + +は、C + 1は、ポインタ演算を行っているのと同じようにポインタ演算を行います。 これは実際にはマージソートのようなたくさんの方法です - 代わりに物事のコピーを作成するのではなく、代わりに渡すことができます - この一部を消去してみましょう - 私はこの配列の半分を渡したい場合は、好きです。 Let 'sは、私は、関数に配列のこちら側を通過したいとしましょう​​。 私は、その関数に渡すでしょうか? 私はxを渡した場合、私は、このアドレスを渡しています。 しかし、私はこの特定のアドレスを渡したい。だから私は何を渡すべきでしょうか? [学生]ポインタ+ 2? [ボーデン]だからX + 2。はい。 それは、このアドレスになるだろう。 また、非常に頻繁に、それはそれの後、アドレスx [2]のように表示されます。 だから、ブラケットが暗黙の逆参照であるため、それのアドレスを取得する必要があります。 X [2]、このボックスに表示されている値を参照し、次にそのボックスのアドレスを取得したく そうあなたが言うとX [2]。 だからそれはあなたが何かに半分のリストを渡したいマージソートでどのように何か あなたが本当にちょうど渡す&X [2]、現在は限り再帰呼び出しが懸念している、 私の新しい配列がそこから始まります。 直前の質問。 [学生]私たちは、アンパサンドを置いたりしない場合 - それは何という名前ですか? >>スター? [学生]スター。 >>技術的には、間接参照演算子が、 - >> [生徒]参照外しをしています。 我々は、私はちょうど言う場合は、y = xとxのポインタですか何が起こるか、スターまたはアンパサンドを入れない場合 yの型は何ですか? >> [学生]私はちょうどそれのポインタ2を言うでしょう。 あなただけ言うのであればy = xを、現在のxとyの点と同じことに。 >>同じ事を[学生]をポイントします。 、xはint型のポインタである場合はどうなりますか?あなたはポインタを代入することはできませんので、>>それは文句を言うだろう。 [学生]オーケー。 我々は矢のようにそれらを描くにもかかわらず、そのポインタを覚えて、 本当に彼らはすべての店 - int型* xは - 本当にすべてのxが保存されているが、OX100のようなものです その我々は100に格納されているブロックを指すように表現するために起こる。 だから私が言うとき、int *にy = xと、私はちょうどyにOX100をコピーするんだけど、 その我々だけでもOX100を指すようにすれば、yと表すことになるだろう。 そして私はと言えばます。int i =(int)をX;それから私はOX100の値が何であっても保存しようとしている その内側が、現在ではなく、整数型のポインタとして解釈されることになるだろう。 しかし、あなたはキャストを必要とするか、またはそうでなければ文句を言うでしょう。 [学生]だからあなたはキャストすることを意味しな​​い - それは、yのxまたはキャストintのintをキャストしようとしている? [ボーデン]何? [学生]オーケー。これらの括弧の後にそこには、xまたはAYそこになるだろうか? [ボーデン]のどちらか。 xとyは等価です。 >> [生徒]オーケー。 彼らは両方のポインタだから。 >>うん。 [学生]だからそれは整数の形で進数100を格納するでしょうか? >> [ボーデン]うん。 それが指すものは何でもではなく値。 [ボーデン]うん。 >> [生徒]だから整数形式でアドレスだけ。オーケー。 あなたには、いくつかの奇妙な理由のために、必要であれば[ボーデン] あなたは、排他的にポインタを扱うと整数を扱うことができませんでした そしてちょうどint型* x = 0のようになる。 次に、ポインタ演算が起き始めると本当に混乱するつもりだ。 そこで、彼らは保存しておくことを数字は意味がありません。 それはあなたがそれらを解釈してしまうだけの方法です。 だから私は、int型にint *からOX100をコピーすることが自由だ おそらくキャストしないために怒鳴ら取得するつもりyou're - と私は割り当てることは自由だ - 私は、この任意のint *に(i​​nt *)をox1234ような何かを割り当てることが自由だ。 &yであるようにox123は同じように有効なメモリアドレスです。 &Yはかなりox123ものを返すことが起こる。 [学生]は、16進数から10進形式に行くために本当にクールな方法であろう、 あなたはポインタを持っていて、int型にキャストした場合好きですか? [ボーデン]あなたは本当にprintfのように使用して印刷することができます。 Let 'sは、私はint型のy = 100を持っていると言う。 だからprintfの(%d個\ nを - あなたが知っておくべきこととして - %xは、整数としてそれを印刷してください。 我々は、ちょうど16進数として、それを印刷します。 だからポインタは、16進数として格納されていません と整数は小数として格納されていません。 すべてはバイナリとして格納されます。 それは、我々は16進数としてポインタを示す傾向にあるというだけです 私たちは、これらの4バイトのブロック単位で物事を考えるので、 とメモリアドレスは精通している傾向があります。 それはBFで始まる場合、それはスタック上にあることを起こる、のように私たちはいる。 だから、それだけで16進数としてポインタの我々の解釈だ。 オーケー。任意の最後の質問? あなたが何かを持っているかの後、私は少しのためにここにいるよ。 そして、それはそれの終わりです。 [学生]イェーイ! [拍手] [CS50.TV]