[Powered by Google Translate] [5. jagu - mugavam] [Rob Bowden - Harvardi Ülikool] [See on CS50. - CS50.TV] Nagu ma ütlesin oma e-posti, seal on palju asju, mida saate kasutada peale seadme tegelikult teha probleem seab. Soovitame seda teha seadme lihtsalt, sest siis saame kergemini aidata teil ja me teame, kuidas kõik läheb tööle. Aga nagu üks näide, kus saab teha asju, kui, ütleme, sa ei pea juurdepääsu et seadme või soovite töötada teaduskeskus kelder - mis tegelikult neil on aparaat liiga - kui sa tahad töötada kõikjal. Üks näide on olete näinud / kuulnud SSH? SSH on põhimõtteliselt nagu ühendust midagi. Tegelikult praegu ma SSHed seadmesse. Ma ei tööta otse seadmesse. Siin on aparaat, ja kui sa vaatad alla siit näed seda IP-aadressi. Ma pole kunagi tööd seade ise; Olen alati tulema üle iTerm2 aken / terminaliakent. Võite SSH et IP-aadress, ssh jharvard@192.168.129.128. Mäletan, et mitmed väga lihtne, sest see on selline tore muster. Aga see küsib minu käest parooli ja nüüd olen seadmesse. Põhimõtteliselt sel hetkel, kui te avada terminal seadme sisemust ise, Selle liidese aga siis oleks seda kasutada, on täpselt sama nagu interface ma kasutan siin kuid nüüd olete SSHed. Sa ei pea SSH seade. Üks näide ühest kohast teise võid SSH on Ma olen päris kindel, mida vaikimisi - Oh. Suuremad. Kõik te peaks olema vaikimisi FAS kontod FAS servereid. Minu jaoks, ma oleks SSH rbowden@nice.fas.harvard.edu. See saab küsida, et esimest korda, ja te ütlete jah. Minu parool on lihtsalt saab olema minu FAS parool. Ja nüüd, ma SSHed et kena servereid ja ma saan teha midagi, ma tahan siia. Paljud klassid võite võtta, nagu 124, on plaanis teha saadate asju siin tegelikult esitada oma probleem seab. Aga öelda, et sa ei pääse oma seade. Siis saad teha asju, nagu siin seda ütlen - See on vaid meie osa küsimustele. Ta küsib, teha seda seadet. Selle asemel ma lihtsalt teha seda serveris. Ma lähen unzip et. Probleem saab olema, et sa oled harjunud kasutama midagi gedit või mis iganes seadme sisemust. Sa ei kavatse olla, et FAS server. See kõik on lihtsalt saab olema see tekstiline liides. Nii võid kas üks, proovige õppida tekstiredaktorit, mis nad on. Neil on Nano. Nano on tavaliselt üsna lihtne kasutada. Te saate kasutada oma nooled ja trükkige tavaliselt. Nii et see ei ole raske. Kui sa tahad saada tõeliselt fancy saate Emacs, mida ma ilmselt poleks pidanud alustama, sest ma ei tea isegi, kuidas sulgeda Emacs. Kontroll X, Control C? Jah. Või saab kasutada Vim, mis on see, mida ma kasutan. Ja nii need on teie võimalused. Kui te ei taha seda teha, saate ka, kui te vaatate manual.cs50.net-- Oh. PC, saate SSH kasutades pahtel, mis sa lähed on alla laadida eraldi. Mac'i, saate lihtsalt vaikimisi pesa või saad laadida iTerm2, mis on nagu kena, uhke Terminal. Kui te lähete manual.cs50.net näete lingi Notepad + +, mis on see, mida saab kasutada arvutis. See võimaldab teil SFTP Notepad + +, mis on põhimõtteliselt SSH. Mida see teile teha, on muuta oma faile kohapeal, ja siis, kui soovite, et neid päästa, siis salvestada nice.fas, kus saab siis käima panna. Ja samaväärne Mac saab olema TextWrangler. Nii et see võimaldab teil teha sama asi. See võimaldab teil redigeerida faile kohapeal ja salvestada neid nice.fas, kus saab siis käima panna. Seega, kui olete kunagi ummikus ilma aparaat, teil on neid võimalusi et ikka sinu probleem komplekti. Üks probleem saab olema, et sa ei kavatse on CS50 raamatukogu sest nice.fas ei vaikimisi on see. Võite alla laadida CS50 raamatukogu - Ma ei usu, mul on vaja, et selles punktis. Võite alla laadida CS50 raamatukogu ja kopeeri see üle nice.fas, või ma arvan, sel hetkel me ei kasuta seda enam niikuinii. Või kui me seda teeme, saab käesoleval ajal on asendada see rakenduste funktsioonide CS50 raamatukogu niikuinii. Nii et ei tohiks olla, et palju piiranguid. Ja ongi nii. Ma lähen tagasi seadme nüüd, me teeme kõik seadmesse. Vaadates meie osa küsimusi, alguses, nagu ma ütlesin oma e-posti, meil rääkida üks lühike sa pidid valvama. Meil on Suunan ja torud ning need kolm küsimust. Et mis oja ei funktsioone nagu printf kirjutada vaikimisi? Nii oja. Mis on oja? Oja on põhimõtteliselt nagu see on lihtsalt mõned - See ei ole isegi allikas 1s ja 0.. Oja see küsib siin on standard välja. Ja nii standard välja on oja, et kui sa kirjutad see, see ekraanile. Standard välja, mida oja, see tähendab, et sa lihtsalt kirjutada 1s ja 0. sellele ja teises otsas tavaline välja loeb vaid sellest oja. See on lihtsalt jada 1s ja 0.. Võite kirjutada, et voolu või saate lugeda ojad sõltuvalt sellest, mida oja tegelikult on. Ülejäänud kaks vaikimisi ojad on standard ja standardviga. Standard on, kui sa ei getString, see ootab sind sisestada kraami. Nii et ootame teid, see on tegelikult ootab standard, mis on tõesti, mida sa saad, kui kirjutad klaviatuuri. Sa kirjutades standard sisse Standardviga on põhimõtteliselt samaväärne standard välja, aga see on spetsialiseerunud, et kui sa printida standardviga, sa peaksid ainult printida veateated, mis nii saab eristada regulaarselt sõnumeid trükkida ekraanil versus veateateid sõltuvalt sellest, kas nad läksid standard välja või standardviga. Faile liiga. Standard läbi, standard, ja standardviga on lihtsalt eriline ojad, kuid tegelikult ühtegi faili, kui avate faili, muutub see oja baiti kus saab lihtsalt lugeda, et oja. Sa, enamasti, saab lihtsalt mõelda faili oja baiti. Mida ojad nad kirjutada vaikimisi? Standard välja. Mis vahe on> ja >>? Kas keegi video eelnevalt? Okei. > Saab olema kuidas suunata failidena, ja >> ka saab suunata väljundi faili, aga see on vaid kavatse lisab faili. Näiteks oletame, et ma juhtun olema dict siin, ja ainult kraami sees dict on kass, kass, koer, kalad, koer. Üks käsk, et teil on käsurida on kass, mis on lihtsalt trükkimise mis on faili. Nii et kui ma ütlen, kass dict, see saab printida kass, kass, koer, kalad, koer. See on kõik, kass teeb. See tähendab, et trükitud standard välja kass, kass, koer, kalad, koer. Kui ma selle asemel soovite ümber suunata, et faili, saan kasutada> ja suunata see iganes fail on. Ma helistan faili fail. Nii et nüüd, kui ma LS, ma vaatan, et mul on uus fail nimega faili. Ja kui ma seda avatumaks, see saab olema just see, mida kass panna käsurida. Nüüd, kui ma seda uuesti teha, siis see läheb ümber väljundi faili, ja ma lähen on täpselt sama asi. Nii tehniliselt, see täiesti kaalus mis meil oli. Ja me näeme, kui ma muudan dict, võtsin koera. Nüüd, kui me kass dict arvesse fail uuesti, me lähed on uus versioon koeraga eemaldada. Nii et täiesti alistab ta. Selle asemel, kui me kasutame >>, see saab lisada faili. Nüüd, avades faili, näeme me just sama asja trükitud kaks korda sest see oli seal üks kord, siis me lisada originaal. Nii see on, mida> ja >> teha. Kas järgmise küsida - see ei küsi midagi. Teine, et meil on <, mis, kui> ümbersuunamised standard välja, teete 2>, et teada suunates standardviga. Nii et kui midagi läks standardviga, siis ei saa panna txt2. Aga teate, kui ma teen 2>, siis see on ikka trükkimine Tere, Rob! et käsurealt sest ma olen ainult suunates standardviga, ma ei suunates standard välja. Standardviga ja standard välja on erinevad. Kui sa tahtsid tegelikult kirjutada standardviga, siis ma võiks muuta, et see oleks fprintf stderr. Nii printf, vaikimisi trükib standard välja. Kui ma tahan printida standardviga käsitsi, siis ma pean kasutama fprintf ning täpsustab, millist ma tahan printida. Kui selle asemel tegin fprintf stdout, siis see on põhimõtteliselt samaväärne printf. Aga fprintf et standardviga. Nii et nüüd, kui ma ümber seda arvesse txt2, Tere, Rob! on endiselt saada trükitud käsureal kuna see on üha trükitud standardviga ja ma olen ainult suunates standard välja. Kui ma nüüd suunata standardviga, nüüd ta ei saanud trükkida, ja txt2 saab olema Tere, Rob! Nüüd saate printida oma tegelikku vigu standardviga ja printida oma regulaarset sõnumite standard välja. Ja nii, kui sa käivitada oma programmi, saate käivitada seda. / Hello seda tüüpi 2> nii et teie programm läheb normaalselt, kuid mingeid veateateid, et sa saad saate vaadata hiljem oma tõrkelogile nii vigu, ja siis vaatame hiljem ja oma vigu fail on kõik vead, mis juhtus. Küsimused? Viimane on toru, mis sa ei mõtle nagu võttes standard välja ühe käsu ja teha see standard, et järgmise käsu. Näiteks siin on kaja on käsurea asi et lihtsalt läheb echo iganes ma panen selle väitega. Ma ei pane jutumärgid. Kaja blaa, blaa, blaa, on lihtsalt trükkimise blaa, blaa, blaa. Enne, kui ma ütlesin, mul oli panna Rob arvesse txt faili sest ma saan ainult suunata txt faili, selle asemel, / kui ma kordan Rob ja siis toru see. / hello, et ka tegema sama tüüpi asi. See võtab antud käsu väljundit, kaja Rob, ja kasutades seda sisendiks. / hello. Sa ei mõtle seda kui esimene suunata kaja Rob see faili ja siis sisestatud. / hello, et faili, mis oli just väljastada. Aga see võtab ajutise faili välja pilt. Küsimused, mis? Järgmine küsimus on planeeritud kaasata see. Mis gaasijuhe võib kasutate leida mitmeid unikaalseid nimesid faili nimega names.txt? Käsud me ei kavatse soovite kasutada siin on unikaalne, nii ainulaadset, ja siis wc. Seda saab teha mees UNIQ tegelikult vaadata, mida see teeb, ja see lihtsalt läheb filtreerida kõrval sobitamine read sisend. Ja mees WC on trükkimineku reavahetus, sõna ja baitides iga faili. Ja viimane läheme soovite kasutada on omamoodi, mis läheb lihtsalt sortida rida txt faili. Kui ma teen mõned txt faili, names.txt, ja see on Rob, Tommy, Joseph, Tommy, Joseph, RJ, Rob, mida ma tahan teha, on leida mitmeid unikaalseid nimesid seda faili. Mida peaks vastus olema? >> [Üliõpilane] 4. >> Jah. See peaks olema 4, sest Rob, Tommy, Joseph, RJ on ainult unikaalsed nimed selles failis. Esimene samm, kui ma lihtsalt ei sõnaarvestus kohta names.txt, see on tegelikult mulle kõike. See on tegelikult trükkimine - Vaatame, mees WC - reavahetused, sõnade ja baitide arv. Kui ma ainult hoolid read, siis ma saan lihtsalt teha wc-l names.txt. Nii et 1. etapis. Aga ma ei taha wc-l names.txt sest names.txt lihtsalt sisaldab kõiki nimesid, ja ma tahan välja filtreerida mis tahes mitteunikaalse ones. Nii et kui ma teen UNIQ names.txt, et ei ole päris mulle, mida ma tahan sest dubleeritud nimed on ikka veel seal. Miks nii? Miks on UNIQ ei tee seda, mida ma tahan? [Üliõpilane] duplikaate ei ole [kuuldamatu] >> Jah. Pea meeles, man-leheküljelt UNIQ ütleb filtri kõrval sobivad read. Nad ei külgne, nii et see ei filtreerida neid. Kui ma natuke neid esimesena, sorteerida names.txt läheb panna kõik duplikaat read kokku. Nii et nüüd omamoodi names.txt on see, et. Ma tahan kasutada seda sisendina ainulaadset, mis on | UNIQ. See annab mulle Joseph, RJ, Rob, Tommy, ja ma tahan kasutada seda sisendina wc-l, mis on annan mulle 4. Nagu ta ütleb siin, mida gaasijuhe võib kasutate? Seda saab teha palju asju nagu kasutades mitmeid käske kui kasutad väljundi ühest käsu sisendiks järgmise käsu. Seda saab teha palju asju, palju tarku asju. Küsimused? Okei. Ongi torude ja ümbersuunamine. Nüüd me läheme edasi tegelik kraam, kodeerimine kraami. Toas käesoleva PDF, näete selle käsu, ja sa tahad teha selle käsu oma seade. wget on käsk lihtsalt saada midagi internetist, põhiliselt nii wget ja see link. Kui sa läksid see URL oma brauseri, siis oleks seda faili alla laadida. Ma lihtsalt klõpsasid seda, nii et see allalaetud fail minu jaoks. Aga kirjalikult wget selle asja sees terminal lihtsalt läheb alla see oma terminal. Mul on section5.zip, ja sa tahad, et unzip section5.zip, mis on annan teile kausta nimega 5. jao, mis läheb on kõik failid me ei kavatse olla kasutades täna sees on. Kuna need programmid "failinimed näitavad, et nad on natuke lollakas, nii teie ülesanne on aru saada, miks kasutatakse gdb. Kas kõik on neid alla laadida / tea kuidas saada neid alla laadida oma seadme? Okei. Running ./buggy1, siis öelda Segmentation fault (core dumpinguhinnaga), mis tahes ajal saad segfault, et see on halb asi. Millisel juhul sa saad segfault? [Üliõpilane] viite mahavõtmine nullviida. >> Jah. Nii et on üks näide. Viite mahavõtmine nullviida sa lähed, et saada segfault. Mis segfault tähendab, et sa liigutav mälu sa ei peaks liigutav. Nii viite mahavõtmine nullviida on liigutav aadress 0, ja põhimõtteliselt kõik arvutid tänapäeval öelda, et aadress 0 on mälu sa ei peaks liigutav. Nii et miks viite mahavõtmine nullviida tulemusi segfault. Kui juhtub, et ei initsialiseerida pointer, siis on prügi väärtus, ja nii kui püüad dereference see suure tõenäosusega Sa puudutad mälu see on eikuskil. Kui juhtub, et saada õnnelik ja prügi väärtus juhtus osutada kusagil virnas või midagi, siis kui sa dereference et osuti mida te pole vormindatud, Midagi ei lähe valesti. Aga kui see on suunatud, ütleme, kusagil virnas ja hunnik, või see osutavad lihtsalt kuskil, et ei ole kasutatud oma programmi veel, siis oled liigutav mälu sa ei peaks liigutav ja sa segfault. Kui Sa kirjutad rekursiivne funktsioon ja see recurses liiga palju kordi ja sinu stack kasvab liiga suur ja korstna põrkas asjadest et see ei tohiks põrgata kokku, Sa puudutad mälu sa ei peaks liigutav, nii et sa segfault. Just segfault on. See on ka samal põhjusel, et kui teil on string nagu - Lähme tagasi eelmisele programmile. Aastal hello.c--Ma lihtsalt kavatse teha midagi muud. char * s = "Tere maailm!"; Kui ma kasutan * s = midagi või s [0] = "X"; nii et tere,. / hello, miks see segfault? Miks see segfault? Mida ootate juhtuda? Kui ma tegin printf ("% s \ n", s); Mida ootate tuleb trükkida? [Üliõpilane] X tere. >> Jah. Probleem on selles, et kui te deklareerite string meeldib see, s on viit, et läheb minna korstna ja mida te ei osutades on see nöör, mis sisaldub püsimälu. Nii lihtsalt nime, püsimälu, sa peaksid idee et kui te proovida muuta mis kasu on püsimälu, sa teed midagi, mida sa ei peaks tegema mäluga ja sa segfault. See on tegelikult suur vahe char * s ja char s []. Nii char s [], nüüd see string läheb pannakse virna, ja korstna ei ole ainult lugemiseks, mis tähendab, et see peaks töötama täiesti korras. Ja ta teeb. Pea meeles, et kui ma teen char * s = "Tere maailm!", S ise on virnas kuid s viitab kusagil mujal, ja et kuhugi mujale juhtub olema ainult lugemiseks. Aga char s [] on lihtsalt midagi pinu. Nii et järjekordne näide segfault juhtub. Me nägime, et ./buggy1 tulemusena segfault. Teoreetiliselt ei tohiks te vaatate buggy1.c kohe. Selle asemel, me vaatame selle läbi gdb. Pange tähele, et kui sa saad Segmentation fault (core dumpinguhinnaga), sa saad seda faili siia kutsus tuum. Kui me ls-l, siis me näeme, et tuum on tavaliselt päris suur fail. See on number baiti faili, nii et tundub, et see on 250-midagi kilobaiti. Selle põhjuseks on see, et mida krahh tabab tegelikult on on siis teie programm jookseb kokku, riik mälu oma programmi lihtsalt saab kopeerida ja kleepida seda faili. Läheb visatakse selle faili. See programm, samal ajal kui see töötab, juhtus olema mälukasutust umbes 250 kilobaiti, ja nii see on, mida sai dumpinguhinnaga arvesse seda faili. Nüüd saate vaadata selle faili, kui me teeme gdb buggy1 tuum. Me ei saa lihtsalt teha gdb buggy1, ja see lihtsalt käivitada gdb regulaarselt, kasutades buggy1 oma sisendfail. Aga kui sa gdb buggy1 tuum, siis see on just kavatse alustada gdb vaadates, et core-faili. Ja sa tahad öelda, buggy1 vahenditega gdb teab, et core-faili pärineb buggy1 programm. Nii gdb buggy1 tuum läheb kohe meid et kui programm juhtus lõpetada. Me näeme siin Program lõpetada signaal 11, segmenteerimine süü. Meil juhtub, et näha liini kokkupanek, mis ilmselt ei ole väga kasulik. Aga kui kirjutad bt või tagasijälituse et see saab olema funktsioon mis annab meile nimekiri meie praegune korstnat raame. Nii tagasijälitust. Paistab, et meil on ainult kaks korstnat raame. Esimene on meie peamine freimi, ja teine ​​on freimi seda funktsiooni, et meil juhtub olema, mis näeb välja nagu meil on ainult koost koodi. Nii et lähme tagasi meie peamine ülesanne, ja mida teha, et me saame teha frame 1 ja ma arvan, saame teha ka maha, aga ma peaaegu kunagi seda alla - või üles. Jah. Üles-alla. Üles viib sind üles üks freimi, alla viib sind maha freimi. Ma pigem ei kasuta kunagi seda. Ma lihtsalt konkreetselt öelda, korpus 1, mis on minna sektsioonis 1. Frame 1 läheb toob meid peamine freimi, ja ta ütleb siinsamas rida koodi me juhtub olema. Kui me tahtsime veel paar rida koodi, saame öelda nimekirja, ja mis läheb meile kõigile rida koodi ümber. Liin me GDB kell oli 6: if (strcmp ("CS50 kivid", argv [1]) == 0). Kui see ei ilmne veel, saad seda kohe siit lihtsalt mõtlesin, miks see GDB. Aga me saame võtta see üks samm edasi ja öelda: "Miks argv [1] segfault?" Lähme prindi argv [1], ja tundub, et see on 0x0, mis on null pointer. Me strcmping CS50 kivid ja null, ja nii, et läheb segfault. Ja miks on argv [1] null? [Üliõpilane] Kuna me ei anna see mingeid käsurea argumente. Jah. Me ei anna see mingeid käsurea argumente. Nii ./buggy1 on ainult kavatse olla argv [0] olema ./buggy1. Ta ei kavatse olla argv [1], nii et läheb segfault. Aga kui selle asemel, ma lihtsalt CS50, see saab öelda Saad D sest see on, mida see peaks tegema. Vaadates buggy1.c, see peaks print "Sa saad D" - Kui argv [1] ei "CS50 kivid", "Sa saad D", teine ​​"Sa saad!" Nii et kui me tahame, me vajame seda võrrelda kui tõsi, mis tähendab, et see on võrreldav 0. Nii argv [1] peab olema "CS50 kivid". Kui soovite teha seda käsurealt, peate kasutama \ põgeneda ruumi. Nii CS50 \ kivid ja saad! Kui sa ei tee längkriips, miks see ei tööta? [Üliõpilane] See on kaks eri argumente. >> Jah. Argv [1] saab olema CS50 ja argv [2] saab olema kivid. Okei. Nüüd ./buggy2 läheb segfault uuesti. Selle asemel, et seda avada oma tuum faili, me lihtsalt avada buggy2 otse, nii gdb buggy2. Nüüd, kui me lihtsalt joosta meie programmi, siis see saab öelda Program signaal SIGSEGV, mis on segfault signaali, ja see on, kus see juhtus juhtuda. Vaadates meie tagasijälitust, näeme, et me olime funktsioon oh_no, mis oli kutsunud funktsioon tilluke, mis oli kutsunud funktsioon Binky, mis oli kutsunud peamine. Me näeme ka argumente nende funktsioonidega. Väide, et tilluke ja Binky oli 1. Kui me loetelu funktsiooni oh_no, näeme, et oh_no on lihtsalt teed char ** s = NULL; * S = "buum"; Miks peaks, et ei suuda? [Üliõpilane] Sa ei saa dereference nullviit? >> Jah. See on lihtsalt öeldes s on NULL, sõltumata sellest, kas see juhtub olema char ** mis, sõltuvalt sellest, kuidas seda tõlgendada, võiks see olla kursor kursor string või massiivi stringe. See s on NULL, siis * s viite mahavõtmine nullviida, ja nii see läheb krahhi. See on üks kiiremaid viise saab olla segfault. See on lihtsalt kuulutatakse nullviida ja kohe segfaulting. Seda oh_no teeb. Kui me läheme üles ühe kaadri, siis me hakka funktsioon, mis nõudis oh_no. Ma pean tegema, et alla. Kui te ei sisesta käsk ja sa lihtsalt vajuta Enter uuesti, see lihtsalt korrata eelmise käsu, et sa jooksid. Meil on frame 1. Videod see raam, näeme siin on meie funktsioon. Võite tabas nimekirja uuesti, või saate teha nimekiri 20 ja see nimekiri veel. Funktsioon tilluke ütleb, et kui ma 1, siis minge oh_no funktsioon, muidu minna Keimaileva funktsioon. Ja me teame, i on 1, sest me juhtuda näha siin et tilluke kutsuti välja argumendi 1. Või saab lihtsalt printida i ja siis öelda, i on 1. Meil on praegu tilluke, ja kui me läheme üles teise raami, me teame, me lõpuks Binky. Up. Nüüd oleme Binky. Videod see funktsioon - nimekirja enne poole katkestas mind - Ta alustas nagu ma on 0, siis me ei kavatse seda nimetada oh_no, muidu kutsun tilluke. Me teame, olin 1, nii ta kutsus tilluke. Ja nüüd oleme tagasi peamine ja põhiline on lihtsalt saab olema int i = rand ()% 3; See on lihtsalt annan teile juhuslik arv, mis on kas 0, 1 või 2. See saab helistada Binky selle numbri ja siis tagastab 0. Vaadates seda, lihtsalt jalgsi läbi programmi käsitsi, ilma et tekiks kohe, sa paneks murdepunkt on peamine, mis tähendab, et kui me käivitada programmi teie programm töötab kuni see tabab murdepunkt. Nii töötab programm, see kestab ja siis tabab põhiülesanne ja peatub. Nüüd oleme sees peamine, ja järku või järgmise läheb toob meid järgmise rida koodi. Seda saab teha samm või kõrval. Lööb kõrval, nüüd ma on seatud rand ()% 3, seega saame trükkida väärtus i, ja siis öelda, i on 1. Nüüd see küsimus, kas me kasutame või järgmise sammu. Ma arvan, et ta Olulised eelmises, kuid me tahaks järgmisena kasutada. Kui me kasutame samm, me samm funktsioon, mis tähendab, pilk tegelik asi , mis toimub sees Binky. Kui me kasutame kõrval, siis see tähendab, minna üle funktsioon ja lihtsalt minna järgmisele koodirida meie peamine ülesanne. Siinsamas sellel liinil, olin kus ta ütles rand ()% 3; kui ma tegin samm oleks minna rakendamiseks rand ja vaata, mis toimub seal, ja ma võiksin sammult läbi Rand funktsioon. Aga ma ei hooli rand funktsiooni. Ma tahan minna järgmisele reale koodi peamine, et ma järgmisena kasutada. Aga nüüd ma hoolin Binky funktsioon, nii et ma tahan astuda sellest. Nüüd ma olen Binky. Esimene rida koodi on öelda, kui (i == 0), mina teen sammu, näeme me lõpuks kell tilluke. Kui me nimekiri asjadest, me näeme, et seda kontrollida on i = 0. Ma ei võrdu 0, nii et see läks teine ​​tingimus, mis läheb helistada tilluke (i). Te võite saada segaduses. Kui sa lihtsalt pilk need read otse, siis võiks arvata, kui (i == 0), okei, siis ma võtsin sammu ja nüüd ma olen tilluke (i), siis võiks arvata, et peab tähendama i = 0 või midagi. Ei, see tähendab lihtsalt, et ta teab seda saab kinni otse liin tilluke (i). Sest ma ei ole 0, siis järgmine samm ei kavatse lõpeb teine. Else ei ole kooskõlas see läheb peatu. See lihtsalt läheb minema järgmisele reale võib see tegelikult täidab, mis on tilluke (i). Astudes tilluke (i), näeme, kui (i == 1). Me ei tea, i = 1, nii et kui me samm, me teame, me ei kavatse sattuda oh_no sest i = 1 nõuab funktsiooni oh_no, kuhu saab astuda, mis läheb seada char ** s = null ja kohe "buum". Ja siis tegelikult vaadates rakendamise buggy2, seda, ma lihtsalt saada juhusliku numbri - 0, 1 või 2 - helistamine Binky, mis siis, kui ma on 0 see nõuab oh_no, muidu nõuab tilluke, mis kerkib siin. Kui i on 1 kõne oh_no, muidu kutsun Keimaileva, mis tulemas siin, kui i on 2, helistada oh_no. Ma isegi ei usu, et on viis - Kas keegi näeb, kuidas muuta see programm, mis ei segfault? Sest kui ma olen midagi puudu, kui i on 0, saate kohe segfault, muidu lähete funktsioon, mis, kui ma 1 sa segfault, muidu sa lähed funktsioon, kui ma on 2 te segfault. Nii et ükskõik, mida te teete, te segfault. Ma arvan, et üks võimalus millega oleks selle asemel teeme char ** s = NULL, võid malloc ruumi, et stringid. Võiksime teha malloc (sizeof) - sizeof mida? [Üliõpilane] (char) * 5? >> Kas see tundub õige? Ma oletan, et see toimib, kui ma tegelikult jooksis, kuid see pole see, mida ma otsin. Vaata tüüpi s. Olgem lisada int *, nii int * x. Teeksin malloc (sizeof (int)). Või kui ma tahtsin massiivi 5, ma teeksin (sizeof (int) * 5); Mis siis, kui mul on int **? Mida ma malloc? [Üliõpilane] suurus kursor. >> Jah. (Sizeof (int *)); Sama asi siin. Ma tahan (sizeof (char *)); See saab eraldada ruumi osuti, mis näitab, et "buum". Ma ei vaja eraldada ruumi "buum" ise sest see on põhimõtteliselt samaväärne sellega, mis ma enne ütlesin char * x = "buum". "Buum" on juba olemas. See juhtub, et on olemas ainult lugemiseks piirkonnas mälu. Aga see on juba olemas, mis tähendab seda rida koodi, kui s on char ** siis * s on char * ja sa oled, millega see char * käsk "buum". Kui ma tahtsin kopeerida "BOOM" ümber on, siis mul oleks vaja eraldada ruumi s. Ma teen * s = malloc (sizeof (char) * 5); Miks 5? Miks mitte 4? Tundub "buum" on 4 tähemärki. >> [Üliõpilane] null iseloomu. Jah. Kõik teie stringid läheb vaja null iseloomu. Nüüd ma saan teha midagi strcat - Mis on funktsioon, millega saab kopeerida string? [Üliõpilane] CPY? >> Strcpy. mees strcpy. Nii strcpy või strncpy. strncpy on veidi turvalisem, kuna saad määrata täpselt, kui palju märke, kuid siin ei ole oluline, sest me teame. Nii strcpy ja vaatan argumendid. Esimene argument on meie sihtkohta. Teine argument on meie allikas. Me läheme kopeerida meie sihtkohta * s pointer "buum". Miks võiks sa teha tahad seda strcpy asemel just see, mida meil oli enne kohta * s = "buum"? On põhjust võiksite seda teha, kuid mis see on põhjus? [Üliõpilane] Kui soovite midagi muuta "buum". >> Jah. Nüüd ma saan teha midagi s [0] = "X"; sest s punkte hunnik ja et ruumi hunnik et s on suunaga on viit rohkem ruumi hunnik, mis on hoidmiseks "buum". Nii et see koopia "buum" on salvestatud hunnik. Seal on tehniliselt kaks koopiat "buum" meie programmis. Seal on esimene, mis on lihtsalt antud seda "buum" string konstantne, ja teine ​​koopia "buum", strcpy loodud koopia "buum". Aga koopia "buum" on salvestatud hunnik, ja hunnik oled vaba muuta. Hunnik ei ole ainult lugemiseks, nii et tähendab, et s [0] läheb teil muuta väärtust "buum". See läheb teil muuta need märgid. Küsimused? Okei. Liikudes edasi buggy3, olgem gdb buggy3. Me lihtsalt käivitada ja näeme me segfault. Kui me tagasijälituse on ainult kaks ülesannet. Kui me läheme üles meie peamine ülesanne, näeme, et me GDB selles rida. Nii lihtsalt vaatab seda joont, for (int rida = 0; fgets see kraam ei võrdu NULL; rida + +). Meie eelmise kaadri kutsuti _IO_fgets. Sa näed, et palju sisseehitatud C funktsioone, et kui sa segfault, tekib tõesti segasena funktsioonide nimed Asjalik _IO_fgets. Aga see läheb seotud selle fgets kõne. Kusagil sisemuses siin oleme segfaulting. Kui me vaatame argumente fgets, saame trükkida puhver. Olgem printida - Oh, ei. Trüki ei kavatse tööd täpselt nii, nagu ma tahan seda. Vaatame programmi tegelik. Puhvrit iseloomu massiivi. See on märk array 128 märki. Nii et kui ma ütlen prindi puhver, see saab printida need 128 tähemärki mis ma arvan, on see, mida oodatakse. Mida ma otsisin on printida aadress puhver, kuid mis tegelikult ei ütle mulle palju. Nii et kui ma juhtun ütlema siin x puhver, näitab see mulle 0xbffff090, mis, kui sa mäletad varasemate või mingil hetkel Oxbffff kipub olema korstna-ish piirkonnas. Korstnat kipub kuskilt alustama veidi alla 0xc000. Lihtsalt nähes seda aadressi, ma tean, et puhvrit juhtub pinu. Taaskäivitamine minu programmi käivitada, üles puhverdada nägime oli see märgijada et on päris palju mõttetu. Siis printida faili, mida ei faili välja näeb? [Üliõpilane] Null. >> Jah. Fail on tüüpi FILE *, seega on pointer, ja väärtus, et osuti on null. Nii fgets läheb püüdma lugeda, et kursorit kaudses mõttes, vaid selleks, et pääseda et osuti, peab ta dereference ta. Või selleks, et pääseda mida tuleb osutades, see dereferences ta. Nii et see on viite mahavõtmine nullviida ja see segfaults. Ma oleks uuesti sinna. Kui me break meie Peaasi ja joosta, esimene rida koodi on char * filename = "nonexistent.txt"; See peaks andma päris suur vihje, miks seda programmi ei õnnestu. Kirjutamise kõrval toob mind järgmise rea, kus ma seda faili avada, ja siis ma kohe sattuda meie rida, kus kord ma tabanud kõrval, see läheb segfault. Kas keegi taha visata põhjus, miks me võiks segfaulting? [Üliõpilane] Faili ei ole olemas. >> Jah. See peaks olema vihje et kui sa avad faili peate kontrollima, et fail on tegelikult olemas. Nii et siin, "nonexistent.txt"; Kui me fopen failinimi lugemiseks, me siis peame ütlema if (fail == NULL) ja öelda printf ("Faili ei ole olemas!" või - veel parem - failinimi); return 1; Nii et nüüd me vaadata, kui see on NULL enne tegelikult jätkub ja üritab lugeda, et faili. Saame uusversioon see lihtsalt näha, et see toimib. Ma ette lisada uus rida. Nüüd nonexistent.txt ei eksisteeri. Alati tuleb kontrollida sellist asja. Alati tuleb vaadata, kui fopen tagastab NULL. Alati tuleb vaadata, et veenduda, et malloc ei tagasta NULL, või sa segfault. Nüüd buggy4.c. Running. Olen aim see ootab sisend või olla lõpmatu silmuspõletamise. Jah, see on lõpmatu silmuspõletamise. Nii buggy4. Tundub, et me oleme lõpmatu silmuspõletamise. Me ei poolita peamine, kulgema meie programm. In gdb, kui lühend te kasutate on ühemõtteline või eriline lühendid, et nad pakuvad teile, siis saate kasutada n järgmisena kasutada, selle asemel et tüüp välja järgmisel lõpuni. Ja nüüd, et ma olen tabanud n kord, ma ei saa lihtsalt vajuta Enter hoida läheb järgmisel selle asemel, et tabanud n Enter, n Enter, n Enter. Tundub, et ma olen mingi loop mis on millega massiiv [i] 0-ga. Tundub, et ma olen kunagi murrab läbi selle jaoks silmus. Kui ma printida i, nii et ma on 2, siis ma lähen järgmine. Ma printida i, i on 3, siis ma lähen järgmine. Ma printida i ja i on 3. Seejärel printida i, i on 4. Tegelikult prindi sizeof (massiiv), nii suurus massiiv on 20. Aga tundub, seal on mõned erilised gdb käsk läheb kuni midagi juhtub. See on nagu milles tingimus, muutuja väärtus. Aga ma ei mäleta, mis see on. Nii et kui me jätkame - Mida sa öelda tahad? Mida sa tuua? [Üliõpilane] Kas kuvada i lisada - >> Jah. Nii et kuvada saan aidata. Kui me lihtsalt kuvada i, siis panna siin, mida I väärtus on nii et ma ei pea seda välja printida iga kord. Kui me muudkui läheb järgmisel näeme 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5. Midagi läheb kohutavalt valesti, ja ma on nullitud kuni 0. Vaadates buggy4.c näeme kõik, mis juhtub on int massiiv [5]; for (i = 0; i <= sizeof (massiiv); i + +) massiiv [i] = 0; Mida me näeme, et on valesti siin? Nagu vihje, kui ma tegin gdb buggy4 - olgem murda peamine, run - Ma ei prindi sizeof (massiiv) lihtsalt näha, mis seisukorras on, kus ma peaks lõpuks välja murda. Kus ma olen? Kas ma saan? Ma ei tunnistanud veel. Nii et printida sizeof (massiiv) ja see on 20, mida oodata, sest minu massiiv on suurus 5 ja see on 5 täisarvud, nii et kogu asi peaks olema 5 * sizeof (int) baiti, kus sizeof (int) kipub olema 4. Nii sizeof (massiiv) on 20. Mis see peaks olema? [Üliõpilane] jagatud sizeof (int). >> Jah, / sizeof (int). Tundub, seal on ikka probleem. Arvan, et see peaks just olema < kuna see on päris palju alati > [Bowden] Jah. Kui me läheme kaugemale lõpuks meie massiiv, kuidagi seda ruumi, et me ülekaaluka on ülekaalukas väärtus i. Ja kui me vaatame buggy4, murda peamine, run, olgem printida aadress i. Tundub, et see on bffff124. Vaatame nüüd printida aadress massiiv [0]. 110. Aga [1]? 114. [2], 118. 11c, 120. array [5] on bfff124. Nii array [5] on samal aadressil, i, mis tähendab, et array [5] on i. Kui nad on sama aadress, siis on sama asi. Nii et kui me seame array [5] 0, seame me I 0. Ja kui sina arvad sellest nii korstnat int i tunnistatakse esimene, mis tähendab i saab mõned ruumi virnas. Siis array [5] on eraldatud, nii siis 20 baiti jaotatakse pinu. Nii et ma saab eraldada, siis need 20 baiti saada eraldatud. Nii et ma juhtub just enne massiivi ja selle tõttu, kuidas, nagu ma ütlesin eelmisel nädalal, kui see on tehniliselt stack kasvab alla kui indeks array, meil on tagatud, et 0. positsiooni massiivi alati juhtub enne esimest positsiooni massiivi. See on selline kuidas ma joonistasin ta eelmisel nädalal. Pange tähele, et allosas meil aadressile 0 ja ülaosas oleme aadress Max. Stack kasvab pidevalt maha. Oletame, et me eraldada i. Me eraldada täisarv i, mis tähendab, ütleme lihtsalt siia täisarv i saab eraldada. Siis me eraldada meie massiivi 5 täisarvud, mis tähendab, et selle all, et Kuna stack kasvab alla, need 5 täisarvud saada eraldatud. Aga kuna kuidas massiivid töötada, me garanteerida, et esimesele kohale massiivi alati on aadress väiksem kui teine ​​asi massiiv. Nii massiivi asendisse 0 alati peab juhtuma esimene mälu, arvestades massiivi positsiooni 1 peab juhtuma pärast seda ja massiivi positsiooni 2 peab juhtuma pärast seda, mis tähendab, et massiivi asendisse 0 juhtuks kuskil siin all, massiivi positsiooni 1 juhtuks eespool, et sest liikuva tähendab kõrgemat aadressid, sest maksimaalne aadress on siin. Nii massiiv [0] siin all, massiiv [1] siin, massiiv [2] siin, massiiv [3] siin. Teade kuidas enne me eraldatud täisarvu i kogu tee siia, kui me liigume kaugemale ja sügavamale meie massiiv, saame üha lähemale meie täisarv i. See lihtsalt nii juhtub, et array [5], mis on üks positsioon väljaspool meie massiiv, on täpselt, kus täisarv sattusin eraldatud. Nii et see punkt, kus me juhtumisi lööb ruumi virnas mis oli eraldatud täisarvu i, ja me kehtestamisel, et 0-ga. Nii et toimib. Küsimused? Jah. [Üliõpilane] Never mind. Okei. [Üliõpilane] Kuidas vältida neid omamoodi vigu? Need omamoodi vigu? Ärge kasutage C oma programmeerimiskeelt. Kasuta keelt, mis on massiivi piire kontrollida. Niikaua kui sa oled ettevaatlik, sa lihtsalt vaja, et vältida läheb mööda piire oma massiivi. [Üliõpilane] Nii siin, kui me läksime mööda piire oma massiivi - [Bowden] See, kui asjad hakkavad valesti. >> [Üliõpilane] Oh, okei. Niikaua kui teil jäävad mällu eraldatud oma massiiv, sa oled hea. Aga C ei ole veatuvastuse. Kui ma massiiv [1000], siis hea meelega lihtsalt muuta mis juhtub - See läheb alguses massiivi, siis läheb 1000 asukoha pärast ja seab selle 0-ks. Ta ei tee ühtegi kontrolli, et oh, see ei ole tegelikult olla 1000 asjad seal. 1000 on nii kaugemale Oleksin muutumises, arvestades, Java või midagi saad massiivi audis indeks või indeks auti erand. Sellepärast palju kõrgemal tasemel keeles on need asjad kus, kui te minna kaugemale piire massiiv, sa ei suuda nii et sa ei saa muuta asju altpoolt te ja siis lähevad asjad palju hullem kui lihtsalt saada erand ütle, et sa ületasid lõpuks massiiv. [Üliõpilane] Ja nii me peaksime just muutunud <= lihtsalt > [Bowden] Jah. See peaks olema > [Üliõpilane] Õigus. Veel küsimusi? Okei. [Üliõpilane] Mul on küsimus. >> Jah. [Üliõpilane] Mis on tegelik massiivi muutuja? [Bowden] Nagu mida on massiivi? Array ise on sümbol. See on lihtsalt aadress algust 20 baiti, et me viitamine. Sa ei mõtle seda kui osuti, kuid see on pidev pointer. Niipea kui asjad koostatud, muutuja massiivi ei eksisteeri enam. [Üliõpilane] Niisiis, kuidas see leida suurust massiivi? Suurus array viitab suurus, mis blokeerivad et sümbol viitab. Kui ma midagi sellist printf ("% p \ n", array); olgem käivitada. Mida ma just tegin valesti? Array Massiiv deklareeritakse siin. Oh, siin. Rõkkama on tark, ja see juhtub märkama, et ma kuulutatud array 5 elementi aga ma indekseerimise kohale 1000. Seda saab teha, sest need on lihtsalt konstandid. Ta saab minna ainult nii kaugele märganud, et ma lähen piiridest massiivi. Aga teate enne, kui meil oli i vale, see ei ole võimalik määrata, kui palju väärtusi ma võiks võtta, nii et see ei saa kindlaks teha, et ma läksin kauem massiivi. See on lihtsalt rõkkama on tark. Aga nüüd teha buggy4. Mis siis veel ma teen valesti? Kaudselt kuulutatakse raamatukogu funktsiooni "printf". Ma tahan # include . Okei. Nüüd töötab buggy4. Printimine väärtuse massiivi nagu ma siin tegin, trüki see pointer trükib midagi, mis näeb välja selline - bfb8805c - mis on mõned aadress see on seadmes-ish piirkonnas. Array ise on nagu osuti, kuid see ei ole tegelik pointer, kuna regulaarne osuti saame muuta. Array on vaid mõned konstantne. 20 kvartalit mälu algab aadress 0xbfb8805c. Nii bfb8805c läbi selle aadressi +20--või ma arvan -20 - on kõik mälu eraldatakse see massiiv. Array, muutuja ise ei salvestata kuhugi. Kui olete koostamise, tõlkija - käsi lehvita seda - kuid kompilaator lihtsalt kasutada kui ta teab massiiv olla. Ta teab, kus see massiiv hakkab, ja nii see saab alati lihtsalt teha asju nii korvab selle algust. See ei pea muutuja ise esindada massiivi. Aga kui ma midagi sellist int * p = array; nüüd p on viit, mis osutab, et massiiv, ja nüüd p tegelikult ei eksisteeri pinu. Ma olen vabalt muuta lk. Ma suudan p = malloc. Nii see algselt viitas massiivis nüüd see esile mõningaid ruumi hunnik. Ma ei saa array = malloc. Kui rõkkama on tark, siis karju mu õigus ära nahkhiir. Tegelikult olen ma üsna kindel, et gcc teeks seda ka. Nii massiivi tüüp "int [5]" ei ole võõrandatav. Sa ei saa anda midagi massiivi tüüp sest massiiv on lihtsalt konstant. See on sümbol, millised viited need 20 baiti. Ma ei saa seda muuta. [Üliõpilane] Ja kus on suurus array salvestada? [Bowden] See ei ole salvestatud kuhugi. See on, kui ta on koostamisel. Nii et kui on suurus array salvestada? Seda saab kasutada ainult sizeof (massiiv) sees funktsiooni, et massiiv on kuulutanud end. Nii et kui ma teen mingi funktsiooni, suva, ja mina (int massiiv []) printf ("% d \ n", sizeof (massiiv)); ja siis siia ma kutsun foo (massiiv); sees seda funktsiooni - olgem käivitada. See on rõkkama on tark uuesti. See ütleb mulle, et sizeof kohta massiivi funktsiooni parameeter naaseb suurus "int *". See oleks viga, kui see pole see, mida ma tahtsin juhtuda. Olgem tegelikult lülitada Werror. Hoiatus. Hoiatused on kõik korras. See on siiski koguda nii kaua, kui see on hoiatus. . / A.out läheb printida 4. Hoiatus, mis oli loodud on selge märk, mis läks valesti. See int massiiv on lihtsalt trükkimise sizeof (int *). Isegi kui ma panen array [5] siin, see on ikka lihtsalt trükkimise sizeof (int *). Nii et niipea kui sa sinna juhitakse funktsioon, vahet massiivid ja viiteid on olematu. See juhtub olema massiivi kuulutas korstnat kuid niipea, kui võtame seda väärtust, et 0xbf blaa, blaa, blaa sellesse funktsiooni, siis see osuti osutab, et massiivi kohta virna. See tähendab, et sizeof kehtib ainult funktsioon, mis massiivi tunnistati, mis tähendab, et kui teil on koostamisel seda funktsiooni, kui rõkkama läbib seda funktsiooni, see näeb massiiv on int array suurus 5. Siis ta näeb sizeof (massiiv). Noh, see on 20. See on tegelikult kuidas sizeof põhimõtteliselt töötab peaaegu kõikidel juhtudel. Sizeof ei ole funktsioon, see on operaator. Sa ei helista sizeof funktsioon. Sizeof (int), kompilaator lihtsalt tõlkida, et kuni 4. Said aru? Okei. [Üliõpilane] Mis vahe on sizeof (massiiv) on peamine ja suva? Seda seetõttu, et me ütleme sizeof (massiiv), mis on tüüpi int *, arvestades, et massiivi siin all ei ole tüüpi int *, see on int massiiv. [Üliõpilane] Nii et kui teil oli parameetri array [] asemel int * massiiv, kas see tähendab, et sa võiksid veel muutuda massiivi, sest nüüd on pointer? [Bowden] Nagu see on? >> [Üliõpilane] Jah. Kas te muudate array jooksul funktsioon nüüd? [Bowden] Sa võid muuta massiivi mõlemal juhul. Mõlemal juhul võite vabalt öelda, massiiv [4] = 0. [Üliõpilane] Aga sa saad teha massiivi käsk midagi muud? [Bowden] Oh. Jah. Mõlemal juhul - >> [üliõpilane] Jah. [Bowden] vahet massiiv [] ja int * massiiv, ei ole. Samuti saate mõned mitmemõõtmelise massiivi siin mõned mugav süntaks, kuid see on ikka lihtsalt kursor. See tähendab, et ma olen vaba tegema massiiv = malloc (sizeof (int)); ja nüüd juhtida kusagil mujal. Aga lihtsalt meeldib, kuidas see töötab igavesti ja alati, muutes selle massiivi muutes viitavad millegi muuga Seda ei muuda massiivi siia alla kuna see on koopia argument, see ei ole osuti sellele argumendile. Ja tegelikult, nagu rohkem märge, et see on täpselt sama - me juba nägime, mida trükkimine massiivi pildid - Mis siis, kui me printida aadress massiiv või aadress aadress massiivi et kumbki neist? Olgem ignoreerida seda. Okei. See on hea. See on nüüd töökorras. / A.out. Trükkimine massiiv, siis trüki aadress massiiv, on sama asi. Array lihtsalt ei ole olemas. Ta teab, kui te prindite massiiv, te prindite sümbol, mis viitab neile 20 baiti. Printimine aadress massiivi, noh, massiiv ei eksisteeri. See ei pea aadress, nii see lihtsalt trükib aadress need 20 baiti. Niipea kui sa kompileerida alla, nagu teie koostatud buggy4. / A.out, massiiv on olematu. Näiturid olemas. Massiivid ei ole. Plokid mälu esindavad massiivi endiselt olemas, kuid muutuja massiivi ja muutujate seda tüüpi ei eksisteeri. Need on nagu peamised erinevused massiivid ja viiteid on niipea kui teete funktsioon nõuab, ei ole mingit vahet. Aga sees funktsiooni, et massiiv ise on välja kuulutatud, sizeof töötab erinevalt kuna te prindite suurus plokid asemel suurusest tüüp, ja sa ei saa seda muuta, sest see on sümbol. Printimine asi ja aadress asi prindib sama asi. Ja see on päris palju see. [Üliõpilane] Kas te ütlete, et veel üks kord? Ma oleks võinud vastamata midagi. Trükkimine massiivi ja aadress massiivi prindib sama asi, samas kui prindite pointer vs aadress pointer, üks asi prindib aadress mida sa osutades, muud prindib aadress kursorit pinu. Saate muuta pointer, sa ei saa muuta massiivi sümbol. Ja sizeof osuti läheb printida suurusest et osutiloendurid. Nii int * p sizeof (p) trükkimineku 4, kuid int massiiv [5] prindi sizeof (massiiv) on trükkimineku 20. [Üliõpilane] Nii int massiiv [5] prindib 20? >> Jah. Sellepärast sees buggy4 kui ta varem sizeof (massiiv) Selle tegin ma <20, mis ei ole see, mida tahtsime. Tahame i <5. >> [Üliõpilane] Okei. [Bowden] Ja siis niipea kui hakkate läbivad ülesanded, kui me tegime int * p = array; sees seda funktsiooni, saame põhimõtteliselt kasutada p ja massiivi täpselt samal viisil, välja arvatud sizeof probleem ja muutuva probleemi. Aga p [0] = 1; on sama, mis öelda massiiv [0] = 1; Ja niipea kui me ütleme foo (massiiv); või foo (p); sees suva funktsioon, see on sama kõne kaks korda. Ei ole erinevus nende kahe kõned. Igaüks head on? Okei. Meil on 10 minutit. Üritame saada läbi selle Hacker Typer programmi sellel veebilehel, mis tuli välja eelmisel aastal või midagi. See on lihtsalt pidi olema nagu kirjutad juhuslikult ja ta prindib välja - Ükskõik faili see juhtub laaditud on see, mis tundub nagu sa kirjutad. See näeb välja nagu mingi operatsioonisüsteemi koodi. See, mida me tahame rakendada. Sul peaks olema binaarsel nimega hacker_typer mis võtab ühe argumendi, fail "häkker tüüp." Running käivitatava peaks selge ekraan ja siis printida välja üks sümbolitest edasikanduvad failis iga kord, kui kasutaja vajutab. Mida iganes klahvi vajutate, peaks ta minema visata ja selle asemel trükkida tegelasele fail mis on argument. Ma päris palju öelda, mida asjadest me ei kavatse vaja teada on. Aga me tahame kontrollida termios raamatukogu. Ma ei ole kunagi kasutanud seda raamatukogu kogu mu elu, nii et see on väga minimaalne eesmärkidel. Aga see saab olema raamatukogu saame kasutada ära visata märk põrkad kui sa kirjutad kirjakeele sisse Nii hacker_typer.c, ja me ei kavatse taha # include . Vaadates man-leheküljelt termios - Ma aim see terminal OS või midagi - Ma ei tea, kuidas seda lugeda. Vaadates seda, ta ütleb, et hõlmata need 2 faili, nii et me teeme seda. Kõigepealt esimene, me tahame võtta ühe argumendi, mis on faili peaksime avama. Mida ma tahan teha? Kuidas vaadata Mul on üks argument? [Üliõpilane] Kui argc võrdub see. >> [Bowden] Jah. Nii et kui (argc! = 2) printf ("Kasutamine:% s [Avatav]"). Nii et nüüd, kui ma saan seda ilma et teine ​​argument - oh, mul on vaja uut rida - näete seda ütleb kasutamine:. / hacker_typer, ja siis teine ​​argument peaks olema faili tahan avada. Mida ma nüüd teen? Ma tahan lugeda seda pilti. Kuidas lugeda failist? [Üliõpilane] avate seda esimesena. >> Jah. Nii fopen. Mis fopen välja näeb? [Üliõpilane] Filename. >> [Bowden] Faili saab olema argv [1]. [Üliõpilane] Ja siis, mida sa tahad sellega teha, nii - >> [Bowden] Jah. Nii et kui te ei mäleta, siis võiks lihtsalt teha mees fopen, kus see saab olema const char * tee, kus tee on failinimi, const char * režiimis. Kui juhtub, et ei mäleta, mida režiim on, siis võid otsida režiimis. Toas man lehekülgi kaldkriipsuga mida saate otsida asju. Nii et ma kirjutada / mode otsida režiimis. n ja N, mida saab kasutada tsükli läbi otsida vastet. Siin öeldakse argument režiim viitab string alustades üks järgnevatest koodidest. Nii R, avatud tekstifaili lugemiseks. See, mida me tahame teha. Lugemiseks, ja ma tahan hoida seda. Asi saab olema FILE *. Mida ma nüüd teha tahad? Andke mulle hetk aega. Okei. Mida ma nüüd teha tahad? [Üliõpilane] Kontrollige, kas see on NULL. >> [Bowden] Jah. Iga kord, kui avate faili, veenduge, et olete edukalt suutnud seda avada. Nüüd ma tahan teha, et termios värk, kus ma tahan kõigepealt lugeda minu praegused seaded ning salvestada need millekski, siis tahan ma oma seadeid muuta visata suvaline märk, et ma tüüpi, ja siis ma tahan uuendada neid seadeid. Ja siis lõpus programm, ma tahan muuta tagasi oma algsed seaded. Nii struct saab olema tüüpi termios, ja ma lähen taha kaks neist. Esimene saab olema minu current_settings, ja siis nad ei kavatse olla minu hacker_settings. Esiteks, ma lähen soovite salvestada minu praegused seaded, siis ma lähen soovite värskendada hacker_settings, ja siis tee lõpus minu programm, ma tahan tagasi praegused seaded. Nii säästa praeguste seadetega viisil, mis toimib, siis mees termios. Me näeme, et meil on see int tcsetattr, int tcgetattr. Ma läbida termios struct oma pointer. Kuidas see välja nägema on - Ma olen juba unustanud, mida funktsioon kutsuti. Kopeeri ja kleebi see. Nii tcgetattr, siis ma tahan läbida struct, et ma hoian teavet, mis saab olema current_settings, ja esimene argument on failipide jaoks asi, mida ma tahan salvestada atribuudid. Mis failipide on nagu iga kord, kui avate faili, see läheb failipide. Kui ma fopen argv [1], siis saab faili deskriptor mis sa viitad kui soovite lugeda või sellele kirjutada. See pole failipide ma tahan kasutada siin. On kolm faili kirjelduste teil on vaikimisi mis on standard, standardi välja ja standardviga. Vaikimisi Ma arvan, et see standard on 0, standard välja on 1 ja standard viga on 2.. Mida ma tahan muutke? Ma tahan muutke kui ma tabanud iseloomuga, Ma tahan seda visata, et iseloomu ära printimise asemel selle ekraani. Mis oja - standard, standard välja, või standardviga - vastab asju, kui ma tüüpi kell klaviatuuri? >> [Üliõpilane] Standard logitud >> Jah. Ma võin kas teha 0 või ma teha saan stdin. Ma saan current_settings standardi sisse Nüüd ma tahan uuendada need seaded, Nii et esimene Ma kopeerida sisse hacker_settings mida mu current_settings on. Ja kuidas structs töö on see lihtsalt kopeerida. See kopeerib kõik väljad, kui te ootaks. Nüüd ma tahan uuendada mõned väljad. Vaadates termios, siis oleks läbi lugeda palju see lihtsalt näha, mida te soovite otsida, kuid lippe sa lähed tahad otsida on kaja, nii Kaja Kaja sisend tähemärki. Esiteks tahan, et seada - Ma olen juba unustanud, mis väljad on. See on see, mida struct välja näeb. Nii režiime Ma arvan, me tahame muuta. Me vaatame lahendus veenduda, et see, mida me tahame muuta. Me tahame muuta lflag vältimiseks oleks vaja vaadata läbi kõik need. Me tahame muuta kohalike olekutes. Sa oleks võinud läbi lugeda kogu see asi, et mõista, kus kõik kuulub et me tahame muuta. Aga see on sees kohalike režiimid, kuhu me läheme, et soovite muuta. Nii hacker_settings.cc_lmode on, kuidas seda nimetatakse. c_lflag. See on koht, kus me sattuda BitWise ettevõtjad. Oleme selline aeg otsa, aga me läheme läbi see reaalne kiire. See on koht, kus me sattuda BitWise ettevõtjad, kus ma arvan, ma ütlesin üks kord ammu, et kui hakkate tegelevad lipud, sa kavatsed kasutada BitWise operaatori palju. Iga natuke lipu vastab mingisugune käitumine. Nii et siin, see lipp on hunnik erinevaid asju, kus nad kõik tähendab midagi muud. Aga mida ma tahan teha, on lihtsalt lülitage natuke, mis vastab kaja. Nii et olukorda muuta ära mina & = ¬ humanitaarabi. Tegelikult ma arvan, et see on nagu techo või midagi. Ma lähen, et kontrollida uuesti. Ma ei termios ta. See on lihtsalt kaja. ECHO saab olema ühe natuke. ¬ humanitaarabi läheb tähenda kõik bitid on seatud 1, mis tähendab, kõik lipud on seatud tõeseks välja arvatud humanitaarabi natuke. Autor lõpeb mu kohalik lipud sellega, see tähendab, kõik lipud, mis on praegu seatud tõeseks ikkagi on true. Kui minu ECHO lipp on seatud tõeseks, siis see on tingimata seatud vale kohta ECHO lipp. Nii et see rida koodi lihtsalt lülitab ECHO lipp. Teine rida koodi, ma lihtsalt kopeerida neid huvides aega ja siis selgitada. Lahuses, ütles ta 0. See on ilmselt parem selgesõnaliselt öelda stdin. Pange tähele, et ma olen ka teed ECHO | icanon siin. Icanon viitab millelegi eraldi, mis tähendab, kanooniline režiimis. Mis kanooniline režiimi abil on tavaliselt siis, kui tipite välja käsurealt standard ei töötle midagi, kuni te tabanud reavahetus. Nii et kui sa getString, kirjutad hunnik asju, siis põrkad reavahetus. See, kui see on saadetud standard sisse See on vaikimisi. Kui ma välja lülitada kanooniline režiim, nüüd iga märgi, kui vajutate on see, mida saab töödelda, mis on tavaliselt selline halb, sest see on aeglane protsess nende hulgas mis on põhjus, miks see hea puhverdada see kogu liini. Aga ma tahan iga märk tuleb töödelda sest ma ei taha seda ootama mind lüüa reavahetus enne ta töötleb kõik märgid ma olen kirjutades. See lülitab kanooniline režiimis. See värk lihtsalt tähendab, kui ta tegelikult töötleb tähemärki. See tähendab, töödelda neid koheselt niipea, kui ma kirjutades neid, töötleb neid. Ja see on funktsioon, mis värskendab minu seaded standard, ja TCSA vahenditega seda teha just nüüd. Teised viisid on oodata kõike, mis on praegu oja on töödeldud. See ei ole tegelikult küsimus. Just praegu oma seadeid muuta, et kõik, mis on praegu hacker_typer_settings. Ma arvan, et ma kutsusin seda hacker_settings, niiet muuda. Muutus kõike hacker_settings. Nüüd lõpus meie programmi me ei kavatse soovivad naasta sellega, mis on praegu sees normal_settings, mis läheb lihtsalt nägema ja normal_settings. Teade ma ei ole muutunud kõik mu normal_settings kuna algselt saada tööd. Siis lihtsalt muuta neid tagasi, annan neile tagasi lõpus. See oli uuendatud. Okei. Nüüd sees siin ma lihtsalt seletada kood huvides aeg. See ei ole nii palju koodi. Me näeme me lugeda tegelasele faili. Me nimetasime seda f. Nüüd saate mees fgetc, kuid kuidas fgetc läheb tööle on lihtsalt see läheb tagasi märk, et sa lihtsalt lugeda või EOF, mis vastab faili lõppu või mõni viga juhtub. Meil on silmuspõletamise, jätkates lugeda ühe märgi toimikust, kuni meil otsa tähemärki lugeda. Ja kui me teeme, et me ootame ühele tegelasele standard sisse Iga kord, kui kirjutad midagi, mida käsurea, et loeb ka tegelasele standard sisse Siis putchar on lihtsalt panen char loeme siin failist standard välja. Võite mees putchar, aga see on lihtsalt paneb standard välja, see trükkimise et iseloomu. Võid ka teha printf ("% c", c); sama mõte. See saab teha suurema osa meie tööst. Viimane asi, mida me kavatseme teha tahad on lihtsalt kirjutamisel meie fail. Kui sul ei ole kirjutamisel, see on mälu leke. Me tahame kirjutamisel faili me algselt avatud, ja ma arvan, et see on. Kui me teeme seda, ma juba sain probleeme. Vaatame. Mida see kurdavad? Oodati 'int', kuid argument on tüüpi "struct _IO_FILE *". Eks näis, kui see toimib. Lubatud ainult C99. Augh. Okei, teha hacker_typer. Nüüd saame kasulikum kirjeldusi. Nii et kasutage deklareerimata tunnus "normal_settings". Ma ei nimetaks seda normal_settings. Ma helistasin talle current_settings. Nii et olgem muuta kõike seda. Nüüd kulgeb argument. Ma teen seda 0 nüüd. Okei. . / Hacker_typer cp.c. Ma ka ei ekraani tühjendamiseks alguses. Aga sa võid vaadata tagasi viimase lahendamist näha, kuidas ekraani tühjendamiseks. See on lihtsalt printida mõned märgid Kuigi see teeb mida ma tahan teha. Okei. Ja mõelda, miks see vajalik on 0 standardsisendi asemel, mida tuleks # define 0, Selle kaebab, et - Enne kui ma ütlesin, et seal on fail kirjeldustega, kuid siis on teil ka oma FILE *, failipide on lihtsalt üks täisarv, arvestades, FILE * on terve hunnik asju sellega seotud. Põhjus, miks me peame ütlema 0 asemel stdin on, et stdin on FILE * mis viitab asi, mis on viitamine failipide 0. Nii et isegi siin, kui ma fopen (argv [1] Ma saan FILE * tagasi. Aga kusagil seda faili * on asi vastab failipide seda toimikut. Kui te vaatate mees leht avatud, nii et ma arvan, et sa pead tegema mees 3 avatud - nope - mees 2 avatud - jah. Kui te vaatate lehte avatud, avatud on nagu madalama taseme fopen, ja see on jälle tegelik failipide. fopen ei hunnik kraami peal avatud, mis tagasipöördumise asemel just seda faili deskriptor tagastab kogu FILE * pointer mille sees on meie väike failipide. Nii standard viitab FILE * asi, arvestades, 0 tähendab lihtsalt failipide standard iseenesest. Küsimused? [Naerab] puhus läbi, et. Hea küll. Me oleme valmis. [Naerab] [CS50.TV]