[Powered by Google Translate] [Oddíl 4 - Více Komfortní]
[Rob Bowden - Harvard University]
[To je CS50. - CS50.TV]
Máme kvíz zítra, v případě, že vy nevěděl, že.
Je to v podstatě na vše, co jste mohli vidět ve třídě nebo měli vidět ve třídě.
To zahrnuje ukazatele, i když jsou velmi nedávné téma.
Měli byste alespoň pochopit vysoké úrovně z nich.
Cokoliv, co byl pryč přes ve třídě, měli byste pochopit, pro kvíz.
Takže pokud máte nějaké dotazy na nich, můžete požádat je teď.
Ale to bude velmi student-vedl zasedání, kde jste klást otázky,
takže doufejme, že lidé mají otázky.
Má někdo nějaké dotazy?
Ano. >> [Student] Můžeš jít přes ukazatelů znovu?
Půjdu přes ukazatelů.
Všechny vaše proměnných nutně žít v paměti,
ale obvykle nemusíte bát, že a stačí říct x + 2 a y + 3
a kompilátor bude zjistit, kde věci jsou živé na vás.
Jakmile máte co do činění s ukazateli, teď jsi explicitně pomocí těchto adresy paměti.
Takže jediné proměnné pouze někdy žít v jednom adresu v daném okamžiku.
Pokud chceme deklarovat ukazatel, jaký je typ bude vypadat?
>> Chci vyhlásit ukazatel p. Co je typ vypadat?
[Student] int * p. Jo >>. Takže int * p.
A jak mám udělat to poukázat na x? >> [Student] Ampersand.
[Bowden] Tak ampersand je doslova nazývá adresa provozovatele.
Takže když říkám, a x je to čím dál paměti adresu proměnné x.
Takže teď mám ukazatel p, a kdekoli v mém kódu mohu použít * p
nebo bych mohl použít x a bude to přesně to samé.
(* P). Co je to děláš? Co, že hvězda znamená?
[Student] To znamená, že hodnota v tomto bodě. Jo >>.
Takže když se podíváme na to, může to být velmi užitečné upozornit na diagramy
je-li to krabička paměti pro x, který se stane, že má hodnotu 4,
pak máme malou krabičku paměti pro p,
a tak p ukazuje na x, takže jsme nakreslit šipku z bodu P do x.
Takže když říkáme, * p říkáme jít do pole, které je p.
Hvězda je sledovat šipku a pak dělat, co chcete s tímto box tady.
Takže můžu říct, * p = 7, a že půjde na pole, které je x, a změny, které se 7.
Nebo bych mohl říct, int z = * p * 2; To matoucí, protože je to hvězda, hvězda.
Ten hvězda dereferencing p, druhá hvězda je vynásobí 2.
Všimněte si, bych mohl mít stejně dobře nahradil * p s x.
Můžete je použít stejným způsobem.
A pak o něco později I může mít p bod na zcela novou věc.
Mohu jen říct, p = &z;
Takže teď p již neodkazuje na x, ale poukazuje na z..
A kdykoliv jsem to * p je to stejné, jako dělá z.
Takže užitečná věc na tom je, jakmile začneme dostat do funkcí.
>> Je to trochu zbytečné deklarovat ukazatel, který ukazuje na něco, co
a pak jste jen dereferencing to
když jste mohl použít původní proměnnou začít.
Ale když se dostanete do funkcí - tak řekněme, že máme nějakou funkci, int foo,
který bere ukazatel a jen dělá * P = 6;
Stejně jako jsme viděli předtím, než se swapu, můžete to udělat efektivní swap a samostatnou funkci
tím, že jen kolem celých čísel, protože vše v C je vždy kolem hodnoty.
I když jste kolem ukazatele jste kolem hodnoty.
To jen tak se stane, že tyto hodnoty jsou adresy paměti.
Takže když říkám foo (p), jsem kolem ukazatel do funkce foo
a potom foo dělá * p = 6;
Takže uvnitř této funkce, * p je stále odpovídá x,
ale nemohu použít x uvnitř této funkce, protože to není rozsahem v této funkci.
Takže * p = 6 je jediný způsob, jak mohu získat přístup k místní proměnné z jiné funkce.
Nebo, no, ukazatele jsou jediný způsob, jak mohu získat přístup k místní proměnné z jiné funkce.
[Student] Řekněme, že byste chtěli vrátit ukazatel. Jak přesně to děláte, že?
[Bowden] Vrací ukazatel jako v něco jako int y = 3; return & y? >> [Student] Jo.
[Bowden] Dobře. Nikdy byste neměli udělat. To je špatné.
Myslím, že jsem viděl v těchto přednáškových snímků jsi začal vidět celý tento diagram paměti
kde tady máte paměťovou adresu 0
a tady máte adresu v paměti 4 koncerty nebo 2 na 32.
Takže máš nějaké věci a nějaké věci a pak se budete muset váš stack
a máte svůj haldy, které jste právě začal poznávat, roste.
[Student] Není haldy nad zásobníku?
>> Jo. Halda je na vrcholu, je to tak? >> [Student] No, dal 0 na vrcholu.
[Student] Oh, dal 0 na vrcholu. >> [Student] Oh, dobře.
Upozornění: Kdekoliv s CS50 budete vidět to takhle. >> [Student] Dobře.
Je to jen, že když jste nejprve vidět stohy,
jako když si myslíte, že stoh si myslíte, že stohování věci na vrcholu jednoho jiný.
Takže máme tendenci otočit to asi tak stack roste jako stack normálně
místo zásobníku visí dolů. >> [Student] Ještě ne hromady technicky rostou až příliš, i když?
Záleží na tom, co máte na mysli tím, vyrůstat.
Zásobník a haldy vždy rostou v opačných směrech.
Zásobník je vždy vyrůstá v tom smyslu, že je to roste
k vyšší paměťové adresy, a haldy roste dolů
v tom, že je to stále k nižším adresy paměti.
Tak, aby horní je 0 a dolní část je vysoká adresy paměti.
Jsou oba roste, jen v protilehlých směrech.
[Student] Jen jsem myslel, že proto, že jste řekl, že jste dal hromadu na dně
protože se zdá více intuitivní, protože pro zásobník začít na vrcholu haldy,
haldy je na vrcholu sebe taky, takže to je - >> Jo.
Můžete také myslet na hromadu jako vyrůstat a větší, ale zásobník víc.
Takže stack je ten, že jsme trochu chtít ukázat roste.
Ale všude, kam se podíváte jinak se chystá ukázat adresu 0 nahoře
a nejvyšší adresa paměti v dolní části, takže to je váš obvyklý pohled na paměti.
>> Máte dotaz?
[Student] Můžete nám říci více o hromadu?
Jo. I k tomu se dostaneme za chvíli.
Za prvé, jít zpátky, proč vracet & Y je špatná věc,
na zásobníku budete mít spoustu zásobníku snímků, které reprezentují všechny funkce
které byli povoláni.
Takže ignorovat předchozí věci, horní část zásobníku je vždy bude hlavní funkce
protože to je to první funkce, která je volána.
A pak, když budete volat jinou funkci, zásobník bude růst dolů.
Takže když ti budu říkat nějakou funkci, foo, a to má svůj vlastní zásobník rám,
může volat nějakou funkci, bar, to dostane jeho vlastní zásobníku rám.
A bar může být rekurzivní, a to mohl zavolat sám,
a tak, aby druhý hovor do baru bude mít své vlastní zásobníku rám.
A tak, co se děje v těchto stack rámy jsou všechny lokální proměnné
a všechny argumenty funkce, které -
Všechny věci, které jsou místně rozsahem této funkci pokračovat v těchto zásobníku rámů.
Takže to znamená, že když jsem řekl něco jako bar je funkce,
Jdu jen prohlásit celé číslo a vrátí ukazatel na tento integer.
Tak kde y žijí?
[Student] y žije v baru. >> [Bowden] Jo.
Někde v tomto malém náměstí paměti je čtverec littler, který má y v něm.
Když jsem se vrátit a y, vracím ukazatel na tento malý blok paměti.
Ale pak, když funkce vrací, jeho stack frame dostane vyskočila ze zásobníku.
A to je důvod, proč se tomu říká stack.
Je to jako struktury zásobníku dat, pokud víte, co to je.
Nebo dokonce jako hromada zásobníků je vždy příklad,
Hlavní je jít na dně, pak první funkce voláte se jít na vrcholu, že
a můžete se dostat zpět do hlavního, až se vrátíte ze všech funkcí, které byly tzv.
, které byly umístěny na vrcholu toho.
>> [Student] Takže pokud jste to vrátit a y, že hodnota se mohou změnit bez předchozího upozornění.
Ano, to - >> [Student] Mohlo by to být přepsána. Jo >>.
Je to úplně - Pokusíte-li se -
To by také int * bar, protože se vrací ukazatel,
tak jeho návratový typ je int *.
Pokud se pokusíte použít návratovou hodnotu této funkce, je to nedefinované chování
proto, že ukazatel ukazuje na špatnou vzpomínkou. >> [Student] Dobře.
Takže co když, například, jste prohlásil int * y = malloc (sizeof (int))?
To je lepší. Ano.
[Student] Mluvili jsme o tom, jak když jsme přetáhnout věci do našeho koše
oni nejsou ve skutečnosti odstraněny, jsme jen ztratit jejich ukazatele.
Takže v tomto případě se budeme vlastně vymazat hodnotu, nebo je tam ještě v paměti?
Z větší části, bude to ještě bude.
Ale řekněme, že náhodou zavolat nějakou jinou funkci, Baz.
Baz dostane svůj vlastní zásobník rám tady.
Je to bude přepsání všech těchto věcí,
a pak, pokud se později vyzkoušet a používat ukazatel, který jste dostali dříve,
to nebude mít stejnou hodnotu.
Bude to změnilo jen proto, že jste volal funkci Baz.
[Student] Ale už nejsme, stále bychom si 3?
[Bowden] S největší pravděpodobností, že ne.
Ale nemůžete spolehnout na to. C jen říká, nedefinované chování.
>> [Student] Oh, to dělá. Dobře.
Takže když se chcete vrátit ukazatel, to je místo, kde malloc přichází v provozu.
Píšu vlastně jen návrat malloc (3 * sizeof (int)).
Půjdeme přes malloc více sekundu, ale představa, že malloc je všechno vaše lokálních proměnných
vždy jít na stack.
Cokoliv, co se malloced pokračuje na haldě, a to navždy a vždy na haldě
dokud je výslovně uvolnit ji.
Takže to znamená, že když malloc něco, bude to přežít po funkce vrátí.
[Student] Bude to přežít poté, co program se zastaví? >> Ne
Dobře, takže to tam bude, dokud program je úplně hotový chodu. Ano >>.
Můžeme jít přes detaily o tom, co se stane, když se program zastaví.
Možná budete muset připomínat mě, ale to je samostatná věc úplně.
[Student] Tak malloc vytváří ukazatel? Jo >>.
Malloc - >> [Student] Myslím, že malloc označuje blok paměti, že ukazatel může použít.
[Bowden] Chci, aby diagram znovu. >> [Student] Takže tato funkce funguje, i když?
[Student] Jo, malloc označuje blok paměti, které můžete použít,
a pak vrátí adresu prvního bloku této paměti.
>> [Bowden] Jo. Takže, když malloc, jste chytil nějaký blok paměti
že je v současné době v haldě.
Pokud Halda je příliš malý, pak haldy je jen poroste, a to roste v tomto směru.
Takže řekněme, že haldy je příliš malý.
Pak je to o růst trochu a vrátí ukazatel na tento blok, který právě vyrostl.
Když věci zdarma, děláš větší prostor v haldě,
takže pak později nazvali malloc můžete znovu použít, že paměť, kterou předtím uvolněn.
Důležité informace o malloc a free je, že vám dává úplnou kontrolu
po celou dobu životnosti těchto paměťových bloků.
Globální proměnné jsou vždy živý.
Lokální proměnné jsou naživu do jejich působnosti.
Jakmile jdete kolem ortézy kudrnaté, místní proměnné jsou mrtví.
Malloced paměť je naživu, když chcete, aby to bylo naživu
a pak se uvolní, když řeknete, že mohou být propuštěn.
To jsou vlastně jen 3 druhy paměti, opravdu.
Tam je automatická správa paměti, což je zásobník.
Věci se dějí za vás automaticky.
Když se řekne int x, je paměť přidělená pro int x.
Když x dostane mimo rozsah, je paměť kultivovaný pro x.
Pak je tu dynamická správa paměti, která je co malloc je,
což je, když máte kontrolu.
Můžete dynamicky rozhodnout, kdy by měly paměť a neměly by být přiděleny.
A pak je tu statická, což prostě znamená, že to žije věčně,
což je to, co globální proměnné.
Jsou to jen vždy v paměti.
>> Otázky?
[Student] Můžete definovat blok jen pomocí složené závorky
ale neměl by mít v případě ztráty nebo while nebo něco takového?
Můžete definovat blok jako ve funkci, ale že má složené závorky taky.
[Student] Takže nemůžete prostě jako náhodné dvojice složených závorek v kódu
které mají lokální proměnné? >> Ano, můžete.
Uvnitř int baru bychom mohli mít {int y = 3;}.
Že to má být tady.
Ale to kompletně definuje rozsah int y.
Po tomto druhém rovnátka kudrnaté, můžete y nesmí být nadále používána.
Málem jsi to nikdy neudělal, ačkoli.
Dostat se zpátky na to, co se stane, když program skončí,
je to něco jako rozšířený omyl / polovina lži, že dáváme, aby se jen dělat věci lépe.
Řekneme vám, že když se alokovat paměť
jste vyčleňují kus RAM pro dané proměnné.
Ale ty jsi opravdu přímo dotýkat RAM někdy ve svých programech.
Pokud si myslíte, že o tom, jak jsem kreslil -
A skutečně, pokud si projít v GDB uvidíte to samé.
Bez ohledu na to, kolikrát jsi spustit program nebo jaký program používáte,
zásobník je vždycky začít -
jste vždy uvidí proměnné kolem něčeho adresu oxbffff.
Je to obvykle někde v této oblasti.
Ale jak může 2 programy mohl mít ukazatele na stejné paměti?
[Student] Tam je nějaký libovolný určení, kde je oxbfff měl být na RAM
, které mohou být ve skutečnosti v různých místech v závislosti na tom, kdy byla volána funkce.
Jo. Termín je virtuální paměť.
Myšlenka je, že každý jednotlivý proces, každý program, který je spuštěn na počítači
má vlastní - předpokládejme, že 32 bitů - zcela nezávislý adresový prostor.
To je adresový prostor.
Má své vlastní zcela nezávislé 4 GB k použití.
>> Takže, pokud se dostanete 2 programy současně, tento program vidí 4 GB k sobě,
tento program vidí 4 GB k sobě,
a to je nemožné pro tento program dereference ukazatele
a skončit s pamětí z tohoto programu.
A co virtuální paměť je mapování z procesů adresového prostoru
skutečných věcí na RAM.
Takže je to pro váš operační systém, aby věděli,
hej, když ten chlap dereferences ukazatel oxbfff, že ve skutečnosti znamená
že chce RAM byte 1000,
vzhledem k tomu, pokud tento program dereferences oxbfff, že opravdu chce RAM byte 10000.
Mohou být libovolně daleko od sebe.
To platí dokonce i věcí v rámci jednoho procesů adresního prostoru.
Tak jako to vidí všechny 4 GB k sobě, ale řekněme, že -
[Student] Má každý proces -
Řekněme, že máte počítač pouze s 4 GB paměti RAM.
Má každý proces vidět celé 4 GB? Ano >>.
Ale 4 GB to vidí je lež.
Je to prostě, že si myslí, že má všechny tyto paměti, protože neví, jiný proces existuje.
To bude používat pouze tolik paměti, jak to vlastně potřebuje.
Operační systém se nebude dát RAM do tohoto procesu
jestli to nebyl použit žádný paměť celého tohoto regionu.
Nebude to, aby to paměť pro tuto oblast.
Ale nápad je to - já se snažím myslet na - já si nemyslím, že analogie.
Analogie jsou tvrdé.
Jednou z otázek, virtuální paměti nebo jedna z věcí, je to řešení
je to, že proces by měl být zcela vědomi sebe.
A tak si můžete zapsat libovolný program, který jen dereferences žádný ukazatel,
Líbí stačí napsat program, který říká, že * (ox1234),
a to je to, dereferencing adresa paměti 1234.
>> Ale je to až do operačního systému a pak přeložit, co znamená 1234.
Takže pokud 1234 se stane, že platné adresa paměti pro tento proces,
jako je to na frontě, nebo tak něco, pak to vrátí hodnotu této paměťové adresy
pokud jde o proces ví.
Ale pokud 1234 není platná adresa, stejně jako se to stane přistát
v nějakém malém kousku paměti zde, který je mimo zásobníku a za hromadu
a vy jste opravdu používat, pak to je, když se dostanete věci, jako segfault chyb
proto, že jste se dotknete paměti, že byste neměli dotýkat.
To je také pravda -
32-bit systém, 32 bitů znamená, že máte 32 bitů při definování adresu paměti.
Je to důvod, proč ukazatele jsou 8 bytů, protože 32 bitů je 8 bajtů - nebo 4 bajty.
Ukazatele jsou 4 byty.
Takže když vidíte ukazatel, jako oxbfffff, že je -
V jakémkoli programu stačí postavit libovolnou ukazatel,
kdekoli od ox0 to vůl 8 f's - FFFFFFFF.
[Student] Neříkal jsi, že jsou 4 byty? Jo >>.
[Student] Pak každý byte bude mít - >> [Bowden] Hexadecimální.
Hexadecimální - 5, 6, 7, 8. Takže ukazateli budete vždy vidět v šestnáctkové soustavě.
Je to jen, jak dělíme ukazatele.
Každé 2 číslice šestnáctkové je 1 byte.
Takže tam to bude 8 hexadecimálních číslic pro 4 byty.
Takže každý ukazatel na 32-bitovém systému bude 4 byty,
což znamená, že ve vašem procesu si můžete postavit libovolného 4 bajty
a aby ukazatel z toho,
, což znamená, že pokud je to známo, může to řešit celý 2 až 32 bajtů paměti.
I když to opravdu není mít přístup k, že
i když je počítač má pouze 512 MB, si myslí, že má tolik paměti.
A operační systém je dost chytrý na to, že to bude jen přidělí to, co skutečně potřebujete.
To není jen tak, oh, nový proces: 4 koncerty.
>> Jo. >> [Student] Co vůl znamená? Proč jsi to napsal?
Je to jen symbol na hexadecimální.
Když vidíte číslo začátek s volem, postupné věci jsou hexadecimální.
[Student] jsi vysvětloval, co se stane, když program skončí. Ano >>.
Co se stane, když program skončí, je operační systém
jen vymaže mapování, že má pro tyto adresy, a to je to.
Operační systém může nyní jen dát tu vzpomínku na jiný program používat.
[Student] Dobře.
Takže když budete přidělovat něco na haldě nebo zásobníku nebo globální proměnné nebo něco,
všichni jen tak zmizet, jakmile program skončí
protože operační systém je nyní zdarma, aby se paměť jiných procesů.
[Student] I když tam jsou pravděpodobně stále hodnoty psané v? Jo >>.
Hodnoty jsou pravděpodobně stále existují.
Je to prostě, že to bude těžké dostat se na ně.
Je to mnohem těžší dostat se na ně, než je dostat se na smazaného souboru
protože smazaný soubor druh sedí tam po dlouhou dobu, a pevný disk je mnohem větší.
Takže to bude přepsat různé části paměti
před tím, než se stane přepsat kus paměti, že soubor používá k být.
Ale hlavní paměti, RAM, můžete procházet mnohem rychleji,
takže to bude velmi rychle být přepsány.
Otázky týkající se této nebo cokoliv jiného?
[Student] Mám otázky týkající se jiného tématu. Dobře >>.
Má někdo nějaké dotazy na toto téma?
>> Dobře. Jiné téma. >> [Student] Dobře.
Chtěl jsem přes některé z praktických testů,
a v jednom z nich se mluvilo o sizeof
a hodnota, která se vrací, nebo různé typy proměnných. Ano >>.
A řekl, že oba int a dlouho obě vrátit 4, takže oba jsou délce 4 bajty.
Je nějaký rozdíl mezi int a dlouhé, nebo je to totéž?
Ano, tam je rozdíl.
C standard -
Já jsem asi jít zkazit.
C Norma je přesně to, co C je oficiální dokumentace C.
To je to, co říká.
Takže C standard jen říká, že char bude navždy a vždy 1 bajt.
Všechno po tom - krátký, je vždy jen definován jako větší než nebo rovno znak.
Toto by mohlo být přísně větší než, ale není pozitivní.
Int je právě definována jako větší než nebo rovno krátký.
A dlouhá je právě definoval jako větší nebo rovna int.
A long long je větší než nebo rovno dlouho.
Takže jediné, co C standard definuje je relativní uspořádání všeho.
Skutečná velikost paměti, že věci zabírají je obecně až po realizaci,
ale je to docela dobře definována v tomto bodě. >> [Student] Dobře.
Takže šortky jsou téměř vždy bude 2 bytů.
Ints jsou téměř vždy bude 4 byty.
Dlouhé dlouhé výrobky jsou téměř vždy bude 8 bytů.
A touží, to záleží na tom, zda používáte 32-bit nebo 64-bit systém.
Tak dlouho bude odpovídat typu systému.
Pokud používáte 32-bitový systém jako Appliance, že to bude 4 byty.
Pokud používáte 64-bit jako hodně novějších počítačích, to bude 8 bytů.
>> Ints jsou téměř vždy 4 bytů v tomto bodě.
Dlouhé dlouhé výrobky jsou téměř vždy 8 bytů.
V minulosti, ints používán pouze 2 byty.
Ale si všimnout, že tato zcela splňuje všechny tyto vztahů větší než a rovno.
Tak dlouho se dokonale dovoleno mít stejnou velikost jako celé číslo,
a je to také mohli být stejné velikosti jako long long.
A to jen tak náhodou, že v 99,999% systémů, se bude rovnat
buď int nebo long long. Záleží jen na 32-bit nebo 64-bit. >> [Student] Dobře.
V plave, jak je desetinné místo určené v podmínkách kousků?
Stejně jako jako binární? Jo >>.
Nemusíte vědět, že pro CS50.
Nemusíte ani dozvědět, že v 61.
Nemáte naučit, že skutečně v každém předmětu.
Je to jen charakter.
Zapomněl jsem přesně bit příděly.
Myšlenka s plovoucí desetinnou čárkou, je, že můžete alokovat určitý počet bitů reprezentovat -
V podstatě vše, co je ve vědecké notaci.
Takže si přidělit určitý počet bitů k reprezentaci čísla sám, jako 1,2345.
Nikdy představovat číslo s více číslicemi, než 5.
Pak se také přidělit určitý počet bitů, takže má tendenci být jako
můžete jít jen do určité číslo, tak je největší exponent můžete mít,
a můžete jít jen do určité exponentem,
rád, že je to nejmenší exponent můžete mít.
>> Nevzpomínám si přesně způsob, jakým bity jsou určeny pro všechny z těchto hodnot,
ale určitý počet bitů jsou věnovány 1,2345,
další určitý počet bitů jsou určeny pro exponent,
a je to jen možné reprezentovat exponentu o určité velikosti.
[Student] A double? Je to jako extra dlouhou plováku? Jo >>.
Je to totéž jako float, s výjimkou teď používáte 8 bajtů místo 4 bajty.
Nyní budete moci používat 9 číslic nebo 10 číslic,
a to bude moci jít do 300 místo 100. >> [Student] Dobře.
A plováky jsou také 4 byty. Ano >>.
No, opět, pravděpodobně záleží celkově o obecné provádění,
ale plováky jsou 4 byty, dvoulůžkové jsou 8.
Zdvojnásobí se nazývají dvojitá, protože jsou dvakrát velikost plováky.
[Student] Dobře. A jsou tam double čtyřhře? >> Nejsou.
Myslím, že - >> [Student] Jako dlouhých touží? Jo >>. To si nemyslím. Ano.
[Student] Na loňské testu byla otázka o hlavní funkci
musel být součástí vašeho programu.
Odpověď byla, že to nemusí být součástí vašeho programu.
V jaké situaci? To je to, co jsem viděl.
[Bowden] Zdá se, že - >> [Student] Jakou situaci?
Máte problém? >> [Student] Jo, můžu rozhodně vytáhněte ji.
To nemusí být, technicky, ale v podstatě to bude.
[Student] Viděl jsem jeden na jiné roce.
Bylo to jako True nebo False: platná - >> Oh, c soubor.?
. [Student] Každý c soubor musí mít - [jak řečeno najednou - nesrozumitelný]
Dobře. Tak to je samostatná.
>> . C soubor pouze musí obsahovat funkce.
Můžete sestavit soubor do strojového kódu, binární, bez ohledu,
aniž by bylo spustitelný ještě.
Platný spustitelný, musí mít hlavní funkci.
Můžete napsat 100 funkce v 1 souboru, ale ne hlavní
a pak zkompilovat, které se na binární,
pak můžete napsat jiný soubor, který má pouze hlavní, ale to vyžaduje spoustu z těchto funkcí
v tomto binární soubor sem.
A tak, když děláš spustitelný soubor, který je co linker dělá
je to kombinuje tyto 2 binární soubory do spustitelného.
Tak. C soubor nemusí mít hlavní funkci vůbec.
A na velké bází kódu uvidíte tisíce. Soubory C a 1 hlavního souboru.
Další otázky?
[Student] Tam byl další otázka.
To řekl, aby je kompilátor. Pravda nebo lež?
A odpověď byla falešná, a pochopil jsem, proč to není jako Clang.
Ale co říkáme, aby, pokud to není?
Udělejte je v podstatě jen - vidím přesně to, co říká.
Ale to jen spouští příkazy.
Udělejte.
Mohu vytáhnout toto nahoru. Jo.
Oh, yeah. Zkontrolujte také to dělá.
To říká, že účelem utilitou make je určit automaticky
které části velkého programu se musí prekompilovat
a vydávat příkazy k překompilovat.
Můžete provést make soubory, které jsou naprosto obrovská.
Udělejte dívá na časová razítka souborů a jak jsme řekli dříve,
můžete sestavit jednotlivé soubory dolů, a není to až se dostanete do linker
že jsou dohromady do spustitelného souboru.
Takže pokud máte 10 různých souborů a provést změnu na 1 z nich,
pak to, co udělat, je dělat, je jen překompilovat, že 1 soubor
a potom znovu všechno dohromady.
Ale je to mnohem hloupější než to.
Je na vás, abyste kompletně definovat, že je to to, co by měla dělat.
Je standardně má schopnost rozpoznat toto časové razítko věci,
ale můžete napsat make soubor nic dělat.
Můžete napsat, aby soubor tak, že když zadáte, aby to jen cd do jiného adresáře.
Byla jsem frustrovaná, protože jsem připínáček vše uvnitř mého spotřebiče
a pak jsem zobrazit PDF z Mac.
>> Tak jsem jít do Finder a můžu si jít, Připojit k serveru,
a server se připojit k je můj spotřebiče, a pak jsem otevřít PDF
, který se sestavuje LaTeXu.
Ale já jsem začínal být frustrovaný, protože pokaždé jsem potřeboval obnovit PDF,
Musel jsem zkopírovat jej do konkrétního adresáře, který by mohl získat přístup
a to bylo stále nepříjemné.
Takže místo toho jsem napsal make soubor, který budete muset definovat, jak to dělá věci.
Jak uděláte v tomto je PDF LaTeX.
Stejně jako jakoukoliv jinou značku souboru - nebo jsem asi jste neviděli Make soubory,
ale máme v Appliance globální make soubor, který právě říká,
Pokud se kompilace soubor C, použijte řinčet.
A tak tady v mém souboru, který na značku dělám já říkám,
Tento soubor budete chtít kompilovat PDF LaTeXu.
A tak je to PDF LaTeX, že to dělá kompilace.
Udělejte není kompilace. Je to prostě běží tyto příkazy v pořadí jsem uvedl.
Tak to běží PDF LaTeX, zkopíruje ho do adresáře chci to být zkopírovány,
to cd do adresáře a dělá jiné věci,
ale vše, co dělá, je uznat, když soubor změn,
a pokud změní, pak to bude spusťte příkazy, které to má spustit
když se soubor změní. >> [Student] Dobře.
Já nevím, kde se globální Udělejte soubory jsou pro mě podívat se na to.
Další otázky? Něco z minulosti kvízy? Jakékoliv ukazatel věci?
Existují jemné věci, s ukazateli, jako je -
Nebudu mít možnost najít kvízovou otázku na to -
ale stejně jako tyhle věci.
Ujistěte se, že jste pochopili, že když řeknu, int * x * y -
To není zrovna nic tady, myslím.
Ale jako * x * y, které jsou 2 proměnné, které jsou ve frontě.
Když řeknu, že x = malloc (sizeof (int)), x je stále variabilní na zásobníku,
malloc je nějaký blok nad v haldě, a my máme x bod do haldy.
>> Takže něco na zásobníku ukazuje na hromadu.
Kdykoli budete malloc něco, jste nevyhnutelně uložením uvnitř ukazatel.
Tak to je ukazatel na zásobníku, je malloced blok na haldě.
Mnoho lidí si zmatený a říci int * x = malloc, x je na hromadu.
Ne, co x poukazuje, je na haldě.
x sám je na stacku, pokud z nějakého důvodu jste x být globální proměnná,
v takovém případě se stane, že je v jiném regionu paměti.
Takže sledování, tyto krabice a šipka diagramy jsou docela běžné, že kvíz.
Nebo, pokud to není na kvíz 0, bude na testu 1.
Měli byste vědět, všechny z nich, podle kroků v sestavování
protože jste museli odpovídat na otázky týkající se těch. Ano.
[Student] Mohli bychom vyrazit přes tyto kroky - >> Jasně.
Před kroků a sestavování jsme předzpracování,
sestavování, montáž a propojení.
Předzpracování. Co to má dělat?
Je to nejjednodušší krok - dobře, ne jako -
to neznamená, že by mělo být zřejmé, ale je to nejjednodušší krok.
Vy mohly provádět to sami. Jo.
[Student] Vezmi si, co máte ve vaší zahrnuje takhle, a to kopíruje a pak také definuje.
Vypadá to na věci jako # include a # define,
a to jen kopie a pasty, co skutečně znamenají.
Takže když říkáte # include cs50.h, preprocesor je kopírování a vkládání cs50.h
do tohoto řádku.
Když se řekne # define x za 4, preprocesor prochází celý program
a nahrazuje všechny výskyty x s 4.
Takže preprocesor má platnou C soubor a výstupy platný C soubor
kde věci byly zkopírovat a vložit.
Takže teď kompilaci. Co to má dělat?
[Student] To jde z C na binární.
>> [Bowden] To není jet celou cestu na binární.
[Student] do strojového kódu a pak? >> To není strojový kód.
[Student] shromáždění? >> Shromáždění.
Jde to shromáždění, než přejde celou cestu ke kódu C,
a většina jazyků něco takového.
Vybrat jakýkoliv vysoké úrovni jazyka, a pokud budete kompilovat,
je pravděpodobné, sestavit v krocích.
Nejprve to bude kompilovat Python do C, pak to bude kompilovat C do shromáždění,
a pak shromáždění se chystá přeloženy do binární.
Takže kompilace bude, aby ji z C na shromáždění.
Slovo sestavování obvykle znamená uvést jej na vyšší úrovni
na nižší úrovni programovacího jazyka.
Tak to je jen krok při sestavování, kde můžete začít s high-úrovni jazyka
a skončí v low-level jazyk, a to je důvod, proč je krok nazývá kompilace.
[Student] Během sestavování, řekněme, že jste udělali # include cs50.h.
Bude kompilátor překompilovat cs50.h, stejně jako funkcí, které jsou tam,
a převést do assembleru stejně,
nebo to bude zkopírovat a vložit něco, co bylo pre-shromáždění?
cs50.h bude do značné míry nikdy skončit ve shromáždění.
Věci jako funkce prototypů a věci jsou jen pro vás být opatrní.
To zaručuje, že kompilátor můžete zkontrolovat věci, jako jste volání funkcí
s právem návratové typy a správné argumenty a tak.
>> Takže cs50.h bude předzpracovány do souboru, a pak, když je to kompilaci
je to v podstatě vyhodit po dbá na to, aby vše, co je nazýváno správně.
Ale funkce definované v CS50 knihovně, které jsou oddělené od cs50.h,
ti nebudou samostatně sestaven.
To bude skutečně sestoupí v propojení kroku, takže k tomu se dostaneme za chvíli.
Ale nejprve, co je montáž?
[Student] Montáž na binární? Jo >>.
Sestavení.
Nechceme říkat, že sestavování, protože shromáždění je do značné míry čisté překlad binární.
Tam je velmi málo logiku jít od shromáždění na binární.
Je to jako hledat v tabulce, oh, máme tento návod;
která odpovídá binární 01110.
A tak se soubory, které montáž obecně výstupy jsou. O soubory.
A o. Soubory jsou to, co jsme říkali dříve,
Jak soubor nemusí mít hlavní funkci.
Každý soubor může být sestaven až do. Souboru ° tak dlouho, jak je to platný C souboru.
To může být sestaven do. O..
Nyní, propojení je, co vlastně přináší spoustu. O soubory a přináší jim spustitelný.
A tak to, co dělá, je linkování můžete myslet na CS50 knihovny jako. Soubor °.
Je to již zkompilovaný binární soubor.
A tak při kompilaci souboru, váš hello.c, který volá GetString,
hello.c dostane sestavují do hello.o,
hello.o je nyní v binárním formátu.
Používá GetString, takže je třeba přejít na cs50.o,
a linker smooshes dohromady a zkopíruje GetString do tohoto souboru
a přichází s spustitelný soubor, který má všechny funkce, které potřebuje.
Takže cs50.o není vlastně O soubor, ale je to dost blízko, že není žádný podstatný rozdíl.
Takže propojení právě přináší spoustu souborů dohromady
že samostatně obsahují všechny funkce je potřeba použít
a vytváří spustitelný soubor, který bude skutečně spustit.
>> A tak to také to, co jsme říkali před
kde můžete mít 1000. c soubory, kompilovat je všechny. o soubory,
která bude pravděpodobně chvíli trvat, pak změníte 1. c. souboru.
Jediné, co potřebujete překompilovat, že 1. C soubor a potom znovu všechno ostatní,
odkaz všechno dohromady.
[Student] Když jsme propojování píšeme lcs50?
Jo, tak lcs50. Ta vlajka signály linker, který by měl být spojující v této knihovně.
Otázky?
Už jsme přešli binární jiné než ty, které 5 sekund na první přednášce?
To si nemyslím.
Měli byste vědět, všechny velké Os, že jsme pryč přes,
a vy byste měli být schopni, kdybychom vám dal funkci,
měli byste být schopni říct, že je to velký O, zhruba. Nebo dobře, velký O je drsný.
Takže pokud jste vidět vnořené cykly for smyčkování přes stejný počet věcí,
jako int i, i <n; int j, j > [Student] n na druhou. >> To bývá n na druhou.
Pokud jste triple vnořené, to inklinuje být n cubed.
Takže tyhle věci byste měli být schopni poukázat okamžitě.
Musíte vědět, vložení druh bubliny a řazení a sloučit druh a všechny z nich.
Je to snazší pochopit, proč jsou ty, n na druhou a n log n a všechny, které
protože si myslím, že byl na testu jeden rok, pokud jsme v podstatě vám dal
provádění bublinkové druhu a řekl: "Co je doba chodu této funkce?"
Takže pokud jste uznat, že jako bubliny řadit, pak můžete okamžitě říci, n na druhou.
Ale pokud jste na něj jen podívají, vy ani nemusíte uvědomit, že je to bublina druhu;
stačí říct, je to dělá tohle a tohle. Toto je n na druhou.
[Student] Existují nějaké těžké příklady můžete přijít s,
jako podobné myšlenky přijít?
>> Nemyslím si, že bychom vám žádné nepříjemné příklady.
Bublina sort věc je asi tak těžké, jak bychom jít,
a dokonce i to, že tak dlouho, jak jste pochopili, že jste iterace pole
pro každý prvek v poli, který se bude něco, co se n na druhou.
Existují obecné otázky, jako tady máme - Oh.
Jen druhý den, Doug tvrdil, "jsem vymyslel algoritmus, který je možné třídit pole
"Zn čísel v O (log n) čas!"
Tak jak můžeme vědět, že to není možné?
[Neslyšitelné Student odpověď] >> Jo.
Přinejmenším, budete muset dotknout každý prvek v poli,
takže je možné třídit pole -
Pokud je vše v pořádku netříděného, ​​pak budete dotýkat všechno v poli,
takže je možné to udělat za méně než O n.
[Student] Ukázal jsi nám, že příklad, že jsou schopni to udělat v O n
pokud používáte velké množství paměti. Jo >>.
A to je - já zapomněl, co to je - je to počítání druh?
Hmm. To je celé číslo třídění algoritmus.
Hledal jsem zvláštní jména pro to, že jsem si nemohl vzpomenout minulý týden.
Jo. Jedná se o typy druhů, které mohou docílit věci ve velkém O n.
Ale existují omezení, jako je možné použít pouze celá čísla do určité číslo.
Plus, pokud se snažíte vyřešit něco to je -
Pokud váš pole je 012, -12, 151, 4000000,
pak, že jeden prvek bude zcela zničit celý třídění.
>> Otázky?
[Student] Pokud máte rekurzivní funkci, a to jen dělá rekurzivní volání
v rámci return, to je ocas rekurzivní,
a tak by nebylo využívají více paměti za běhu
, nebo by alespoň používat srovnatelné paměti jako opakující se řešení?
[Bowden] Ano.
Bylo by pravděpodobně poněkud pomalejší, ale ne tak docela.
Ocas rekurzivní je docela dobrý.
Se znovu podíváme stack snímků, řekněme, že máme hlavní
a máme int bar (int x), nebo tak něco.
To není dokonalý rekurzivní funkce, ale návrat bar (x - 1).
Tak samozřejmě, tohle je vadný. Musíte základní případy a tak.
Ale myšlenka je, že toto je ocas rekurzivní,
což znamená, že když hlavní hovory bar to dostane jeho stack frame.
V tomto zásobníku rámu to bude málo blok paměti
která odpovídá jeho argument x.
A tak řekněme, že hlavní stane volat bar (100);
Takže x bude začít jako 100.
Pokud kompilátor uznává, že je to ocas rekurzivní funkce,
pak, když bar dělá jeho rekurzivní volání bar,
namísto toho, aby nový zásobník rám, který je místo, kde zásobník začne růst do značné míry,
nakonec to bude probíhat do haldy a pak dostanete segfault chyb
protože paměť začíná srážet.
>> Takže místo toho, aby svůj vlastní zásobník rám, může si uvědomit,
hej, já nikdy muset vrátit k tomuto rámce fronty,
takže místo toho jsem si jen vyměnit tento argument s 99 a pak začít bar po celém těle.
A pak to bude dělat to znovu a dosáhnou návratu bar (x - 1),
a namísto toho, aby nový rámec fronty, bude to jen nahrazení současné argument s 98
a pak skočit zpět na začátku baru.
Tyto operace, které je nahradí hodnotu 1 na zásobníku a skákání zpět na začátek,
jsou docela účinné.
Takže je nejen to samé využití paměti jako samostatná funkce, která je interaktivní
proto, že jste pouze pomocí 1 zásobníku frame, ale nejste utrpení nevýhody
mít volání funkcí.
Volání funkce může být poněkud drahé, protože má tohle všechno nastavení
a teardown a všechny tyhle věci.
Tak tohle ocas rekurze je dobrá.
[Student] Proč to nevytváří nové kroky?
Vzhledem k tomu, že si uvědomuje, že není třeba.
Výzva k baru je jen vrací rekurzivního volání.
Takže to nemusí dělat nic s návratovou hodnotou.
Je to jen tak, aby okamžitě vrátit.
Tak to jen tak nahradit jeho vlastní argumentaci a začít znovu.
A také, pokud nemáte ocas rekurzivní verzi,
pak dostanete všechny tyto bary, kde, kdy tento ukazatel vrací
má vrátit jeho hodnotu na tento jeden, a pak, že bar se okamžitě vrátí
a vrátí jeho hodnotu na tento jeden, pak je to jen tak aby se okamžitě vrátil
a vrátí jeho hodnotu na tento jeden.
Takže šetříte to objevovat všechny tyto věci pryč zásobníku
protože vrácená hodnota je jen tak, aby byla přenesena celou cestu zpět stejně.
Tak proč ne jen vyměnit náš argument s aktualizovaným argumentu a začít znovu?
Pokud funkce není ocas rekurzivní, pokud děláte něco jako -
[Student], pokud bar (x + 1). Jo >>.
>> Takže pokud jste to ve stavu, pak děláte něco s návratovou hodnotou.
Nebo i když jste právě udělat návrat 2 * bar (x - 1).
Takže teď bar (x - 1) musí vrátit, aby se pro výpočet 2 krát, že hodnoty,
takže teď to potřebují svůj samostatný zásobník rám,
a nyní, bez ohledu na to, jak moc se snažíš, budete muset -
To není ocas rekurzivní.
[Student] Chtěl jsem zkusit přivést rekurzi usilovat o koncové rekurze -
[Bowden] V ideálním světě, ale v CS50 nemusíte se.
S cílem získat rekurze ocasu, obecně, můžete nastavit další argument
kde bar bude mít int x do y
a y odpovídá konečnému věc, kterou chcete vrátit.
Takže pak budete vracet bar (x - 1), 2 * y.
Takže je to jen na vysoké úrovni, jak transformovat věci byly ocas rekurzivní.
Ale navíc argument -
A pak na konci, když se dostanete na základní případ, stačí se vrátit y
protože jste se hromadí po celou dobu návratovou hodnotu, kterou chcete.
Tak nějak si to dělám iterativně, ale pomocí rekurzivní volání.
Otázky?
[Student] Možná o ukazatel aritmetický, stejně jako při použití řetězce. Jistě >>.
Ukazatel aritmetika.
Při použití řetězců je to snadné, protože řetězce jsou char hvězdy,
znaky jsou navždy a vždy jeden byte,
a tak ukazatel aritmetické je ekvivalentní k pravidelnému aritmetiky, když máte co do činění s řetězci.
Řekněme, že char * s = "hello".
Takže máme blok v paměti.
Je třeba 6 bajtů, protože se vždy potřebujete null terminátor.
A char * s se bude poukázat na začátku tohoto pole.
Takže s body tam.
Nyní, to je v podstatě, jak každý pole funguje,
bez ohledu na to, zda byl návrat do malloc nebo zda je to na zásobníku.
Každá řada je v podstatě ukazatel na začátek pole,
a pak každý pole operace, jakékoliv indexování, je jen tak do tohoto pole určité vyrovnání.
>> Takže když jsem řekl něco jako s [3], což bude s a počítání 3 znaky a.
Tak s [3], máme 0, 1, 2, 3, takže s [3] se bude ve vztahu k tomuto l.
[Student] A tak bychom mohli dosáhnout stejnou hodnotu tím, že dělá S + 3 a pak závorky star?
Ano.
To je ekvivalentní * (s + 3);
a že je navždy a vždy ekvivalentní bez ohledu na to, co děláte.
Už nikdy nebudete muset použít držák syntaxi.
Můžete vždy použít * (y + 3) syntax.
Lidé mají tendenci rád držáku syntaxi, ačkoli.
[Student] Takže všechny pole jsou vlastně jen ukazatele.
Tam je nepatrný rozdíl, když řeknu, int x [4]; >> [Student] Znamená to, že vytvořit paměť?
[Bowden] To bude vytvářet 4 ints ve frontě, tak 16 bytů celkově.
Bude to vytvořit 16 bajtů na zásobníku.
x není uloženo kdekoliv.
Je to jen symbol odkazuje na začátku věc.
Protože jste prohlásila, pole uvnitř této funkce,
co kompilátor udělá je jen nahradit všechny výskyty proměnné x
tam, kde se to stalo zvolit, aby těchto 16 bajtů.
Je možné to udělat s char * s, protože s je skutečný ukazatel.
Je zdarma ke přejděte na jiné věci.
x je konstantní. Nelze mít místo na jiném poli. >> [Student] Dobře.
Ale tato myšlenka, toto indexování, je stejná bez ohledu na to, zda je to tradiční pole
nebo jestli je to ukazatel na něco nebo jestli je to ukazatel na malloced pole.
A ve skutečnosti, že je tak ekvivalentní, že je rovněž jedno a totéž.
Je to vlastně jen znamená, co je uvnitř hranatých závorek a to, co zbylo z držáků,
je sečte, a dereferences.
Tak tohle je stejně platný jako * (y + 3), nebo s [3].
[Student] Můžete mít odkazy směřující na 2-rozměrné pole?
>> Je to těžší. Tradičně, no.
2-rozměrné pole je jen 1-rozměrné pole s nějakou pohodlnou syntaxi
protože když řeknu, int x [3] [3], je to opravdu jen 1 pole s 9 hodnotami.
A tak když jsem index, kompilátor ví, co mám na mysli.
Když řeknu, že x [1] [2], že ví, že chci jít do druhé řady, takže to bude přeskočit první 3,
a pak to chce druhý věc, takže to bude stáhni jeden.
Ale je to stále jen jedno-rozměrné pole.
A tak když jsem chtěl přiřadit ukazatel na daném poli,
Řekl bych, že int * p = x;
Typ x je jen -
Je to drsné říkat typ x, protože je to jen symbol, a to není skutečné proměnné,
ale je to jen int *.
x je jen ukazatel na začátek tohoto. >> [Student] Dobře.
A tak nebudu mít přístup [1] [2].
Myslím, že je zvláštní Syntaxe pro deklarování ukazatele,
něco směšné jako int (* p [-. něco naprosto směšné Já ani nevím.
Ale je tu Syntaxe pro deklarování ukazatele, jako se závorkami a věcí.
Dokonce se ani nemusí nechat udělat.
Jsem se mohl podívat zpět na něco, co by mi pravdu.
Podívám se na to později, pokud je syntaxe pro bod. Ale nikdy nebudete vidět.
A dokonce i syntaxe je tak archaický, že pokud budete používat, budou lidé zmateně.
Vícerozměrné pole jsou velmi vzácné, jak to je.
Jste docela hodně -
No, pokud děláte věci, matice to nebude vzácné,
ale v C budete jen zřídka bude používat vícerozměrná pole.
Jo. >> [Student] Řekněme, že máte opravdu dlouhou pole.
>> Takže ve virtuální paměti, že se zdá být vše po sobě jdoucích,
jako prvky přímo vedle sebe,
ale ve fyzickém paměti, že by bylo možné, že se rozešli? Ano >>.
Jak virtuální paměť funguje, je to jen odděluje -
Jednotka přidělení je stránka, která má tendenci být 4 KB,
a tak když proces říká, hej, já chci použít tuto paměť,
operační systém bude přidělí mu 4 KB pro toho malého bloku paměti.
Dokonce i když si jen použít jeden malý byte v celém bloku paměti,
operační systém se bude dát mu plné 4 KB.
Takže to, co to znamená, je, že jsem mohl mít - řekněme, že to je moje stack.
Tento zásobník může být oddělen. Můj stack může být megabajtů a megabyty.
Můj stack může být obrovský.
Ale stack sám má být rozdělen do jednotlivých stránek,
která, pokud se podíváme na tady řekněme, že to je naše RAM,
když mám 2 GB paměti RAM, je to skutečná adresa 0 jako 0. byte mého RAM,
a to je 2 GB všechny tady dole.
Takže tato stránka může odpovídat tomuto bloku sem.
Tato stránka může odpovídat tomuto bloku sem.
To by se dalo odpovídat tenhle sem.
Takže operační systém je zdarma přiřadit fyzické paměti
na jednotlivou stránku libovolně.
A to znamená, že pokud se tato hranice se stane rozkročit pole,
pole se stane být opuštěno to a právo tohoto pořadí stránky,
pak toto pole se bude rozdělena do fyzické paměti.
A pak se po ukončení programu, kdy proces skončí,
Tyto mapování se vymažou a pak je to zdarma využívat tyto malé bloky pro ostatní věci.
Další otázky?
[Student] Ukazatel aritmetika. >> Ach jo.
Řetězce bylo jednodušší, ale při pohledu na něco jako ints,
tak zpět do int x [4];
Ať už je to pole, nebo zda je to ukazatel na malloced pole celých čísel 4,
to bude zacházeno stejným způsobem.
[Student] Tak pole jsou na haldě?
[Bowden] Pole nejsou na haldě. >> [Student] Oh.
>> [Bowden] Tento typ pole má tendenci být na zásobníku
pokud jste prohlásil ji za - ignoruje globální proměnné. Nepoužívejte globální proměnné.
Uvnitř funkce říkám int x [4];
Bude to vytvořit 4-celé číslo bloku na zásobníku pro toto pole.
Ale to malloc (4 * sizeof (int)); se chystá jít na haldě.
Ale po tomto bodě mohu použít X a P v téměř stejným způsobem,
jiné než výjimek, které jsem řekl dříve, než o tom můžete přiřadit ks.
Technicky, jejich velikosti jsou poněkud odlišné, ale to je zcela irelevantní.
Nikdy jste vlastně používají své velikosti.
P Mohl bych říct, p [3] = 2, nebo x [3] = 2;
Můžete je použít v přesně stejným způsobem.
Takže ukazatel aritmetika nyní - Ano.
[Student] Líbí se vám nemusel dělat p * pokud máte držáky?
Konzole jsou implicitní dereference. Dobře >>.
Vlastně, i to, co říkáte, se můžete dostat vícerozměrných polí
s ukazateli, co můžete udělat, je něco jako, řekněme, int ** pp = malloc (sizeof (int *) * 5);
Já si jen napsat to všechno jako první.
Nechtěla jsem, že jeden.
Dobře.
Co jsem udělal, je zde - To by mělo být pp [i].
Takže pp je ukazatel na ukazatel.
Jste mallocing pb poukázat na pole 5 hvězdiček int.
Takže v paměti máte na zásobníku pp
Bude to poukázat na pole 5 bloků, které jsou všechno sami ukazatele.
A pak, když jsem malloc tady dole, jsem malloc, že ​​každý z těchto jednotlivých ukazatelů
by měla směřovat na samostatném bloku na 4 bajty na haldy.
Takže tento poukazuje na 4 bajty.
A tenhle ukazuje na odlišný 4 bajty.
>> A všechny z nich poukázat na jejich vlastní 4 bajty.
To mi dává způsob, jak dělat multidimenzionální věci.
Mohl bych říct, pp [3] [4], ale teď to není totéž jako multidimenzionální pole
protože vícerozměrné pole je přeložena [3] [4] do jediné posun do pole x.
Tento dereferences p, přistupuje třetí index, pak dereferences, že
a přístupy - 4 by neplatné - druhý index.
Vzhledem k tomu, kdy jsme měli int x [3] [4] jak před, tak vícerozměrné pole
a při poklepání držák je to opravdu jen jeden dereference,
jste po jediné ukazatel a pak offset,
je to opravdu 2D odkazy.
Můžete sledovat 2 samostatné ukazatele.
Tak to také technicky umožňuje mít multidimenzionální pole
kde každý jednotlivec je pole různé velikosti.
Takže si myslím, zubaté vícerozměrných polí je to, co se jmenuje
protože opravdu první věc, kterou by mohl směřovat k něčemu, co má 10 prvků,
Druhá věc by mohl směřovat k něčemu, co má 100 prvků.
[Student] Je nějaký limit na počet ukazatelů můžete mít
ukázal na jiné ukazatele? >> Ne
Můžete mít int ***** věst.
Zpět na ukazatel aritmetiky - >> [studentka] Oh. Jo >>.
[Student] Pokud mám int *** p a pak jsem udělat dereferencing a říkám p * je rovna této hodnotě,
je to jen bude dělat 1 úroveň dereferencing? Ano >>.
Takže když chci získat přístup k věci, že poslední ukazatel ukazuje na -
Pak si udělat *** p. Dobře >>.
Tak tohle je p poukazuje na 1 blok, poukazuje na jiného bloku, poukazuje na jiného bloku.
Pak, pokud to uděláte * p = něco jiného, ​​pak měníte to
Dosud poukázat na jiný blok. Dobře >>.
>> [Bowden] A pokud byly malloced, pak jste nyní unikly paměti
pokud se stalo, že mají různé odkazy na tyto
protože se nemůžete dostat zpět k těm ty, které jste právě zahodil.
Ukazatel aritmetika.
int x [4], se bude alokovat pole celých čísel 4
kde x bude poukázat na začátku pole.
Takže když jsem řekl něco jako x [1], já chci, aby to znamená jít do druhé celé číslo v poli,
který by byl tento.
Ale opravdu, to je 4 bytů do pole, protože to číslo zabírá 4 bajty.
Takže posun 1 opravdu znamená posun 1
krát větší než bez ohledu na typ pole je.
To je pole celých čísel, takže ví, jak udělat 1 krát velikost int, když chce kompenzovat.
Druhý syntaxe. Pamatujte si, že to je ekvivalentní * (x + 1);
Když řeknu, že kurzoru + 1, co to vrací je adresa, na kterou je ukazatel ukládání
plus 1 krát větší typu ukazatel.
Takže pokud x = ox100, pak x + 1 = ox104.
A můžete zneužívají a řekne něco jako char * c = (char *) x;
a nyní c bude stejná adresa jako x.
c bude rovna ox100,
ale c + 1 bude rovna ox101
od ukazatel aritmetický závisí na typu ukazatele, které jsou přidány k.
Takže c + 1, to vypadá na c, je to char ukazatel, takže to bude přidat 1 krát velikost char,
, která se vždy bude 1, takže budete mít 101,
vzhledem k tomu, když to udělám x, která je také stále 100, x + 1 bude 104.
[Student] Můžete použít c + +, aby se pokročilo ukazatel o 1?
Ano, můžete.
Můžete to udělat s x, protože x je jen symbol, je to konstanta, nemůžete změnit x.
>> Ale c stane být jen ukazatel, takže c + + je dokonale platné, a to bude zvyšovat o 1.
Je-li c bylo jen int *, pak c + + by se 104.
+ + Se ukazatel aritmetický stejně jako c + 1 by měl udělat ukazatel aritmetiku.
To je vlastně, jak hodně věcí, jako je druh korespondence -
Namísto vytváření kopií věcí, můžete místo toho projít -
Stejně jako když jsem chtěl, aby tuto polovinu pole - nechte se vymazat něco z toho.
Řekněme, že jsem chtěl, aby tuto stranu pole do funkce.
Co bych předat této funkci?
Pokud projdu x, jsem absolvování adresu.
Ale já chci, aby tuto konkrétní adresu. Tak co bych měl projít?
[Student] Pointer + 2?
[Bowden] Tak x + 2. Ano.
To je bude tato adresa.
Budete také velmi často vidí to jako x [2], a pak adresu toho.
Takže musíte mít adresu, protože držák je implicitní dereference.
x [2] se vztahuje na hodnotu, která je v tomto poli, a pak se má adresu tohoto pole,
takže říkáte & x [2].
Tak to je, jak se něco v druhu korespondence, kde chcete předat polovinu seznamu k něčemu
opravdu jen projít a x [2], a nyní pokud jde o rekurzivní volání se týká,
moje nové pole začíná tam.
Last minute otázky.
[Student] Pokud se nám nepodaří dát ampersand nebo - co je to jmenuje? >> Star?
[Student] Star. Technicky >>, dereference operátor, ale - >> [studentka] dereference.
>> Pokud nemáme dát hvězdu nebo ampersand, co se stane, když jsem jen říct, y = x, a x je ukazatel?
Jaký je typ y? >> [Student] Já si jen říct, že je ukazatel 2.
Takže pokud jste právě řekl y = x, x a y nyní ukazují na stejnou věc. >> [Student] Bod na stejnou věc.
A je-li x int ukazatel? >> To by si stěžovat, že není možné přiřadit ukazatele.
[Student] Dobře.
Pamatujte si, že ukazatele, i když jsme kreslit jako šípy,
Opravdu vše, co store - int * x - opravdu vše x je ukládání je něco jako ox100,
které jsme náhodou reprezentovat jako cílení na bloku uloženého v 100.
Takže když říkám int * y = x; jsem jen kopírování ox100 do y,
které jsme právě bude reprezentovat jako y, také ukázal na ox100.
A když řeknu, int i = (int) x, pak i se chystá uložit bez ohledu na hodnotu ox100 je
uvnitř ní, ale teď to bude vykládat jako celé číslo namísto ukazatele.
Ale budete potřebovat sádru, nebo jinde to bude stěžovat.
[Student] Tak to jste na mysli cast -
Je to bude obsazení int X i lití int na y?
[Bowden] Co?
[Student] Dobře. Po těchto závorkách je tam bude x, nebo ay tam?
>> [Bowden] Buď. x a y jsou rovnocenné. >> [Student] Dobře.
Vzhledem k tomu, že jsou oba ukazatele. Jo >>.
[Student] Tak to by uložit hexadecimální 100 v celé číslo formě? >> [Bowden] Jo.
Ale ne hodnota bez ohledu na to odkazuje.
[Bowden] Jo. >> [Student] Takže jen adresa ve formě celého čísla. Dobře.
[Bowden] Pokud byste chtěli z nějakého důvodu bizarní,
můžete zabývat výhradně s ukazateli a nikdy řešit s celými čísly
a prostě být jako int * x = 0.
Pak budete si opravdu zmatený, jakmile ukazatel aritmetický začne děje.
Takže čísla, která ukládají, jsou nesmyslné.
Je to jen, jak jste skončili jejich výklad.
Takže jsem volně kopírovat ox100 z int * na int,
a já jsem volný přiřadit - Jsi pravděpodobně bude dostat křičel na dobu odlévání -
Jsem volná přiřadit něco jako (int *) ox1234 do této svévolné int *.
Takže ox123 je stejně platná adresa paměti, jak je & y.
A y se stane vrátit něco, co je docela hodně ox123.
[Student] Bylo by to opravdu cool způsob, jak jít z šestnáctkové do desítkové podobě,
jako když máte ukazatel a obsadil ji jako int?
[Bowden] Můžete opravdu jen tisknout pomocí jako printf.
Řekněme, že mám int y = 100.
Takže printf (% d \ n - jako byste měli již víte - tisk, že jako celočíselné,% x.
Budeme jen vytisknout ji jako hexadecimální.
Takže ukazatel není uložena jako hexadecimální,
a číslo není uloženo jako desetinné.
Vše je uloženo jako binární.
Je to jen, že máme tendenci ukázat ukazatele jako hexadecimální
protože si myslíme, že věci v těchto 4-byte blocích,
a paměťové adresy mají tendenci, aby se seznámili.
My jsme jako, když začne s bf, pak se stane, že je v zásobníku.
Takže je to jen naše interpretace ukazatelů jako hexadecimální.
Dobře. Nějaká poslední otázky?
>> Budu tady na chvíli po, pokud máte něco jiného.
A to je konec, že.
>> [Student] Yay! [Potlesk]
>> [CS50.TV]