[Powered by Google Translate] [Oddiel 5 - Viac Comfortable]
[Rob Bowden - Harvard University]
[To je CS50. - CS50.TV]
>> Ako som povedal vo svojom e-mailu, existuje veľa vecí, ktoré môžete použiť
iné ako zariadenie skutočne robiť problémové súbory.
Odporúčame vám to v prístroji len preto, že potom môžeme ľahšie pomôže
a vieme, ako to všetko bude fungovať.
Ale ako jeden príklad, kde si môžete robiť veci, ak, povedzme, nemáte prístup
k spotrebiču, alebo chcete pracovať v suteréne Science Center -
ktoré vlastne majú prístrojom príliš -
Ak chcete pracovať kdekoľvek.
Jedným z príkladov je videli ste / počul SSH?
SSH je v podstate rovnako ako pripojenie k niečomu.
Vlastne, teraz som SSHed do prístroja.
Nikdy som pracovať priamo v prístroji.
Tu je spotrebič, a keď sa pozriete dole tu vidíte túto IP adresu.
Nikdy som pracovať v zariadení samotnom;
Vždy som prísť na iTerm2 okná / terminálovom okne.
Môžete SSH na túto IP adresu, ssh jharvard@192.168.129.128.
Pamätám si, že počet veľmi ľahko, pretože je to taký milý vzor.
Ale to bude opýtajte sa ma na moje heslo, a teraz som v spotrebiči.
V podstate, v tomto bode, ak otvoril terminál vo vnútri spotrebiča samotného,
toto rozhranie, ale mali by ste použiť ju, je presne rovnaká
ako rozhranie ja používam tu, ale teraz si SSHed.
Nemusíte sa pripojiť cez SSH na spotrebiče.
Jeden príklad na inom mieste by ste mohli SSH na je, že som si istá, že máte v predvolenom nastavení -
Oh. Väčší.
Všetci z vás by mal mať podľa účtov predvolené FAS na serveroch FAS.
Pre mňa, ja by som SSH rbowden@nice.fas.harvard.edu.
Je ťa opýtať, že prvýkrát, a poviete áno.
Moje heslo je len bude môj FAS heslo.
A tak teraz, som SSHed na pekné servery, a môžem si robiť, čo chcem tu.
Mnoho tried môžete vziať, rovnako ako 124, budú mať nahráte veci sem
skutočne predložiť svoje problémové sady.
Ale povedať, že nemáte prístup k vášmu prístroju.
Potom môžete robiť veci, ako je tu to bude hovoriť -
To je len naša časť otázok.
To sa vás spýta, ako to urobiť v spotrebiči.
Namiesto toho som si len to na serveri.
Idem k rozbalenie, že.
Problém bude, že ste zvyknutí používať niečo ako gedit
alebo čo vnútri zariadenia.
Nebudete mať, že na FAS serveri.
Je to všetko len bude to textové rozhranie.
Takže by ste mohli buď jeden, skúste sa naučiť textového editora, ktorý oni majú.
Majú Nano.
Nano je zvyčajne veľmi ľahko ovládateľný.
Môžete použiť šípky a zadajte normálne.
Takže to nie je ťažké.
Ak chcete získať naozaj fantázie môžete použiť Emacs,
ktoré som asi nemal otvoriť, pretože ja ani neviem, ako ukončiť Emacs.
Ovládanie X, Control C? Jo.
Alebo môžete použiť Vim, čo je to, čo mám použiť.
A tak to sú vaše možnosti.
Ak nechcete robiť, že môžete tiež, keď sa pozriete na manual.cs50.net--
Oh.
Na počítači, môžete pomocou SSH PuTTY,
ktoré budete musieť stiahnuť zvlášť.
Na Macu, stačí Terminal predvolené použitie, alebo si môžete stiahnuť iTerm2,
ktorý je ako pekné, efektné terminálu.
Ak pôjdete do manual.cs50.net uvidíte odkaz na Notepad + +,
čo je to, čo môžete použiť na počítači.
To vám umožní SFTP z Notepad + +, ktorý je v podstate SSH.
Čo to vám umožní urobiť, je upravovať svoje súbory lokálne,
a potom zakaždým, keď chcete uložiť, bude to ušetrí až nice.fas,
kde potom môžete spustiť.
A odpovedá na Mac bude TextWrangler.
Tak to vám umožní urobiť to isté.
To vám umožní upravovať súbory lokálne a uložiť ich do nice.fas,
kde potom môžete spustiť.
Takže ak ste niekedy uviazol bez zariadenia, máte tieto možnosti
na stále robiť svoje problémové sady.
Jeden problém bude, že nebudete mať CS50 knižnicu
pretože nice.fas nemá v predvolenom nastavení majú, že.
Môžete buď stiahnuť CS50 knižnice -
Ja si nemyslím, že je potrebné, aby v tomto bode.
Môžete buď stiahnuť CS50 knižnicu a skopírujte ho do nice.fas,
alebo som si, že v tomto bode nemáme používať už tak ako tak.
Alebo ak áno, môžete v súčasnej dobe ho nahradiť
Implementácia týchto funkcií v CS50 knižnici tak ako tak.
Takže by nemal byť tak veľký obmedzenia.
A to je, že.
>> Vrátim sa do spotrebiča teraz, budeme robiť všetko, čo v spotrebiči.
Pri pohľade na našu sekciu otázok, na začiatku, ako som povedal vo svojom e-mailu,
musíme si pohovoriť o jednej skratke ste sa mali pozerať.
Máme presmerovanie a rúrky a tieto tri otázky.
>> Ak chcete, ktoré prúd sa funkcie ako printf písať v predvolenom nastavení?
Tak stream. Čo je prúd?
Prúd je v podstate taká, že je to len nejaký -
Nie je to ani zdrojom 1s a 0s.
Prúd, ktorý sa pýta na tú je štandardný výstup.
A tak štandardný výstup je prúd, ktorý pri písaní na to,
sa objaví na obrazovke.
Štandardné, tým, že prúd, znamená to, že stačí napísať 1s a 0s k nemu,
a druhý koniec štandardný výstup len číta z tohto prúdu.
Je to len reťazec 1s a 0s.
Môžete písať do vodných tokov, alebo si môžete prečítať z potokov
v závislosti na tom, čo prúd vlastne je.
Zvyšné dva Predvolené toky sú štandardne a štandardné chyby.
Štandardné in je vždy, keď to GetString, je to na vás čaká na vstup veci.
Tak to vás čaká, je to vlastne čaká na štandarde,
čo je naozaj to, čo dostanete, keď zadáte na klávesnici.
Píšete do štandardu palcov
Štandardná chyba je v podstate ekvivalentná štandardný výstup,
ale je to špecializované v tom, že pri tlači na štandardný chybový výstup,
ste mali tlačiť iba chybové správy, ktoré
takže môžete rozlíšiť medzi pravidelnými správami tlačených na obrazovku
proti chybových správ v závislosti na tom, či šli do štandardný výstup alebo štandardnou chybou.
Súbory taky.
Štandardný výstup, štandardný v, a štandardná chyba je len zvláštne prúdy,
ale naozaj akýkoľvek súbor, pri otvorení súboru, to sa stáva prúd bajtov
, Kde môžete len čítať z tohto prúdu.
Tie, pre najviac sa rozdeliť, môže len myslieť súboru ako prúd bajtov.
Takže to, čo toky sa píšu v predvolenom nastavení? Štandardný výstup.
>> Aký je rozdiel medzi> a >>?
Vari niekto sledovať video vopred? Dobre.
> So bude, ako presmerovať do súborov,
a >> bude tiež presmerovať výstup do súboru,
ale je to miesto bude pripojiť k súboru.
Napríklad, povedzme, že som náhodou dict tu,
a jediný veci vnútri dict je mačka, mačka, pes, ryba, pes.
Jeden príkaz, že máte v príkazovom riadku je mačka,
ktorý je len tak vytlačiť to, čo je v súbore.
Takže keď hovorím mačka dict, že to bude tlačiť mačka, mačka, pes, ryba, pes. To je všetko, mačka robí.
To znamená, že pre tlač na štandardný výstup mačka, mačka, pes, ryba, pes.
Keby som namiesto toho chcete presmerovať, že do súboru, môžem použiť> a presmerovať ju na čo je súbor.
Zavolám súbor súbor.
Takže teraz, keď ja ls, uvidím Mám nový súbor s názvom súboru.
A keď som ho otvoríte, bude to mať presne to, čo mačky dal na príkazovom riadku.
Takže teraz keď to urobím znovu, potom to bude presmerovať výstup do súboru,
a budem mať rovnaký presne to.
Takže technicky to úplne nedbala toho, čo sme mali.
A uvidíme, či zmením dict, som vytiahol psa.
Teraz, keď sme sa mačka dict do súboru znova, budeme mať novú verziu s pes odstránené.
Tak to úplne potlačí ho.
Namiesto toho, ak budeme používať >>, bude to pripojiť súbor.
Teraz, otváranie súboru, vidíme, máme len samé tlačenej dvakrát
pretože tam bol raz, potom sme pripojená k originálu.
Tak to je to, čo> a >> robiť.
Má ďalšie sa opýtať - to nie je to opýtať.
>> Druhý, ktorý máme, je <, ktorá, ak> presmeruje štandardný výstup,
<Sa bude presmerovanie štandardu a
Uvidíme, či sa máme príklad.
Dokážem písať jedného naozaj rýchlo.
Poďme sa ľubovoľný súbor, hello.c.
Relatívne jednoduché súboru.
Ja som len na to, reťazec a potom tlač "Hello", čo reťazec som vstúpil bol.
Takže si ahoj a potom. / Hello.
Teraz to výzva, aby som zadať niečo,
čo znamená, že čaká na veci, ktoré majú byť zapísané do štandardu palcov
Takže zadať čo chcem do štandardu dovnútra sme len povedať Ahoj, Rob!
Potom sa tlačí na štandardný výstup Hello, Robe!
Ak to urobím. / Hello a potom presmerovať,
zatiaľ môžete iba presmerovať zo súboru.
Takže keď som dal v nejakom súbore, txt, a dal som Roba,
keď spustím ahoj a potom presmerovať súbor txt do. / hello, to bude hovoriť Hello, Rob! okamžite.
Keď sa prvýkrát dostane do GetString a to čakanie na štandarde v,
štandard v už čaká na klávesnici dát dostať zadaných.
Namiesto toho, sme presmerovaní štandardom pre čítanie zo súboru txt.
A tak to bude čítať zo súboru txt, ktorý je len čiara Rob,
a potom to bude tlačiť Hello, Rob!
A keby som chcel, mohol by som tiež urobiť. / Hello <txt
a potom štandardné na to, že je to tlač, ktorý je Ahoj, Robe!,
Môžem presmerovať, že do vlastného súboru.
Ja si len zavolať na súbor hello - nie, nebudem, pretože to je spustiteľný - txt2.
Teraz, txt2 bude mať výstup. / Dobrý deň, <txt, ktorý sa bude Hello, Rob!
>> Otázky?
>> Dobre. Takže tu máme potrubia.
Rúrky sú posledné jednotka presmerovanie.
>> Oh. Myslím, že jeden jednotka presmerovanie, ak je miesto> tie 2>,
že je presmerovanie štandardná chyba.
Takže ak sa niečo na štandardný chybový výstup, dopadlo by to dať do txt2.
Všimnime si ale, či som to 2>, potom je to stále tlače Ahoj, Rob! do príkazového riadku
pretože som len presmerovanie štandardné chybu, ja nie som presmerovanie normu von.
Štandardná chyba a štandardný výstup sa líšia.
Ak by ste chceli, aby skutočne písať na štandardný chybový výstup,
potom by som mohol zmeniť to byť fprintf na stderr.
Takže printf, v predvolenom nastavení, vytlačí na štandardný výstup.
Ak chcem tlačiť na štandardný chybový výstup ručne, potom musím použiť fprintf
a určiť, čo chcem tlačiť.
Ak namiesto toho som fprintf stdout, potom je to v podstate rovnocenné printf.
Ale fprintf na štandardný chybový výstup.
Takže teraz, keď som presmerovať to na txt2, Hello, Rob! stále dostáva vytlačený v príkazovom riadku
pretože je dostať vytlačené na štandardný chybový výstup, a ja som len presmerovanie štandardný výstup.
Keby som teraz presmerovať štandardný chyba, teraz to nedostal tlačený, a txt2 bude Hello, Rob!
Takže teraz, môžete tlačiť skutočné chyby na štandardný chybový výstup
a tlačiť pravidelné správy na štandardný výstup.
A tak pri spustení programu, môžete ho spustiť ako. / Hello tento typ s 2>
tak, aby váš program bude bežať normálne,
ale nejaké chybové správy, ktoré dostanete, môžete zistiť neskôr v protokole chýb,
tak chyby, a potom sa pozrite neskôr a vaše chyby súbor bude mať nejaké chyby, ktoré sa stali.
>> Otázky?
>> Posledný z nich je rúrka, ktorá si môžete myslieť, ako že sa normu z jedného príkazu
, Ktorá je tak štandard ďalšieho príkazu.
Príkladom je echo je príkazový riadok vec
, Ktorý je len tak echo, čo som dal ako svoj argument. Nebudem dať úvodzovky.
Echo bla, bla, bla je len tak tlačiť bla, bla, bla.
Predtým, keď som povedal, že som musel dať Roba do txt súboru
pretože môžem len presmerovať súbory s príponou TXT, miesto, / keď som echo Rob
a potom potrubie je do. / hello, bude to tiež urobiť rovnaký typ veci.
To je v súčasnej dobe výstup tohto príkazu, echo Rob,
a používať to ako vstup pre. / hello.
Môžete si ju predstaviť ako prvý presmerovanie echo Roba do súboru
a potom zadajte do. / hello tohto súboru, ktorý bol práve na výstupe.
Ale to má dočasný súbor z obrázku.
>> Otázky týkajúce sa, že?
>> Ďalšia otázka sa bude týkať tohto.
Čo potrubie môžete použiť na vyhľadanie počet unikátnych mien v súbore s názvom names.txt?
Príkazy budeme chcieť použiť tu sú jedinečné, tak UNIQA, a potom wc.
Môžete to urobiť man UNIQA skutočne pozrieť na to, čo robí, že,
a to len tak filtruje susediace zhodné riadky od vstupu.
A človek wc bude tlačiť znak nového riadku, slovo, a počet bajtov pre každý súbor.
A posledný budeme chcieť použiť je niečo,
ktorý sa bude len trochu riadky súboru txt.
Ak urobím nejaký súbor txt, names.txt, a to Rob, Tommy, Joseph, Tommy, Joseph, RJ, Rob,
to, čo chcem urobiť je zistiť počet unikátnych mien v tomto súbore.
Takže to, čo by mala byť odpoveď? >> [Študent] 4. Jo >>.
Malo by byť 4 od Roba, Tommy, Josef, RJ sú iba jedinečné názvy v tomto súbore.
Prvým krokom, keď som jednoducho počet slov na names.txt,
je to vlastne hovorí mi všetko.
To je vlastne tlač - Poďme sa pozrieť, man wc - nové riadky, slová, a byte počet.
Keby som len o vedení, potom som si len urobiť wc-l names.txt.
Tak to je krok 1.
Ale ja nechcem, aby wc-l names.txt pretože names.txt len ​​obsahuje všetky názvy,
a chcem odfiltrovať žiadne non-jedinečné ty.
Takže ak som to UNIQA names.txt, že nie je úplne daj mi to, čo chcem
pretože duplikované názvy sú stále tam.
Prečo je to? Prečo sa Uniqa nie je robiť to, čo chcem?
[Študent] duplicity nie [nepočuteľné] >> Jo.
Nezabudnite si man stránku pre UNIQA hovorí filtruje susediace zhodné riadky.
Sú spolu nesusedia, takže to nebude filtrovať.
Keby som triediť je prvý, sort names.txt bude dať všetky duplicitné riadky dohromady.
Takže teraz trochu names.txt je.
Budem chcieť, aby ho použiť ako vstup do UNIQA, ktorý je | Uniqa.
To mi dáva Jozefa, RJ, Rob, Tommy,
a chcem ho použiť ako vstup do wc-l,
ktoré sa bude dať mi 4.
Rovnako ako tu sa píše, čo by mohlo potrubia použiť?
Môžete si urobiť veľa vecí, ako pomocou série príkazov
kde použiť výstup z jedného príkazu ako vstup do ďalšieho príkazu.
Môžete si urobiť veľa vecí, veľa chytrých vecí.
>> Otázky?
Dobre.
To je to pre potrubia a presmerovanie.
>> Teraz pôjdeme na skutočné veci, kódovanie stuff.
Vnútri tohto PDF, uvidíte tento príkaz,
a budete chcieť spustiť tento príkaz vo vašom prístroji.
wget je príkaz pre len dostať niečo z internetu, v podstate,
tak wget a to URL.
Ak ste šiel na túto adresu URL v prehliadači, bolo by to stiahnuť tento súbor.
Len som klikol na to, tak to stiahli súbor pre mňa.
Ale písanie wget tejto veci vnútri terminálu
sa práve chystá stiahnuť do svojho terminálu.
Mám section5.zip, a budete chcieť rozbaliť section5.zip,
ktoré sa bude dať vám zložku s názvom section5,
ktorá bude mať všetky súbory sa budeme používať dnes vnútri nej.
Ako súborov tieto programy "názvy napovedajú, že sú trochu buggy,
Takže vašou úlohou je prísť na to, prečo používať gdb.
Má všetky nechať stiahnuť / vedieť, ako sa dostať je k stiahnutiu
do ich zariadenia? Dobre.
>> Beh ./buggy1, bude hovoriť Segmentation fault (core dumpingové),
ktorý zakaždým, keď sa segfault, je to zlá vec.
Za akých okolností by ste si segfault?
[Študent] Nepriamy odkaz nulový ukazovateľ. Jo >>. Takže to je jeden príklad.
Nepriamy odkaz nulový ukazovateľ Budeš sa dostať segfault.
Čo segfault znamená je, že sa dotknete pamäte by ste nemali dotýkať.
Takže dereferencing nulový ukazovateľ sa dotýka adresu 0,
av podstate všetky počítače v súčasnej dobe povedať, že adresa 0 je pamäť, ktorú ste nemali dotýkať.
Takže to je dôvod, prečo dereferencing nulový ukazovateľ výsledkov v segfault.
Ak sa vám stalo, nie je inicializovať ukazovateľ, potom to má na odpadky hodnotu,
a tak pri pokuse o dereferencia to, so všetkou pravdepodobnosťou ste sa dotknete pamäte
že je uprostred ničoho.
Ak sa vám stalo, šťastie a odpadky hodnota
stalo poukázať na niekde na fronte, alebo tak niečo,
potom, keď dereferencia, že ukazovateľ, ktorý ste nebol inicializovaný,
nič pokaziť.
Ale ak je to ukázal na, povedzme, niekde medzi zásobníka a haldy,
alebo je to ukazuje len niekde, že nebol použitý ani programu ešte,
potom ste sa dotknete pamäť, nemali by ste sa dotýkať a segfault.
Ak napísať rekurzívne funkciu, a to recurses príliš mnohokrát
a váš stack rastie príliš veľký a zásobník zrazí do vecí
že by nemal byť kolízie s, ste dotýka pamäti by ste nemali dotýkať,
takže segfault.
To je to, čo segfault je.
>> Je to tiež z rovnakého dôvodu, že ak máte reťazec v tvare -
Poďme sa vrátiť k predchádzajúcemu programu.
Vo hello.c--ja len tak, aby sa niečo iné.
char * s = "hello world!";
Ak mám použiť * s = niečo alebo s [0] = 'X';
tak, aby ahoj,. / hello, prečo sa to segfault?
Prečo sa to segfault?
Čo by ste očakávať, že sa stane?
Ak som printf ("% s \ n", s); čo by ste očakávať, že bude tlačiť?
[Študent] X ahoj. Jo >>.
Problém je, že pri deklarovaní reťazec, ako je tento,
s je ukazovateľ, ktorý pôjde na stack,
a čo s ukazuje na to je reťazec, ktorý je obsiahnutý v neprepisovateľné pamäti.
Takže len podľa mena, len pre čítanie pamäte, mali by ste mať predstavu
, Že ak sa pokúsite zmeniť to, čo je v read-only pamäte,
robíte niečo, čo by nemal robiť s pamäťou a segfault.
To je vlastne veľký rozdiel medzi char * s a char s [].
Takže char s [], teraz tento reťazec sa bude klásť na zásobníku,
a zásobník je len na čítanie, čo znamená, že by to malo fungovať úplne v poriadku.
A to robí.
Pamätajte si, že keď som si char * s = "hello world!", S sám je na zásobníku
ale s bodmi niekam inam, a že niekde inde sa stane, že len na čítanie.
Ale char s [] je jednoducho niečo, na zásobníku.
Takže to je ďalší príklad segfault deje.
>> Videli sme, že ./buggy1 vyústila v segfault.
Teoreticky, nemali by ste sa pozrieť na buggy1.c okamžite.
Namiesto toho sa pozrieme na to cez gdb.
Všimnite si, že keď sa dostanete Segmentation fault (core dumpingové),
si stiahni súbor sem volal jadro.
Ak by sme ls-l, uvidíme, že jadro je obvykle docela veľký súbor.
To je počet bajtov v súbore, takže to vyzerá, že je to 250-niečo kilobajtov.
Dôvodom je, že to, čo core dump je v skutočnosti
je, keď váš program havaruje, stav pamäti programu
len dostane skopírovať a vložiť do tohto súboru.
To dostane vyhodený do tohto súboru.
Tento program, zatiaľ čo bol spustený, sa stalo mať využitie pamäti asi 250 kb,
a tak to je to, čo dostal kopačky do tohto súboru.
Teraz sa môžete pozrieť na tomto súbore, ak budeme robiť gdb buggy1 jadro.
Môžeme jednoducho gdb buggy1, a že bude len spustenie gdb pravidelne,
pomocou buggy1 ako jeho vstupný súbor.
Ale ak si gdb buggy1 jadro, potom je to konkrétne ide naštartovať gdb
pri pohľade na tento základný súbor.
A hovoríte buggy1 znamená gdb vie, že jadro súboru pochádza z buggy1 programu.
Takže gdb buggy1 jadro bude okamžite priniesť nám
kde program stalo ukončiť.
Vidíme tu Program ukončený signálom 11, Segmentation fault.
Sme sa ocitli na rad zhromaždenie, ktoré pravdepodobne nie je príliš užitočné.
Ale ak zadáte BT alebo backtrace, že to bude funkcia
ktorý nám dáva zoznam našich aktuálnych zásobníka snímok.
Tak backtrace. Vyzerá to, že máme len dve stack rámy.
Prvý z nich je naša hlavná rámec frontu,
a druhý je zásobník rám pre túto funkciu, ktorá sa stane, že je v,
ktorý vyzerá ako máme iba montážny kód.
Tak poďme späť do našej hlavnej funkcie,
a to, že môžeme urobiť rámik 1, a myslím, že môžeme tiež urobiť dolu,
ale skoro nikdy to dole - alebo nahor. Jo.
Hore a dole. Až vám prináša jednu zásobníka snímku, dole sa dostanete dole zásobníka rám.
Mám vo zvyku nikdy použiť.
Len som konkrétne povedať, rám 1, ktorá je ísť do rámu s označením 1.
Rám 1 bude, aby nás do hlavného zásobníka rámu,
a hovorí, že tu na riadok kódu sme náhodou byť.
Ak by sme chceli ešte pár riadkov kódu, môžeme povedať zoznamu,
a že sa to nám všetkým riadky kódu okolo neho.
Linka sa segfaulted na to 6:
if (strcmp ("CS50 skaly", ArGV [1]) == 0).
Ak to nie je zrejmé ešte, môžete si ho rovno odtiaľ len tým, že myslí, prečo je segfaulted.
Ale môžeme si to ešte o krok ďalej a povedať, "Prečo by ArGV [1] segfault?"
Poďme tlač ArGV [1], a vyzerá to, že je to 0x0, ktorý je nulový ukazovateľ.
Sme strcmping CS50 skaly a NULL, a tak že to bude segfault.
A prečo je ArGV [1] null?
[Študent] Pretože sme nemali dať žiadne argumenty príkazového riadku.
Jo. Nechceli sme dať žiadne argumenty príkazového riadku.
Takže ./buggy1 len bude mať ArGV [0] bude ./buggy1.
To nebude mať ArGV [1], tak, že to bude segfault.
Ale ak, namiesto toho som robiť len CS50, že to bude hovoriť Získate D
pretože to je to, čo má urobiť.
Pri pohľade na buggy1.c, to má tlačiť "Dostanete D" -
Ak ArGV [1] nie je "CS50 skaly", "Dostanete D", inak "Tu získate!"
Takže ak chceme, musíme to porovnať ako pravdivé,
, Čo znamená, že je v porovnaní s 0.
Takže ArGV [1] musí byť "CS50 skaly".
Ak chcete urobiť, že na príkazovom riadku, budete musieť použiť \ uniknúť priestor.
Takže CS50 \ skaly a dostanete A!
Ak nechcete robiť spätné lomítko, prečo to nefunguje?
[Študent] Je to dva rôzne argumenty. Jo >>.
ArGV [1] bude CS50, a ArGV [2] bude skaly. Dobre.
>> Teraz ./buggy2 bude segfault znovu.
Namiesto otvorenia sa svojej hlavnej súboru, budeme len otvoriť buggy2 priamo,
tak gdb buggy2.
Teraz, keď sme len spustiť náš program, potom to bude hovoriť Program prijímaného signálu SIGSEGV,
ktorý je segfault signál, a to je miesto, kde sa stalo stalo.
Pri pohľade na naše backtrace, vidíme, že sme boli vo funkcii oh_no,
ktorý bol povolaný funkcie Dinky, ktorý bol nazývaný pomocou funkcie Binkym,
ktorý bol povolaný hlavné.
Môžeme tiež vidieť argumenty týchto funkcií.
Argument bezvýznamné a Binky bola 1.
Ak by sme zozname funkciu oh_no, vidíme, že oh_no je len to, char ** S = NULL;
* S = "BOOM";
Prečo by to zlyhanie?
[Študent] Nemôžete dereferencia null ukazovateľ? Jo >>.
To je len hovorí s je NULL, bez ohľadu na to, ak sa to stane, že je char **,
ktoré, v závislosti na tom, ako interpretovať to, mohlo by to byť ukazovateľ na ukazovateľ na reťazec
alebo pole reťazcov.
Je to s je NULL, takže * s je dereferencing nulový ukazovateľ,
a tak to bude pád.
To je jeden z najrýchlejších spôsobov, ako môžete prípadne segfault.
Je to jednoducho prehlasuje, že nulový ukazovateľ a okamžite segfaulting.
To je to, čo oh_no robí.
Ak pôjdeme do jednej snímky, potom budeme dostať do funkcie, ktorá je volaná oh_no.
Musím to urobiť, aby sa.
Ak nezadáte príkaz a vy jednoducho stlačiť Enter znova,
to bude len opakovať predchádzajúci príkaz, ktorý ste spustili.
Sme v ráme 1.
Výpis tohto rámu, tu vidíme, je naša funkcia.
Môžete hit zoznam znovu, alebo si môžete urobiť zoznam 20 a bude obsahovať viac.
Funkcia dinky hovorí, že ak je aj 1, potom prejdite na funkciu oh_no,
iný ísť do Slinky funkciu.
A my vieme, aj je 1, pretože sme sa ocitli na tu
že dinky bola volaná s argumentom 1.
Alebo môžete jednoducho vytlačiť aj, a to bude hovoriť aj je 1.
Sme v súčasnej dobe v Dinky, a ideme ak do ďalšieho snímku, vieme, že skončíš v Binkym.
Up. Teraz sme v Binkym.
Výpis túto funkciu - zoznam z pred pol ma prerušil -
Začalo to ako keď som je 0, potom budeme hovoriť, že oh_no, inak volajte hezoučký.
Vieme, že som bol 1, tak to je volané hezoučký.
A teraz sme späť v hlavnom, a hlavné je len bude int i = rand ()% 3;
To je len tak, aby vám náhodné číslo, ktoré je buď 0, 1, alebo 2.
Bude to hovoriť Binky s týmto číslom, a to vráti 0.
Pri pohľade na to,
len prechádzky programu ručne bez spustenia okamžite,
by ste nastaviť bod zlomu na hlavné, čo znamená, že keď sme sa spustiť program
váš program beží až kým nenarazí na bod prerušenia.
Takže spustenie programu, bude to bežať a potom to bude hit hlavné funkcie a zastaviť beh.
Teraz sme vo vnútri hlavnej, a krok, alebo vedľa sa chystá priviesť nás na ďalší riadok kódu.
Môžete to urobiť krok alebo ďalšie.
Biť ďalší, teraz som bol nastavený na rand ()% 3, a tak môžeme vytlačiť hodnotu i,
a to bude hovoriť aj je 1.
Teraz to záleží, či budeme používať nasledujúce alebo krok.
Myslím, že by na tom záležalo v predchádzajúcom, ale budeme chcieť použiť ďalšie.
Ak budeme používať krok, sme krok do funkcie, čo znamená, že pozrieť sa na skutočné veci
, Čo sa deje vo vnútri Binkym.
Ak sa používajú nasledujúce, potom to znamená prejsť funkciu
a jednoducho ísť na ďalší riadok kódu v našej hlavnej funkcie.
Práve tu na tejto trati, bol som na miesto, kde sa hovorí rand ()% 3;
keby som to urobil krok, bolo by to ísť do realizácie rand
a pozrieť sa na to, čo sa tam deje, a ja som mohol šliapnuť pomocou funkcie rand.
Ale ja sa nestarám o funkciu rand.
Ja len chcem ísť na ďalší riadok kódu v hlavnej, tak som použiť ďalší.
Ale teraz som to stará o Binky funkciu, takže chcem, aby krok do toho.
Teraz som v Binkym.
Prvý riadok kódu je povedať if (i == 0), som o krok,
vidíme, skončí na Dinky.
Ak sme zoznam vecí, vidíme, že čítal je i = 0.
i nie je rovné 0, tak to šlo do iného stavu,
ktorá sa bude volať Dinky (i).
Môžete sa zmiasť.
Ak stačí sa pozrieť na týchto tratiach priamo, možno si myslíte, že if (i == 0),
v poriadku, potom som urobil krok, a teraz som na Dinky (i),
si môže myslieť, že musí znamenať i = 0, alebo tak niečo.
Nie Ide o to, že vie, že môže prilepiť priamo na riadok Dinky (i).
Vzhľadom k tomu, aj nie je 0, je ďalším krokom nebude končiť na ostatnému.
Else nie je položka, že to bude zastaviť na.
Je to jednoducho ísť na ďalší riadok môže skutočne spustiť, čo je hezoučký (i).
Vstup do Dinky (i), uvidíme, či (i == 1).
Vieme, i = 1, takže keď sme krok, vieme, že skončíme v oh_no
pretože i = 1 volá funkciu oh_no, ktoré môžete vstúpiť do,
ktorý sa bude nastavenie char ** s = NULL a okamžite "BOOM".
A potom vlastne sa pozerať na vykonávanie buggy2,
to, aj sa len na to, náhodné číslo - 0, 1, alebo 2 - volanie Binky,
ktorá keď sa aj 0 volá oh_no, inde to volá hezoučký, ktorý príde sem.
Ak aj je 1, výzva oh_no, inak volajte Slinky, ktorý príde sem,
ak je aj 2, volajte oh_no.
Neviem ani, že existuje spôsob, ako -
Má niekto vidí spôsob, ako robiť to program, ktorý nebude segfault?
Pretože ak som niečo chýba, ak je aj 0, budete okamžite segfault,
inak idete do funkcie, ktorá, ak aj je 1 ste segfault,
inak idete do funkcie, ak je aj 2 si segfault.
Takže bez ohľadu na to, čo robíte, budete segfault.
>> Myslím, že jeden spôsob, ako sa uvádza, že by miesto toho robil char ** S = NULL,
môžete malloc priestor pre tento reťazec.
Mohli by sme urobiť malloc (sizeof) - sizeof čo?
[Študent] (char) * 5? >> Znamená to nezdá správne?
Ja som za predpokladu, že to bude fungovať, ak som vlastne bežal, ale to nie je to, čo som hľadal.
Pozrite sa na typ s Dodajme, int *, takže int * x.
Ja by som to malloc (sizeof (int)).
Alebo keď som chcel pole 5, by som to (sizeof (int) * 5);
Čo keď mám int **?
Čo by som malloc?
[Študent] Veľkosť ukazovatele. Jo >>. (Sizeof (int *));
Rovnaká vec sa tu.
Chcem (sizeof (char *));
To bude prideliť priestor pre ukazovateľ, ktorý ukazuje na "BOOM".
Nepotrebujem prideliť priestor pre "BOOM" sám
pretože to je v podstate ekvivalentná tomu, čo som povedal predtým
char * x = "BOOM".
"BOOM" už existuje. Stáva sa, že existujú v read-only oblasti pamäte.
Ale to už existuje, čo znamená, že tento riadok kódu, ak S je char **,
potom * s je char * a vy nastavenie tohto char * poukázať na "BOOM".
Ak by som chcel kopírovať "BOOM" do s, potom budem musieť prideliť priestor pre s
Urobím * s = malloc (sizeof (char) * 5);
Prečo 5?
Prečo nie 4? Vyzerá to, že "BOOM" je 4 znaky. >> [Študent] null znak.
Jo. Všetky vaše reťazcov budú potrebovať null charakter.
Teraz môžem urobiť niečo ako strčí - Aká je funkcia pre kopírovanie reťazca?
[Študent] CPY? >> Strcpy.
muž strcpy.
Takže strcpy alebo strncpy.
strncpy je trochu bezpečnejšie, pretože môžete presne špecifikovať, koľko znakov,
ale tu to nevadí, pretože vieme.
Takže strcpy a pozrieť sa do argumentov.
Prvý argument je náš cieľ.
Druhý argument je naším zdrojom.
Budeme kopírovať do nášho cieľového * S ukazovateľ "BOOM".
Prečo by si to chcete urobiť s strcpy miesto práve to, čo sme mali predtým
z * s = "BOOM"?
K dispozícii je dôvod, prečo budete chcieť urobiť, ale čo je to dôvod?
[Študent] Ak chcete niečo zmeniť v "BOOM". Jo >>.
Teraz môžem urobiť niečo ako s [0] = 'X';
pretože s bodmi do haldy a že priestor na halde, ktorá je ukazuje na
je ukazovateľ na ďalšie miesta na halde, ktorá je ukladanie "BOOM".
Takže to kópia "boom" je uložený v halde.
Tam sú technicky dve kópie "boom" v našom programe.
Tam je prvý, ktorý sa práve daný touto "BOOM" reťazcová konštanta,
a druhú kópiu "BOOM", strcpy vytvoril kópiu "BOOM".
Ale kópie "boom" je uložený na halde, a haldy máte možnosť zmeniť.
Halda je len na čítanie, tak to znamená, že s [0]
sa chystá nechať zmeniť hodnotu "BOOM".
Bude to nechať zmeniť tieto znaky.
>> Otázky?
Dobre.
>> Poďme sa pozrieť na buggy3, poďme gdb buggy3.
Sme len spustiť a vidíme, sa segfault.
Ak by sme backtrace, tam sú len dve funkcie.
Ak by sme išli do našej hlavnej funkcie, vidíme, že segfaulted na tomto riadku.
Takže len pri pohľade na tento riadok, for (int riadok = 0; fgets toto nie je rovný NULL;
linka + +).
Naša predchádzajúcu snímku bol nazývaný _IO_fgets.
Uvidíte, že šarža vstavaných funkcií C,
že keď sa dostanete segfault, bude naozaj záhadné názvy funkcií
podobné _IO_fgets.
Ale že sa to súvisí s týmto fgets výzvy.
Niekde sem dovnútra, sme segfaulting.
Ak sa pozrieme na argumenty fgets, môžeme tlačiť vyrovnávacej pamäte.
Poďme vytlačiť ako - Oh, nie.
Tlač nebude fungovať presne tak, ako chcem, aby to.
Poďme sa pozrieť na aktuálny program.
Buffer je pole znakov. Je to postava pole 128 znakov.
Takže keď hovorím tlač buffer, že to bude tlačiť tie 128 znakov,
ktorá Myslím, že je to, čo sa očakáva.
Čo som hľadal, je vytlačiť adresu vyrovnávacej pamäte,
ale to nie je naozaj mi veľa.
Takže keď som sa náhodou povedať, tu x buffer, ukazuje mi 0xbffff090,
ktoré, ak si pamätáte z minulosti alebo nejakého bodu, Oxbffff inklinuje byť stack-ish región.
Zásobník má tendenciu začať niekde tesne pod 0xc000.
Len tým, že vidí túto adresu, ja viem, že vyrovnávacej pamäte sa deje na zásobníku.
Reštartovanie môj program, spustite, up, miernenie sme videli, bolo túto postupnosť znakov
ktoré sú do značnej miery zmysel.
Potom tlače súboru, čo to súbor vyzerá?
[Študent] Null. Jo >>.
Súbor je z * typ súboru, takže je to ukazovateľ,
a hodnota tohto ukazovateľa je nulový.
Takže fgets sa pokúsi čítať z tohto ukazovateľa v nepriamym spôsobom,
ale aby sa prístup k tomuto ukazovateľ, že má k dereferencia to.
Alebo, aby sa prístup, čo by malo byť smerujúce, to dereferences IT.
Takže to dereferencing nulový ukazovateľ, a to segfault chýb.
Mohol som znova ho tam.
Ak zrušíme v našom hlavnom bode a spustiť,
prvý riadok kódu je char * filename = "nonexistent.txt";
To by malo docela veľký náznak toho, prečo tento program zlyhá.
Písanie vedľa ma privádza na ďalší riadok, kde som otvoriť tento súbor,
a potom som okamžite dostať do našej línie, kde kedysi som zasiahla ďalší, bude to segfault.
Má niekto chcel vyhodiť dôvod, prečo by sme mohli byť segfaulting?
[Študent] Súbor neexistuje. Jo >>.
To má byť náznak
že ak ste otvorení súboru je nutné skontrolovať, či súbor skutočne existuje.
Tak tu, "nonexistent.txt";
Keď sme fopen súboru pre čítanie, potom sme potrebné hovoriť
if (súbor == NULL) a hovoriť printf ("Súbor neexistuje!"
alebo - ešte lepšie - filename); return 1;
Takže teraz sme skontrolovať, či je to NULL
ako v skutočnosti pokračovanie a snaží sa čítať z tohto súboru.
Môžeme prerobiť to jednoducho vidieť, že to funguje.
Mal som v úmysle zahrnúť nový riadok.
Takže teraz nonexistent.txt neexistuje.
Vždy by ste mali skontrolovať pre tento druh veci.
Vždy by ste mali skontrolovať, či fopen vráti NULL.
Vždy by ste mali skontrolovať, aby sa ubezpečil, že malloc nevráti NULL,
inak by ste segfault.
>> Teraz buggy4.c.
Beh. Hádam, že je to čaká na vstup alebo prípadne nekonečné slučky.
Áno, je to nekonečné slučky.
Tak buggy4. Vyzerá to, že sme nekonečné slučky.
Môžeme rozdeliť na hlavnej, spustite náš program.
V gdb, tak dlho, ako skratka použiť je jednoznačná
alebo špeciálne skratky, ktoré poskytujú pre vás,
potom môžete použiť n na použitie nabudúce namiesto toho, aby musel písať v budúcom celú cestu.
A teraz, keď som udrel n raz, môžem len stlačte Enter ďalej ďalšie
namiesto toho, aby museli zasiahnuť n Enter, n Enter, n Enter.
Vyzerá to, že som v nejakej slučke for, že je nastavenie pole [i] na 0.
Vyzerá to, že som nikdy vypadla z toho pre slučky.
Keby som tlače i, tak som ich 2, potom pôjdem ďalej.
Budem tlačiť aj, i je 3, potom pôjdem ďalej.
Budem tlačiť i a i je 3. Ďalšie, tlač i, i je 4.
Vlastne, tlač sizeof (pole), takže veľkosť poľa je 20.
Ale vyzerá to, že tam je nejaký osobitný gdb príkaz pre prechod až sa niečo stane.
Je to ako nastavenie podmienku na hodnote premennej. Ale ja neviem, čo to je.
Takže ak budeme pokračovať -
Čo si hovoril? Čo ste vychovávať?
[Študent] Má zobrazí aj pridať - >> Jo. Takže zobrazí aj vám môže pomôcť.
Ak by sme len zobraziť i, bude to dať sem, čo hodnota i je
takže nemám ju vytlačiť zakaždým.
Ak budeme len ďalej vedľa, vidíme 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5.
Niečo sa deje strašne zle, a ja sa nastaví na 0.
Pri pohľade na buggy4.c, vidíme všetko, čo sa stane, je int pole [5];
for (i = 0; i <= sizeof (array); i + +)
array [i] = 0;
Čo vidíme, že je to zle?
Ako náznak, keď som robil gdb buggy4 - poďme rozbiť hlavné, run -
Ja som print sizeof (pole) len preto, aby videli, čo je stav, kedy by som si mal konečne vypuknúť.
Kde to som? Som utekal?
Som nepriznal ešte.
Takže tlač sizeof (pole), a to 20,
ktorého sa očakáva, pretože moje pole je veľkosti 5 a je to z 5 celých čísel,
takže celá vec by mala byť 5 * sizeof (int) bytov, ak sizeof (int) tendencia k 4.
Takže sizeof (pole) je 20.
Čo by to mohlo byť?
[Študent] deleno sizeof (int). >> Jo, / sizeof (int).
Vyzerá to, že je tu ešte jeden problém. Myslím, že by to malo byť len <
pretože je to docela hodně vždy <a nikdy <=.
Teraz sa poďme zamyslieť, prečo bol tento skutočne zlomené.
Má niekto uhádne, prečo bol aj obnoviť 0 až každej iterácii slučky?
Jediné vnútri tu, že sa deje, je, že pole [i] je nastavený na hodnotu 0.
Takže nejako, tento riadok kódu je príčinou nášho int i byť nastavená na 0.
[Študent] Mohlo by to byť preto, že je to naliehavé pamäť tejto časti aj
keď si myslia, že je to ďalší prvok poľa? >> [Bowden] Áno.
Keď ideme po skončení nášho poľa,
nejako, že priestor, ktorý sme prepísanie je prepísanie hodnoty i
A tak keď sa pozrieme do buggy4, rozbiť hlavné, beh,
Poďme vytlačiť adresu i
Vyzerá to, že to bffff124.
Teraz poďme vytlačiť adresu pole [0]. 110.
Čo [1]? 114.
[2], 118.
11c, 120. array [5] je bfff124.
Takže pole [5] má rovnakú adresu ako ja, čo znamená, že pole [5], je i
Ak majú rovnakú adresu, sú jedno a to isté.
Takže keď sme sa pole [5] na 0, ktorú vytvárame aj na 0.
A ak si myslíte, že o tom, pokiaľ ide o zásobníka,
int i je deklarovaný ako prvý, čo znamená, že som sa dostane určitý priestor na zásobníku.
Potom array [5] je pridelené, tak potom 20 bytov sú prideľované na zásobníku.
Takže aj dostane pridelené prvý, potom týchto 20 bytov si pridelené.
Tak som sa deje priamo pred poľa,
a kvôli tomu, ako, ako som povedal minulý týždeň, ak je to technicky stack rastie dolu,
keď index do poľa, sú zaručené sme, že 0. pozície v poli
vždy sa stane pred prvom mieste v poli.
To je druh, ako som nakreslil minulý týždeň.
Všimnite si, že v spodnej časti máme adresu 0 a na vrchole sme adresu Max.
Zásobník je vždy rastie dolu.
Povedzme, že sme sa rozdeliť i
Sme alokovať integer aj, čo znamená, povedzme, že sa tu celé číslo aj dostane pridelené.
Potom sme prideliť našu ponuku 5 celých čísel, čo znamená, že pod tým,
pretože zásobník rastie dole, dostať pridelené tých 5 celé čísla.
Ale pretože, ako pole pracovať, to zaručuje, že sme prvé pozície v poli
má vždy adresu menší ako druhý vec v poli.
Takže array poloha 0 musí vždy stáť prvý v pamäti,
vzhľadom k tomu, polia pozíciu 1 má stať potom, čo
a pole pozície 2 sa stane po tom,
čo znamená, že pole v polohe 0 by sa stalo, niekde tu dole,
Pole pozície 1 by sa stalo, že vyššie
pretože pohybujúce sa rozumie vyššia adresy, pretože maximálna adresa je tu.
Takže pole [0] sa tu, array [1] tu, array [2] tu, array [3] tu.
Všimnite si, ako pred tým, ako pridelí celé číslo aj po celú cestu až sem,
ako sme sa presunúť ďalej a ďalej do nášho poľa, sme stále bližšie a bližšie k nášmu celé číslo i
To len tak sa stane, že pole [5], čo je o jednu pozíciu nad naše polia,
je presne tam, kde celé číslo aj stalo ktoré majú byť pridelené.
Tak to je miesto, kde sme sa náhodou biť priestor na zásobníku
, Ktorá bola pridelená pre celočíselné aj, a my sme nastavení, ktoré sa 0.
>> To je, ako to funguje. Otázky? Jo.
[Študent] To nevadí. Dobre.
[Študent] Ako sa vyhnúť týmto druh chyby?
Tieto druh chyby? Nepoužívajte C ako programovací jazyk.
Používajte jazyk, ktorý má pole medze kontroly.
Tak dlho, ako ste opatrní, stačí, aby sa zabránilo ísť za hranice svojho poľa.
[Študent] Tak tu, keď sme išli okolo hranice svojho poľa -
[Bowden] To je miesto, kde sa veci začnú zle. >> [Študent] Oh, dobre.
Tak dlho, ako si pobyt v pamäti pridelenej pre polia, že si v poriadku.
Ale C robí žiadnu kontrolu chýb. Ak to urobím pole [1000], bude to s radosťou len zmeniť nech sa stane čokoľvek -
Ide to na začiatku poľa, potom ide 1000 postavenie po a nastaví na hodnotu 0.
To nerobí žiadnu kontrolu, že oh, to nie je v skutočnosti mať 1000 vecí v ňom.
1000 je ďaleko za to, čo som mala byť zmena,
vzhľadom k tomu, Java alebo niečo dostanete ponuku z indexu Bounds
alebo index out of Bounds výnimky.
To je dôvod, prečo mnoho jazykoch vyššej úrovne majú tieto veci
kde keď idete za hranice poľa, sa vám to nepodarí
takže nie je možné meniť veci z pod vami
a potom sa veci ísť oveľa horšie, než len dostať výnimku
hovorí, že ste šiel za koniec poľa.
[Študent] A tak sme mali iba zmenil <= len <? >> [Bowden] Jo.
To by malo byť <sizeof (pole) / sizeof (int);
pretože sizeof (pole) je 20, ale chceme len 5. >> [Študent] Právo.
Ďalšie otázky? Dobre.
>> [Študent] Mám dotaz. Jo >>.
[Študent] Aký je skutočný pole premenná?
[Bowden] Ako čo je pole?
Array sám je symbolom.
Je to práve adresa začiatku 20 bajtov, ktoré sme odkazujúcich.
Môžete si ju predstaviť ako ukazovateľ, ale je to konštanta ukazovateľ.
Akonáhle sa veci zhromaždené, premenná pole už neexistuje.
[Študent] Tak ako to zistiť veľkosť poľa?
Veľkosť poľa sa odkazuje na veľkosť tohto bloku, ktorý tento symbol odkazuje.
Keď som urobiť niečo ako printf ("% p \ n", pole);
poďme spustiť.
Čo som práve urobil zle?
Array "array" vyhlásil tu.
Oh, tu.
Rinčať je šikovný, a to sa stane si, že som vyhlásil poľa ako 5 elementov
ale ja som indexovanie do polohy 1000.
To môže urobiť, pretože to sú len konštanty.
To môže ísť len tak ďaleko, všimol si, že budem mimo hranice poľa.
Všimnime si ale predtým, keď sme mali aj byť nesprávne,
nemožno presne určiť, koľko hodnôt by som si mohol vziať na,
tak to nemôže stanoviť, že som šiel za koniec poľa.
To je len zvonenie je šikovný.
>> Ale teraz robiť buggy4. Takže čo iného robím zle?
Implicitne prehlasuje knižničný funkcie "printf".
Budem chcieť, aby # include .
Dobre. Teraz beží buggy4.
Tlač hodnotu poľa ako ja tu, potlač ako ukazovateľ
postery niečo, čo vyzerá takto - bfb8805c - čo je asi adresa
že je v zásobníku-ish regiónu.
Pole sám je ako ukazovateľ, ale nie je to skutočný ukazovateľ,
pretože bežný ukazovateľ môžeme zmeniť.
Pole je len nejaká konštanta. V 20 blokov pamäti kto na adrese 0xbfb8805c.
Takže bfb8805c prostredníctvom tejto adrese +20- alebo myslím -20 -
je všetky pamäte pridelené pre toto pole.
Array, je premenná sama nie je uložené kdekoľvek.
Keď ste zostavovaní, kompilátor - Hand Wave na to -
ale kompilátor bude len používať, ak vie, pole sa.
Vie, kde toto pole začína,
a tak to môže vždy len robiť veci, pokiaľ ide o kompenzácie od tohto začiatku.
To nepotrebuje premennú sám reprezentovať poľa.
Ale keď som niečo také int * p = pole; teraz p je ukazovateľ, ktorý ukazuje na tomto poli,
a teraz p vlastne neexistuje v zásobníku.
Som voľná zmeniť ks. Môžem p = malloc.
Tak to pôvodne zamerala na pole, teraz to ukazuje na nejaký priestor na halde.
Nemôžem pole = malloc.
Ak zvonenie je šikovný, bude to na mňa kričať hneď bat.
Vlastne, som si celkom istý, gcc by to taky.
Takže typ poľa "int [5]" nie je prevoditeľná.
Nemôžete priradiť niečo typu poľa
pretože pole je len konštantný.
Je to symbol, ktorý odkazuje táto 20 bytov. Nemôžem to zmeniť.
>> [Študent] A, kde je veľkosť poľa uložená?
[Bowden] To nie je uložené kdekoľvek. Je to, keď je to kompiláciu.
Takže, kde je veľkosť poľa uložené?
Môžete použiť iba sizeof (pole) vo vnútri funkcie, ktorá pole je deklarovaná sám.
Takže keď urobím nejakú funkciu, foo, a ja (int array [])
printf ("% d \ n", sizeof (pole));
a potom sem zavolám foo (array);
vnútri tejto funkcie - poďme ho spustiť.
To je zvonenie je šikovný znovu.
To mi hovorí, že sizeof na pole parametra funkcie
vráti veľkosť "int * '.
To by bolo chybou, ak to nie je to, čo som chcel aby sa to stalo.
Poďme skutočne vypnúť Werror.
Varovanie. Varovania sú v poriadku.
To bude ešte zostaviť tak dlho, ako to má varovanie.
. / A.out bude tlačiť 4.
Varovanie, ktorý bol vytvorený, je jasným ukazovateľom toho, čo sa stalo.
Tento int pole je len tak tlačiť sizeof (int *).
Aj keď som dal ponuku [5] tu, je to stále len tak tlačiť sizeof (int *).
Takže akonáhle odovzdáte ho do funkcie, rozdiel medzi poľami a ukazovatele
neexistuje.
To sa stane, že pole, ktorý bol vyhlásený na zásobníku,
ale akonáhle sme sa prejsť túto hodnotu, že 0xbf bla, bla, bla do tejto funkcie,
potom tento ukazovateľ ukazuje na danom poli na zásobníku.
Takže to znamená, že sizeof platí len vo funkcii, ktorá poľa bola vyhlásená,
čo znamená, že keď sa zostavovaní túto funkciu,
Pri zvonení prechádza tejto funkcie, to vidí pole je int pole o veľkosti 5.
Takže potom to vidí sizeof (pole). No, to je 20.
To je vlastne, ako sizeof funguje v podstate takmer vo všetkých prípadoch.
Sizeof nie je funkcia, je to operátor.
Nemusíte volať sizeof funkciu.
Sizeof (int), bude kompilátor len prekladať ktoré až 4.
Máš to? Dobre.
>> [Študent] Tak v čom je rozdiel medzi sizeof (pole) v hlavnej a foo?
To je preto, že hovoríte, že sizeof (pole), čo je z * typ int,
vzhľadom k tomu, polia tu dole nemá * typu int, je to int pole.
>> [Študent] Takže ak ste mali parameter v poli [] namiesto int * pole,
by znamenalo, že by ste mohli ešte zmeniť pole, pretože teraz je to ukazovateľ?
[Bowden] Like this? >> [Študent] Jo. Môžete zmeniť pole vo funkcii teraz?
[Bowden] Dalo by sa zmeniť pole v oboch prípadoch.
V oboch týchto prípadoch si budete môcť povedať, array [4] = 0.
[Študent] Ale môžete si pole prejdite na niečo iné?
[Bowden] Oh. Jo. V oboch prípadoch - >> [študentka] Jo.
[Bowden] Rozdiel medzi pole [] a int * pole, tam nie je nikto.
Môžete tiež získať nejaké viacrozmerné pole tu
pre niektoré pohodlné syntaxe, ale je to stále len ukazovateľ.
To znamená, že som si môže robiť, pole = malloc (sizeof (int)), a teraz ukazujú niekam inam.
Ale rovnako ako, ako to funguje navždy a vždy,
Zmenou tohto poľa tým, že ho upozorniť na niečo iné
nemení toto pole tu dole, pretože je to kópia argumentu,
to nie je ukazovateľ na tento argument.
A skutočne, rovnako ako ďalšie znamenie, že je to presne to isté -
sme už videli, čo tlačiarenský pole -
čo keby sme vytlačiť adresu poľa alebo adresu na adresu poľa
buď z nich?
Poďme ignorovať tento jeden.
Dobre. To je v poriadku. Je to teraz beží. / A.out.
Potlač pole, potom tlač adresu poľa, sú jedno a to isté.
Array jednoducho neexistuje.
To vie, kedy tlačíte pole, tlačíte na symbol, ktorý odkazuje na tých 20 bajtov.
Tlač adresu poľa, dobre, pole neexistuje.
To nemá adresu, tak to jednoducho vytlačí adresu týchto 20 bajtov.
Akonáhle budete kompilovať dole, ako v kompilované buggy4. / A.out,
poľa je neexistujúce.
Ukazovatele existujú. Pole nie.
Bloky pamäte predstavuje pole stále existujú,
ale premenná poľa a premenné tohto typu neexistujú.
Tí sú ako z hlavných rozdielov medzi poľami a ukazovatele
sú, akonáhle urobíte volanie funkcie, nie je tam žiadny rozdiel.
Ale vo vnútri funkcie, ktoré polia má vyhlásenie, sizeof pracuje odlišne
pretože tlačíte veľkosť blokov namiesto veľkosti typu,
a môžete ho zmeniť, pretože je to symbol.
Tlač vec a adresu veci vytlačí rovnakú vec.
A to je celkom veľa to.
[Študent] Mohli by ste povedať, že ešte raz?
Možno som niečo uniklo.
Tlač poľa a adresa poľa vypíše to isté,
vzhľadom k tomu, ak tlačíte ukazovateľ oproti adresu ukazovatele,
jedna vec vytlačí adresu toho, čo ste ukázal,
iný vytlačí adresu ukazovateľom na zásobníku.
Môžete zmeniť ukazovateľ, nemôžete zmeniť pole symbol.
A sizeof ukazovateľ bude tlačiť veľkosť tohto ukazovateľa typu.
Takže int * p sizeof (p) sa bude tlačiť 4,
ale int array [5] print sizeof (pole), bude k tlači 20.
[Študent] Tak int array [5] sa vytlačí 20? Áno >>.
Preto vnútri buggy4 keď to bolo sizeof (pole)
to bolo robil aj <20, čo nie je to, čo sme chceli.
Chceme aj <5. >> [Študent] Dobre.
[Bowden] A potom, akonáhle začnete prechádzať v funkciami,
keby sme int * p = array;
vnútri tejto funkcie, môžeme v podstate použiť p a polia v presne rovnakým spôsobom,
okrem problému sizeof a meniace problém.
Ale p [0] = 1, je rovnaký ako porekadlo pole [0] = 1;
A akonáhle hovoríme foo (array), alebo foo (p);
vnútri funkcie foo, to je rovnaký hovor dvakrát.
Nie je žiadny rozdiel medzi týmito dvoma hovormi.
>> Všetci dobre na to? Dobre.
Máme 10 minút.
>> Budeme sa snažiť dostať sa cez tento program Hacker Typer,
tento web, ktorý vyšiel v minulom roku alebo tak niečo.
Je to proste má byť, ako píšete náhodne, a to vytlačí -
Či súbor sa to stane, že v zásobníku sa, ako to vyzerá píšete.
Vyzerá to ako nejaký druh operačného systému kódu.
To je to, čo chceme realizovať.
Mali by ste mať binárny spustiteľný názvom hacker_typer
ktorý berie v jedinom argumente, súbor "hacker typu."
Spustenie spustiteľný by vyčistiť obrazovku
a potom vytlačiť jeden znak z odovzdaný v súbore zakaždým, keď užívateľ stlačí kláves.
Takže bez ohľadu na kľúč stlačení, mal by vyhodiť a namiesto toho vytlačí znak zo súboru
že je argument.
Budem celkom veľa povedať, čo veci budeme potrebovať vedieť, sú.
Ale chceme sa pozrieť na knižnicu termios.
Nikdy som používal tento knižnicu v celom mojom živote, tak to má veľmi minimálny účely.
Ale to bude knižnica môžeme použiť vyhodiť znak, ktorý hit
keď píšete do štandardu palcov
Takže hacker_typer.c, a budeme chcieť, aby # include .
Pri pohľade na manuálové stránke pre termios - ja hádať, že je to terminál OS alebo tak niečo -
Ja neviem, ako to čítať.
Pri pohľade na to, že hovorí, že aj na tieto 2 súbory, takže budeme robiť, že.
>> Prvá vec, ktorú ako prvý, chceme, aby sa v jedinom argumente, ktorý je súbor by sme mali otvoriť.
Tak čo chcem robiť? Ako môžem skontrolovať, či mám jediný argument?
[Študent] Ak argc rovná ju. >> [Bowden] Jo.
Takže if (argc = 2!) Printf ("Použitie:% s [súbor otvoriť]").
Takže teraz, keď spustím to bez udania druhý argument - oh, potrebujem novú linku -
uvidíte, že hovorí použitie:. / hacker_typer,
a potom druhý argument by mal byť súbor chcem otvoriť.
Teraz, čo mám robiť?
Chcem čítať z tohto súboru. Ako som čítal zo súboru?
[Študent] môžete otvoriť ako prvý. Jo >>.
Tak fopen. Čo fopen vyzerá?
[Študent] súboru. >> [Bowden] súboru bude ArGV [1].
[Študent] A potom to, čo chcete robiť s tým, aby - >> [Bowden] Jo.
Takže ak ste si spomenúť, mohol by si urobiť muž fopen,
kde to bude const char * path, kde path je meno súboru,
const char * mode.
Ak ste náhodou nepamätáte, čo je režim, potom sa môžete pozrieť na režim.
Vnútri manuálových stránok, znak lomítko je to, čo môžete použiť na vyhľadanie veci.
Tak som typ / režim vyhľadávania pre režim.
n a N sú to, čo môžete použiť na prechádzanie vyhľadávania zápasov.
Tu sa hovorí, že body argumentov režimu na reťazec
začína s jedným z nasledujúcich postupností.
Takže r, Open textový súbor pre čítanie. To je to, čo chceme robiť.
Pre čítanie, a chcem uložiť, že.
Vec bude FILE *. Teraz, čo chcem robiť?
Dajte mi chvíľku.
Dobre. Teraz, čo chcem robiť?
[Študent] Skontrolujte, či je to NULL. >> [Bowden] Jo.
Zakaždým, keď otvoríte súbor, uistite sa, že ste úspešne schopný otvoriť.
>> Teraz chcem urobiť, aby termios veci tam, kde chcem najprv prečítať moje súčasné nastavenie
a zachrániť tých, do niečoho, potom chcem zmeniť svoje nastavenie
vyhodiť ľubovoľný znak, ktorý som typ,
a potom chcem aktualizovať tieto nastavenia.
A potom na konci programu, chcem zmeniť späť na svoje pôvodné nastavenia.
Takže struct bude typových termios, a budem chcieť dva ty.
Prvý z nich bude moja current_settings,
a potom to bude moja hacker_settings.
Po prvé, budem chcieť uložiť svoje aktuálne nastavenia,
potom budem chcieť aktualizovať hacker_settings,
a potom ako na konci svojho programu, chcem sa vrátiť na aktuálne nastavenie.
Takže uloženie aktuálne nastavenie, tak, že funguje, my man termios.
Vidíme, že máme túto int tcsetattr, int tcgetattr.
Minul som v termios struct svojim ukazovateľ.
Spôsob, akým to bude vyzerať, je - I've už zabudli, čo funkcia bola volaná.
Skopírujte a vložte ju.
Takže tcgetattr, potom chcem odovzdať v struct, že som uloženie informácií v,
ktorá sa bude current_settings,
a prvý argument je deskriptor súboru pre vec, ktorú chcem uložiť atribúty.
Čo popisovač súboru je je ako kedykoľvek otvorte súbor, dostane popisovač súboru.
Keď som fopen ArGV [1], sa dostane popisovač súboru, ktorý ste odkazujúce
zakaždým, keď chcete čítať alebo do nej zapisovať.
To nie je deskriptor súboru chcem používať tu.
K dispozícii sú tri deskriptory súborov, ktoré máte v predvolenom nastavení,
ktoré sú štandardné v, štandardný výstup a štandardné chyba.
V predvolenom nastavení, myslím, že je to štandard v je 0, štandardný výstup je 1 a štandardná odchýlka je 2.
Takže to, čo chcem zmeniť nastavenia?
Chcem zmeniť nastavenie, keď som trafil postavu,
Chcem, aby to hodiť, že charakter preč namiesto tlače na obrazovku.
Čo potok - štandard v, štandardný výstup, alebo štandardné chybou -
reaguje na veci, keď som typ na klávesnici? >> [Študent] Štandardné a >> Jo.
Tak som si buď urobiť 0, alebo môžem urobiť stdin.
Začínam sa current_settings z normy a
>> Teraz chcem aktualizovať tieto nastavenia,
takže prvý budem kopírovať do hacker_settings, čo moji current_settings sú.
A ako structs práce je, že bude len kopírovať.
To skopíruje všetky polia, ako by ste očakávali.
>> Teraz chcem aktualizovať niektoré z polí.
Pri pohľade na termios, by ste si prečítať cez veľa to
len aby videl, čo by ste chceli hľadať,
ale príznaky budete chcieť hľadať, sú echo,
tak ECHO znaky Echo vstupné.
Najprv chcem nastaviť - I've už zabudli, čo sú polia.
To je to, čo struct vyzerá.
Takže vstupné režimy myslím, že chceme zmeniť.
My sa pozrieme na riešenie, aby sa ubezpečil, že je to to, čo chceme zmeniť.
Chceme zmeniť lflag, aby sa zabránilo nutnosti prezrieť všetky tieto.
Chceme zmeniť miestne režimy.
Budete musieť prečítať tento celú vec pochopiť, kde všetko patrí
že chceme zmeniť.
Ale je to vo vnútri miestnych režimov, kde budeme chcieť zmeniť.
Takže hacker_settings.cc_lmode je to, čo sa volá.
c_lflag.
To je miesto, kde sme sa dostali do bitovej operátormi.
Sme trochu oneskorene, ale my pôjdeme cez to naozaj rýchlo.
To je miesto, kde sme sa dostali do operátormi bitovej,
kde Myslím, že som povedal, jeden čas dávno, že pri každom spustení zaoberajúce sa vlajkami,
budete používať bitového súčinu prevádzkovateľovi veľa.
Každý bit vo vlajke zodpovedá nejaké správanie.
Tak tu, tento príznak má veľa rôznych vecí, kde všetci z nich znamenať niečo iné.
Ale to, čo chcem urobiť, je jednoducho vypnúť bit, ktorý zodpovedá ECHO.
Takže zase, že vypnutie robím & = ¬ ECHO.
Vlastne si myslím, že je to ako TECHO, alebo tak niečo. Idem len skontrolovať znova.
Môžem termios to. Je to len ECHO.
ECHO sa bude jeden bit.
¬ ECHO bude znamenať všetky bity sú nastavené na 1, čo znamená, že všetky príznaky sú nastavené na hodnotu true
s výnimkou ECHO bit.
Tým končí moje miestne príznaky s tým, to znamená všetky príznaky, ktoré sú v súčasnej dobe nastavené na hodnotu true
bude stále nastavená na hodnotu true.
Ak je moja ECHO príznak nastavený na true, potom je to nutne nastavená na hodnotu false na ECHO vlajky.
Takže tento riadok kódu len vypne ECHO vlajkou.
Ďalšie riadky kódu, budem len skopírovať v záujme času a potom je vysvetliť.
V roztoku, povedal 0.
Je to asi lepšie explicitne povedať stdin.
>> Všimnite si, že som tiež robil ECHO | icanon tu.
Icanon sa vzťahuje k niečomu samostatné, čo znamená, že kanonické režimu.
Čo kánonický režim znamená, je obvykle, keď píšete z príkazového riadku,
štandard v nespracováva nič, kým nenarazíte nový riadok.
Takže, keď to GetString, zadajte veľa vecí, potom hit nový riadok.
To je, keď je to poslal normy palcov
To je predvolené.
Keď som vypnúť kánonickú režim, hneď každý jednotlivý znak stlačíte
je to, čo dostane spracovávané, čo je zvyčajne trochu zle, pretože je to pomalý spracovať tieto veci,
čo je dôvod, prečo je dobré, aby sa zmiernili do celých riadkov.
Ale chcem každá postava má byť spracované
pretože nechcem, aby na mňa počkať zasiahnuť nový riadok
pred spracováva všetky znaky som písať.
Toto vypne kánonickú režim.
Toto jednoducho znamená, keď v skutočnosti spracováva znaky.
To znamená, že spracovanie je okamžite, akonáhle som písanie, spracovať.
A to je funkcia, ktorá je aktualizácia svoje nastavenia pre štandardné v,
a TCSA prostriedky to urobiť práve teraz.
Ďalšie možnosti sú počkať, až všetko, čo je v súčasnej dobe na toku je spracovaný.
To naozaj nezáleží.
Práve teraz meniť moje nastavenie je všetko, čo je v súčasnej dobe v hacker_typer_settings.
Myslím, že som ju nazval hacker_settings, tak sa poďme zmeniť.
Zmena všetko hacker_settings.
>> Teraz na konci nášho programu budeme chcieť vrátiť
na to, čo je v súčasnej dobe vo vnútri normal_settings,
ktorý sa bude len vyzerať ako & normal_settings.
Všimnite si, som sa nezmenil žiadny z mojich normal_settings od pôvodne dostať ju.
Potom len zmeniť späť, odovzdám späť na konci.
To bolo aktualizácie. Dobre.
>> Teraz vnútri tu budem vysvetľovať kód v záujme času.
To nie je tak moc code.
Vidíme čítame znak zo súboru. Hovorili sme, že f
Teraz si môže človek fgetc, ale ako fgetc bude fungovať
je len to bude vráti znak, ktorý ste práve prečítali, alebo EOF,
ktorý zodpovedá konci súboru alebo nejaké chyby deje.
Sme slučky, naďalej čítať znak zo súboru,
kým sme došli znakov čítať.
A zatiaľ čo my robíme to, že budeme čakať na jeden znak z normy palcov
Zakaždým si niečo písať v príkazovom riadku,
že číta v charakteru od štandardu a
Potom putchar sa práve chystá dať char čítame tu zo súboru na štandardný výstup.
Môžete muž putchar, ale je to len uvedenie na štandardný výstup, je to tlač, že charakter.
Dalo by sa tiež len to, printf ("% c", c); Rovnaký nápad.
To bude robiť väčšinu našej práce.
>> Posledná vec, ktorú budeme chcieť urobiť, je len fclose náš súbor.
Ak nechcete fclose, že je to k pretečeniu pamäte.
Chceme fclose súbor sme pôvodne otvorený, a myslím, že je to ono.
Urobíme Ak to, že som už nejaké problémy.
Poďme sa pozrieť,.
Čo to sťažujú?
Predpokladaný "int", ale argument je typu "struct _IO_FILE *".
Uvidíme, či to funguje.
Povolený len v C99. Augh. Dobre, aby hacker_typer.
Teraz sme sa dostali ďalšie užitočné popisy.
Takže použitie nelegálnej identifikátor "normal_settings".
Nevolal som, že normal_settings. Nazval som ju current_settings.
Takže poďme zmeniť všetko.
Teraz okolo argument.
Budem túto 0 zatiaľ.
Dobre. . / Hacker_typer cp.c.
Tiež som vyčistiť obrazovku na začiatku.
Ale môžete sa pozrieť na posledný problém, aby videl, ako ich vymazať obrazovku.
Je to jednoducho tlače niektoré znaky
zatiaľ čo toto je to, čo chcem robiť.
Dobre.
A premýšľať o tom, prečo to musela byť 0 namiesto štandardného vstupu,
, Ktorá by mala byť # vymedziť 0,
to sa sťažuje, že -
Ako keď som povedal, že je to popisovače súborov, ale potom máte tiež svoj súbor *,
popisovač súboru je len jeden integer,
vzhľadom k tomu, FILE * má veľa vecí s ním spojené.
Dôvod, prečo sme potrebné hovoriť 0 namiesto štandardného vstupu
je to, že stdin je FILE *, ktorý poukazuje na to, čo je odkazovanie na deskriptor súboru 0.
Takže aj tu, keď som si fopen (ArGV [1], začínam si súbor * späť.
Ale niekde v tom súbore * je vec zodpovedajúce deskriptor súboru pre daný súbor.
Ak sa pozriete na manuálové stránke pre otvorené, takže myslím, že budete musieť urobiť človek 3 open - Nie -
man 2 open - jo.
Ak sa pozriete na stránky pre otvorenú, otvorený je ako nižšie úrovne fopen,
a je to vráti aktuálne popisovač súboru.
fopen robí veľa vecí na vrchole otvorené,
ktoré namiesto vrátenia len, že deskriptor súboru vráti a celú súboru * ukazovateľ
vnútri ktorej je náš malý deskriptor súboru.
Takže štandard sa vzťahuje na veci FILE *,
vzhľadom k tomu, 0 odkazuje len na štandarde deskriptora súboru v sebe.
>> Otázky?
[Smiech] prehnal, že.
Dobrá. Skončili sme. [Smiech]
>> [CS50.TV]