[Powered by Google Translate] [Sekcio 5 - Pli Vasta] [Rob Bowden - Universitato Harvard] [Jen CS50. - CS50.TV] Kiel mi diris en mia retpoŝto, ekzistas multe da aferoj, kiujn vi povas uzi escepte la aparaton al reale fari la problemo aroj. Ni rekomendas al vi fari tion en la aparaton nur ĉar tiam ni povas pli facile helpi vin kaj ni scias kiel ĉio tuj funkciis. Sed kiel unu ekzemplon de kie vi povas fari tion se, ekzemple, vi ne havas aliron al aparaton aŭ vi volas labori en la Science Center kelo - kiu reale havas la aparaton tro - se vi volas labori ie ajn. Unu ekzemplo estas vi vidis / aŭdis SSH? SSH estas esence same kiel konekti al iu. Efektive, nun mi SSHed en la aparaton. Mi neniam labori rekte en la aparaton. Jen la aparaton, kaj se vi rigardas malsupren tie vi vidas ĉi IP adreso. Mi neniam labori en la aparaton mem; Mi ĉiam venu al iTerm2 fenestro / fina fenestro. Vi povas SSH al tiu IP-adreso, ssh jharvard@192.168.129.128. Mi memoras tiun ciferon tre facile, ĉar ĝi estas tiom bela ŝablono. Sed tio demandos min por mia pasvorto, kaj nun mi estas en la aparaton. Esence, je ĉi tiu punkto, se vi malfermis fina ene de la aparaton mem, ĉi interfacon, tamen vi uzus ĝin, estas ĝuste la sama kiel la interfaco Mi uzas super tie sed nun vi SSHed. Vi ne devas SSH al la aparaton. Unu ekzemplo de alia loko vi povis SSH al estas mi sufiĉe certas ke vi havas defaŭlte - Oh. Pli granda. Vi ĉiuj devus havi defaŭlte FAS rakontas pri la FAS-serviloj. Por mi, mi volus SSH al rbowden@nice.fas.harvard.edu. Ĝi tuj demandas al vi, ke la unua fojo, kaj vi diros jes. Mia pasvorto nur tuj estos mia FAS pasvorton. Kaj tial nun, mi SSHed al la bela serviloj, kaj mi povas fari ion mi volas ĉi tie. Multaj klasoj vi povus preni, kiel 124, tuj vi alŝutu stuff ĉi tien al reale proponi vian problemon aroj. Sed diru vi ne havas aliron al via aparaton. Tiam vi povas fari tion, kiel ĉi tie ĝi diros - Tiu estas nur nia sekcio de demandoj. Ĝi petos vin fari tion en la aparaton. Anstataŭe mi nur faras ĝin en la servilo. Mi tuj maldensigi tio. La problemo tuj estos ke vi kutimis uzi iun kiel gedit aŭ kion ajn ene de la aparaton. Vi ne havos ke sur la FAS-servilo. Ĝi estas ĉiuj nur tuj estos ĉi teksta interfaco. Do vi povus ĉu unu, provu lerni tekstoredaktilo ke ili ja havas. Ili havas Nano. Nano estas kutime bela facila uzi. Vi povas uzi vian sagojn kaj tajpu normale. Do tio ne peza. Se vi volas vere fantaziaj vi povas uzi Emacs, kiun mi probable ne devus esti malfermita ĉar mi eĉ ne scias kiel fermi Emakso. Kontrolo X, Kontrolo C? Yeah. Aŭ vi povas uzi Vim, kiu estas kion mi uzas. Kaj tial tiuj estas viaj ebloj. Se vi ne volas fari tion, vi povas ankaŭ, se vi rigardas manual.cs50.net-- Oh. En la PC, vi povas SSH uzante PuTTY, kion vi tuj devos elŝuti aparte. Sur Mac, vi povas simple defaŭlte uzo Terminal aŭ vi povas elŝuti iTerm2, kio estas kiel bela, fantazio Terminal. Se vi iras al manual.cs50.net vi vidos ligon al Notepad + +, kiu estas kiu vi povas uzi en la PC. Ĝi permesas SFTP de Notepad + +, kiu estas esence SSH. Kio ĉi lasos vin fari estas redakti viajn dosierojn loke, kaj poste kiam ajn vi volas savi ilin, ĝi helpos al nice.fas, kie vi povas poste ekzekuti ilin. Kaj la ekvivalenta sur Mac tuj estos TextWrangler. Do ĝi lasas vin fari la samon. Ĝi ebligas ŝanĝi dosierojn surloke kaj gardi ilin nice.fas, kie vi povas poste ekzekuti ilin. Do se vi iam kaptita sen aparaton, vi havas tiujn opciojn ankoraŭ fari vian problemon aroj. La problemo tuj estos ke vi ne tuj havos la CS50 biblioteko ĉar nice.fas ne defaŭlte havi tiun. Vi povas aŭ elŝuti la CS50 biblioteko - Mi ne kredas ke mi bezonas ke en ĉi tiu punkto. Vi povas aŭ elŝuti la CS50 biblioteko kaj kopii ĝin al nice.fas, aŭ mi kredas je ĉi tiu punkto ni ne uzas ĝin plu ĉiuokaze. Aŭ se ni faras, vi povas por la epoko esti anstataŭigi ĝin per la realigoj de la funkcioj en la CS50 biblioteko ĉiuokaze. Por ke ne devus esti tiu parto de limigo. Kaj tio estas tiel. Mi reiros al la aparaton nun; ni faru cxion en la aparaton. Rigardante nian sekcion de demandoj, komence, kiel mi diris en mia retpoŝto, ni devas paroli pri la mallonga vi supozis vidi. Ni havas la redireccionando & Pipes kaj ĉi tiuj tri demandoj. Al kiu rivereto do funkcioj kiel printf skribi defaŭlte? Do rivereto. Kio estas torento? Al torento estas esence same kiel ĝi estas nur iuj - Ne eĉ fonto de 1s kaj _0s_. La rojo ĝi estas petante tie estas normo eksteren. Kaj tiel normo ekster estas rivereto, ke kiam vi skribas al li, aperas sur la ekrano. Normo ekster, per rivereto, ĝi signifas ke vi ĝuste skribas 1s kaj _0s_ al ĝi, kaj la alia fino de normo ekster nur legas de tiu fluo. Estas nur ĉeno de 1s kaj _0s_. Vi povas skribi al la rojoj aŭ vi povas legi de fluoj depende kion la rivereto reale estas. La aliaj du defaŭlta rojoj estas normo en kaj norma eraro. Normo en estas kiam ajn vi GetString, ĝi estas atendas vin al eniro stuff. Do atendas vin, ĝi estas vere atendas sur norma en, kiu estas vere kion vi akiras, kiam vi tajpas en la klavaro. Vi tajpas en normo in Norma eraro estas esence ekvivalenta al normo ekster, sed estas specialigita en tiu kiam vi presi al norma eraro, vi supozas nur presi erarmesaĝojn al tiu tiel vi povas diferenci inter regula mesaĝojn presita al la ekrano kontre erarmesaĝojn depende cxu ili iris al la normo ekster aŭ norma eraro. Dosieroj tro. Normo ekster, normo, kaj norma eraro estas nur speciala torentojn sed vere neniu dosiero, kiam vi malfermos dosieron, ĝi fariĝas la kurento de bajtoj kie vi povas simple legis de tiu fluo. Vi, plejparte, povas nur pensi pri dosieron kiel fluo da bitokoj. Do kio riveretoj do ili skribas al defaŭlte? Norma eksteren. Kio estas la diferenco inter> kaj >>? Ĉu iu rigardi la video antauxe? Okay. > Tuj estos kiel vi ridirektanta en dosieroj, kaj >> ankaŭ tuj alidirektilo eligo en dosieroj, sed ĝi estas anstataŭ tuj aldonas al la arkivo. Ekzemple, ni diras, ke mi hazarde havas dict ĉi tie, kaj la sola aĵo ene de dict estas kato, kato, hundo, fiŝoj, hundo. Unu ordonon, kiun vi havas al la komanda linio estas kato, kio estas ĝuste tuj presi kio estas en dosiero. Do kiam mi diras kato dict, ĝi tuj presi kato, kato, hundo, fiŝoj, hundo. Tio estas ĉio kato faras. Tio signifas ke ĝi presis al normo ekster kato, kato, hundo, fiŝoj, hundo. Se mi anstataŭ volas redirekti ke al dosiero, mi povas uzi> kaj redirekti ĝin al kiom la dosiero estas. Mi vokos la dosiero dosiero. Do nun, se mi ls, mi vidos mi havas novan dosieron nomatan dosiero. Kaj se mi malfermos gxin, li tuj devos precize kion kato metis al la komanda linio. Do nun, se mi faras tion denove, tiam tuj alidirektilo la eligo en dosiero, kaj mi tuj havi la sama ĝusta afero. Do teknike, ĝi tute overrode kion ni havis. Kaj ni vidos ĉu mi ŝanĝu dict, mi prenis el hundo. Nun se ni kato dict en dosiero denove, ni havos la novan version kun hundo forigitaj. Do tute overrides ĝin. Anstataŭe, se ni uzas >>, ĝi tuj aldonas dosieron. Nun, malfermante dosieron, ni vidas ni havas nur la sama afero presita dufoje ĉar estis tie unufoje, tiam ni aldonis al la originala. Do, tio estas kion> kaj >> fari. Ĉu la sekva demandi - Ne demandu pri tio. La alia kiu ni havas estas <, kiu se> alidirektiloj normo ekster, vi faras 2>, ke tio redireccionando norma eraro. Do se iu iris al norma eraro, ĝi ne get metita en txt2. Sed rimarki se mi faras 2>, tiam ĝi estas ankoraŭ presi Saluton, Rob! al la komanda linio ĉar mi nur redireccionando norma eraro, mi ne redireccionando normo eksteren. Norma eraro kaj normo ekster estas malsamaj. Se vi volas vere skribos al norma eraro, tiam mi povus ŝanĝi ĉi tion al esti fprintf al stderr. Do printf, implicite, presas al normo eksteren. Se mi volas presi al cxeferarigo permane, poste mi devas uzi fprintf kaj precizigi kion mi volas presi al. Se anstataŭe mi faris fprintf stdout, tiam tio estas esence ekvivalenta al printf. Sed fprintf al norma eraro. Do nun, se mi alidirektilo ĉi tiu enen txt2, Saluton, Rob! ankoraŭ getting presita en la komanda linio ekde ĝi estas getting presita al norma eraro kaj mi nur redireccionando normo eksteren. Se mi nun alidirektilo norma eraro, nun ĝi ne get presita, kaj txt2 tuj estos Saluton, Rob! Do nun, vi povas presi viajn reala erarojn al norma eraro kaj presi viajn regulajn mesaĝojn al normo eksteren. Kaj tiel, kiam vi kuris, via programo, oni povas ruli ĝin kiel. / Saluton ĉi tiu tipo kun la 2> por ke via programo tuj kuri kutime, sed neniu erarmesaĝojn kiuj vi akiras vi povas kontroli poste en via eraro log, tiel eraroj, kaj tiam rigardi poste kaj viajn erarojn dosieron havos neniun eraroj kiu okazis. Demandoj? La lasta estas pipo, kiun vi povas pensi pri kiel preni la normo ekster de unu komando kaj tial estas la normo en la venonta ordono. Ekzemplo tie eĥo estas komandlinio afero kiu estas ĝuste tuj eĥon ajn mi metis kiel ĝia argumento. Mi ne mortigos citaĵoj. Eĥo bla, bla, bla estas ĝuste tuj presi bla, bla, bla. Antaŭe, kiam mi diris ke mi devis meti Rob en txt-dosiero ĉar mi povas nur alidirektilo txt-dosieroj, anstataŭ, / se mi eĥon Rob kaj tiam pipon ĝin en. / saluton, ke ankaŭ faros la sama tipo de afero. Ĉi prenas la eligo de ĉi komando, eĥo Rob, kaj uzante ĝin kiel la enigo por. / saluton. Vi povas pensi pri tio kiel unua alidirektilo eĥo Rob en dosieron kaj poste enigo enen. / saluton tiu dosiero kiu estis ĝuste outputted. Sed ĝi prenas la provizora dosiero el la bildoj. Demandojn sur tio? La sekva demando tuj engaĝi ĉi. Kio dukton povus vi uzas por trovi la nombro de unikaj nomoj en dosiero nomata names.txt? La komandoj nin tuj volas uzi ĉi tie estas solaj, do uniq, kaj tiam wc. Vi povas fari viro uniq al reale rigardu kion tiu faras, kaj ĝi estas nur tuj filtri apuda matching linioj de la enigo. Kaj viro wc tuj presi la linion, vorto, kaj bajto grafoj por ĉiu dosiero. Kaj la lasta nin tuj volas uzi estas varo, kiu iras al nur ordigi liniojn de txt-dosiero. Se mi faras iujn txt-dosiero, names.txt, kaj ĝi estas Rob, Tommy, Jozef, Tommy, Jozef, RJ, Rob, kion mi volas fari tie estas trovi la nombron de solaj nomoj en ĉi tiu dosiero. Do kion devus esti la respondo? >> [Studento] 4. >> Jes. Ĝi devus esti 4 ekde Rob, Tommy, Jozef, RJ estas la sola unika nomoj en ĉi tiu dosiero. La unua paŝo, se mi nur faru vorto havas names.txt, ĉi tiu estas efektive diri ĉion al mi. Tiu estas fakte impreso - Ni vidos, viro wc - newlines, vortoj, kaj bajto grafo. Se mi nur zorgas pri linioj, tiam mi povas nur fari wc-l names.txt. Do jen paŝo 1. Sed mi ne volas wc-l names.txt ĉar names.txt nur enhavas ĉiujn nomojn, kaj mi volas filtri ajna ne-solaj. Do, se mi faras uniq names.txt, kiu ne sufiĉe doni al mi kion mi volas ĉar la duobligitaj nomoj estas ankoraŭ tie. Kial estas tio? Kial uniq ne faras tion, kion mi volas? [Studento] La duobligas ne [inaudible] >> Jes. Memoru la viro paĝo uniq diras filtrilon apuda kongruanta linioj. Ili ne estas apuda, do tute ne filtri ilin. Se mi ordigi ilin unue, varo names.txt tuj metis ĉiujn duplikatajn linioj kune. Do nun speco names.txt estas tio. Mi tuj volas uzi tiun kiel la enigo al uniq, kiu estas | uniq. Tio donas al mi Jozef, RJ, Rob, Tommy, kaj mi volas uzi tiun kiel la enigo al wc-l, kiu tuj donos al mi 4. Kiel diras ĉi tie, kion dukton povus vi uzas? Vi povas fari multon kiel uzi serion da ordonoj kie oni uzas la eligo de unu komandon kiel la enigo al la sekvanta komando. Vi povas fari multon, ĝi tre lerte aĵojn. Demandoj? Okay. Estas tio por pipoj kaj redirección. Nun ni iru al la efektiva materialo, la kodigo stuff. Ene de ĉi PDF, vi vidos ĉi komando, kaj vi volas kuri ĉi komando en via aparaton. wget estas la komando por nur nun io el la interreto, esence, tiel wget kaj ĉi URL. Se vi iris al tiu retadreso en via retumilo, estus elŝuti tiu dosiero. Mi nur klakis sur ĝi, do ĝi elŝutis la dosieron por mi. Sed skribi wget de tiu afero ene de la fina Estas ĝuste tuj elŝuti ĝin en vian terminalo. Mi havas section5.zip, kaj vi volas descomprimir section5.zip, kiu tuj donos al vi dosierujo nomita section5, kiu iras al havi ĉiujn dosierojn nin tuj uzos hodiaŭ ene de ĝi. Kiel tiuj programoj 'dosiero nomoj sugestas, ili estas iom kalesxo, tial Via misio estas ekkompreni kial uzante gdb. Ĉu ĉiuj jam ili malŝarĝis / scias kiel akiri ilin elŝutebla en ilian aparaton? Okay. Kurante ./buggy1, ĝi diros Segmentación kulpo (kerno verŝis), kion ajn vi ricevas segfault, estas malbona. Sub kiaj cirkonstancoj vi ricevas segfault? [Studento] Dereferencing nula puntero. >> Jes. Do kiu estas unu ekzemplo. Dereferencing nula puntero vi tuj ricevas segfault. Kia segfault signifas ke vi tuŝis memoro vi ne devas esti tuŝi. Do dereferencing nula puntero tuŝas adreso 0, kaj esence, ĉiuj komputiloj nuntempe diri ke adreso 0 estas memoro vi ne devas esti tuŝi. Por ke tio dereferencing nula puntero rezultoj en segfault. Kiam vi hazarde ne pravalorizi puntero, tiam ĝi havas rubo valoro, kaj do kiam vi provas dereference ĝin, en ĉiu verŝajneco vi tuŝi memoro jen en la mezo de nenie. Se vi hazarde preni bonŝanca kaj la rubo valoro okazis al punkto ie en la pilo aŭ ion, tiam, kiam vi dereference ke puntero kiujn vi ne inicializada, nenio iros malbone. Sed se ĝi estas indikante, diru, ie inter la pilo kaj la amaso, aŭ ĝi estas montrante nur por ie, ke ne estis uzata de via programo ankoraux, tiam vi tuŝi memoro vi ne devas esti kortuŝa kaj vi segfault. Kiam vi skribas rekursia funkcio kaj ĝi recurses tro da fojoj kaj via pilo kreskas tro grandaj kaj la pilo karambolas en aĵoj por ke gxi ne estu karamboli kun, vi tuŝis memoro vi ne devas esti tuŝi, tiel vi segfault. Tio estas kion segfault estas. Estas ankaŭ la sama kialo ke se vi havas ĉenon kiel - ni reiru al la antaŭa programo. En hello.c--I'm just tuj faros ion alian. char * s = "Saluton mondo!"; Se mi uzas * s = io aŭ s [0] = 'X'; tiel faru saluton,. / saluton, kial tiu segfault? Kial ĉi segfault? Kion vi atendas pasas? Se mi faris printf ("% s \ n", s); kion vi atendus esti presita? [Studento] X saluton. >> Jes. La problemo estas, ke kiam vi deklaras ĉenon kiel ĉi tiu, s estas puntero ke tuj iros sur la pilo, kaj kion s indikante estas ĉi ŝnuro kiu estas enhavita en nurlega memoro. Do nur la nomo, nurlega memoro, vi devus ricevi la ideo ke se vi provas ŝanĝi kio estas en nurlega memoro, vi faras ion vi ne faros kun memoro kaj vi segfault. Tio estas vere granda diferenco inter char * s kaj char s []. Do char s [], nun ĉi ŝnuroj tuj estos metita sur la pilo, kaj la pilo estas ne legis nur, kio signifas ke ĉi tiu devus funkcii perfekte bela. Kaj ĝi faras. Memoru ke kiam mi faras char * s = "Saluton mondo!", S mem estas sur la stako sed s poentojn al alie, kaj ke ie ajn hazarde estas nurlega. Sed char s [] estas nur iun sur la stako. Do jen alia ekzemplo de segfault okazas. Ni vidis, ke ./buggy1 rezultis en segfault. En teorio, vi devus ne rigardi buggy1.c tuj. Anstataŭ, ni rigardos ĝin tra gdb. Rimarku, ke kiam vi ricevas Segmentación kulpo (kerno verŝis), vi ricevas tiun dosieron super tie nomas kerno. Se ni ls-l, ni vidos, ke kerno estas kutime sufiĉe granda dosiero. Tio estas la nombro de bitokoj de la dosiero, do ĝi aspektas kiel ĝi estas 250-io kilobajtoj. La kialo estas ke kion la kerno dump efektive estas estas kiam via programo frakasas, la stato de memoro de via programo nur gets kopiitaj kaj pasted en ĉi tiun dosieron. Ĝi prenas verŝis en tiun dosieron. Ĉi tiu programo, dum ĝi ruliĝas, okazis havi memoron uzado de ĉirkaŭ 250 kilobajtoj, kaj tiel tion got verŝis en ĉi tiun dosieron. Nun vi povas rigardi en tiu dosiero, se ni faras gdb buggy1 kerno. Ni povas nur fari gdb buggy1, kaj kiu nur funkciigas gdb regule, uzante buggy1 kiel ĝia enigo dosiero. Sed se vi faras gdb buggy1 kerno, tiam ĝi estas specife tuj funkciigas gdb per rigardas tiun kernon dosiero. Kaj vi diras buggy1 per gdb scias ke tiu kerno dosiero devenas la buggy1 programo. Do gdb buggy1 kerno tuj tuj venigi nin al kie la programo okazis al finiĝi. Ni vidas tie Programo finita kun signalo 11, Segmentación kulpo. Ni okazi vidi linion de muntado, kiu probable ne estas tre helpema. Sed se vi tajpas bt aŭ retrospuro, ke tuj estos la funkcio kiu donas al ni la listo de niaj aktualaj pilo kadroj. Do retrospuro. Ĝi aspektas kiel ni nur havas du pilo kadroj. La unua estas nia ĉefa pilo kadro, kaj la dua estas la pilo framo por tiu funkcio kiu ni hazarde estas en, kiu aspektas kiel ni nur havas la asembleo kodo por. Do ni iru returne en nia ĉefa funkcio, kaj por fari tion ni povos fari kadro 1, kaj mi kredas ke ni povas ankaŭ fari sube, sed mi preskaŭ neniam faras malsupren - aŭ supren. Yeah. Supren kaj malsupren. Supren alportas vin unu pilo kadro, malsupren alportas vin pilo kadro. Mi emas neniam uzi tiun. Mi nur diras specife kadro 1, kiu estas iri al la framo etikeditaj 1. Kadro 1 tuj venigos nin en ĉefa pilo kadro, kaj ĝi diras ĉi tie la linio de kodo oni hazarde estas en. Se ni volis paron pli linioj de kodo, ni povas diri listo, kaj ke tuj doni al ni ĉiuj linioj de kodo ĉirkaŭ ĝi. La linio ni segfaulted ĉe estis 6: if (strcmp ("CS50 rokoj", argv [1]) == 0). Se ĝi ne estas evidenta tamen, vi povas akiri ĝin rekte de ĉi tie nur pensante kial segfaulted. Sed ni povas porti ĝin unu paŝon kaj diris, "Kial argv [1] segfault?" Estu la impreso argv [1], kaj ĝi similas ke estas 0x0, kiu estas la nula puntero. Ni strcmping CS50 rokoj kaj nula, kaj por ke tuj segfault. Kaj kial argv [1] nula? [Studento] Ĉar ni ne donis ĝin ajna komand-linio argumentoj. Yeah. Ni ne donos ĝin ajna komand-linio argumentoj. Do ./buggy1 nur havos argv [0] esti ./buggy1. Oni ne tuj havas argv [1], por ke tuj segfault. Sed se, anstataŭe, mi faras ĝuste CS50, ĝi tuj diros Vi ricevas D ĉar tio kio ĝi estas supozita fari. Rigardante buggy1.c, ĝi estas supozitaj presi "Vi ricevos D" - Se argv [1] estas ne "CS50 rokoj", "Vi ricevas D", alie "Vi ricevas A!" Do, se ni volas A, ni bezonas tiun kompari kiel vera, kio signifas ke ĝi komparas al 0. Do argv [1] bezonas esti "CS50 rokoj". Se vi volas fari tion en la komandlinio, vi devas uzi \ eskapi la spaco. Do CS50 \ rokoj kaj Vi ricevas A! Se vi ne faras la backslash, kial tio ne funkcias? [Studento] Estas du malsamaj argumentoj. >> Jes. Argv [1] tuj estos CS50, kaj argv [2] tuj estos rokoj. Okay. Nun ./buggy2 tuj segfault denove. Anstataŭ malfermi ĝin per sia kerno dosiero, ni simple malfermi buggy2 rekte, tiel gdb buggy2. Nun se ni nur kuri nia programo, tiam ĝi tuj diri Programo ricevita signalo SIGSEGV, kiu estas la segfault signalon, kaj ĉi tiu estas kie okazis okazos. Rigardante nian retrospuro, ni vidas ke ni estis en la funkcio oh_no, kiu estis nomita de la funkcio Dinky, kiu estis nomita de la funkcio binky, kiu estis nomita de main. Ni povas vidi ankaŭ la argumentojn al tiuj funkcioj. La argumento por Dinky kaj binky estis 1. Se ni listigi la funkcio oh_no, ni vidas ke oh_no estas nur faras char ** s = NULL; * S = "BOOM"; Kial tio malsukcesos? [Studento] Vi ne povas dereference la nula puntero? >> Jes. Tiu estas nur diras s estas NULL, sendepende se tio okazas esti char **, kiu, dependante de kiom vi interpretas ĝin, povus esti puntero al puntero al ĉeno aŭ tabelo de kordoj. Estas s estas NULL, do * s dereferencing nula pointer, kaj tiel ĉi tiu tuj frakasi. Tiu estas unu el la plej rapidaj manieroj vi povas eble segfault. Ĝi simple deklari nulaj puntero kaj tuj segfaulting. Tion oh_no faras. Se ni iru unu kadro, tiam ni tuj eniri la funkcio kiu nomis oh_no. Mi bezonas fari tion sube. Se vi ne enigi komandon kaj vi ĵus batis Entajpu denove, ĝi simple ripeti la antaŭajn komandon kiun vi kuris. Ni estas en kadro 1. Printante ĉi tiu kadro, ni vidas tie estas nia funkcio. Vi povas batis listo denove, aŭ vi povas fari listo 20 kaj ĝi estos listigi pli. La funkcio Dinky diras se i estas 1, tiam iru al la oh_no funkcio, alie iru al la Slinky funkcio. Kaj ni scias i estas 1, ĉar ni okazos vidi ĉi tien ke Dinky nomis per la argumento 1. Aŭ vi povas simple presi i kaj ĝi diros i estas 1. Ni estas aktuale en Dinky, kaj se ni iru alia kadro, ni scias ke ni finas en binky. Ĝis. Nun ni estas en binky. Printante ĉi funkcio - la listo de antaŭ duono frakasus min - dividis kvazaŭ mi estas 0, tiam ni tuj nomas ĝin oh_no, alie nomas Dinky. Ni scias mi estis 1, do nomis Dinky. Kaj nun ni estas denove en ĉefa, kaj ĉefa estas ĝuste tuj estos int i = rand ()% 3; Tio estas ĝuste tuj donos al vi hazarda numero kiu estas ĉu 0, 1, aŭ 2. Ĝi okazas nomi binky kun tiu nombro, kaj ĝi revenos 0. Rigardante tion, nur promeni tra la programo permane sen kuri ĝin tuj, vi starigis ripozon punkto je ĉefa, kio signifas ke kiam ni kuras la programo via programo kuras supren ĝis batas ripozon punkto. Do kurante la programo, ĝi kuros kaj tiam ĝi atingos la ĉefa funkcio kaj ĉesi kuri. Nun ni estas ene de ĉefa, kaj paŝo aŭ apud tuj venigi nin al la sekvanta linio de kodo. Vi povas fari paŝon aŭ apud. Bati proksima, nun i estas kreita por rand ()% 3, do ni povas presi la valoro de i, kaj ĝi diros i estas 1. Nun gravas ĉu ni uzas sekva aŭ paŝo. Mi supozas ke gravis en la antaŭa, sed ni volus uzi poste. Se ni uzas paŝo, ni tretas en la funkcio, kio signifas rigardi la reala afero ke okazas ene de binky. Se ni uzas sekva, do tio signifas iri trans la funkcio kaj ĝuste iri al la sekvanta linio de kodo en nia ĉefa funkcio. Ĝuste sur tiu linio, mi estis ĉe kie diris rand ()% 3; se mi faris paŝon, ĝi iros en la efektivigo de rand kaj rigardu kio okazas tie, kaj mi povus treti tra la rand funkcio. Sed mi ne zorgas pri la rand funkcio. Mi nur volas iri al la sekvanta linio de kodo en ĉefa, do mi uzas alia. Sed nun mi faras zorgon pri la binky funkcio, do mi volas treti sur tio. Nun mi estas en binky. La unua linio de kodo estas dironta if (i == 0), Mi prenas unu paŝon, ni vidas ni finos je Dinky. Se ni Listo aĵoj, ni vidas ke ĝi kontrolis estas mi = 0. i estas ne egala al 0, do iris al la alia kondiĉo, kiu iras nomi Dinky (i). Vi povus preni konfuzita. Se vi ĵus rigardi tiujn liniojn rekte, eble vi pensus se (i == 0), bone, tiam mi prenis unu paŝon kaj nun mi estas ĉe Dinky (i), vi eble pensas ke devas signifi i = 0 aŭ io. Ne, tio nur signifas ke ĝi scias povas bati rekte al la linio Dinky (i). Ĉar mi estas ne 0, la sekva paŝo ne tuj enfluos en la alia. Else ne estas linio tuj halti en. Ĝi simple tuj iros al la sekvanta linio povas fakte ekzekuti, kiu estas Dinky (i). Tretante en Dinky (i), ni vidu se (i == 1). Ni scias mi = 1, do kiam ni tretas, ni scias ke ni tuj finos en oh_no ĉar mi = 1 nomas la funkcion oh_no, kiun vi povas treti en, kiu iras al starigis char ** s = al nulaj kaj tuj "BOOM". Kaj tiam vere rigardi la efektivigo de buggy2, ĉi tio, mi estas nur nun hazarda nombro - 0, 1, aŭ 2 - voko binky, kion se i estas 0 flamo oh_no, alie li nomas Dinky, kiu venas ĉi tien. Se i estas 1, nomita oh_no, alie nomas Slinky, kiu venas tien, se i estas 2, nomita oh_no. Mi eĉ ne kredas ke estas maniero - Ĉu iu vidas manieron de fari tiun programon kiu ne segfault? Ĉar se mi mankas io, se i estas 0, vi tuj segfault, alie vi iras al funkcio kiu se i estas 1 vi segfault, alie vi iros al funkcio kie se i estas 2 vi segfault. Do ne gravas kion vi faras, vi segfault. Mi supozas unidirekta de fiksi estus anstataŭ fari char ** s = NULL, vi povus malloc spaco por ke kordoj. Ni povus fari malloc (sizeof) - sizeof kio? [Studento] (char) * 5? >> Ĉu ĉi ŝajnas ne? Mi supozas ĉi funkcios se mi efektive kuris, sed ĝi ne estas kion mi serĉas. Rigardu la tipo de s. Ni aldonu int *, do int * x. Mi farus malloc (sizeof (int)). Aŭ se mi volis tabelo de 5, mi farus (sizeof (int) * 5); Kio se mi havas int **? Kion farus mi malloc? [Studento] Grandeco de la puntero. >> Jes. (Sizeof (int *)); Sama afero cxi tie. Mi volas (sizeof (char *)); Tiu tuj destini spaco por la puntero kiu notas al "BOOM". Mi ne bezonas destini spaco por "BOOM" mem ĉar ĉi tiu estas esence ekvivalenta al kion mi diris antaŭe char * x = "BOOM". "BOOM" jam ekzistas. Ĝi okazas ekzisti en la nurlega regiono de memoro. Sed jam ekzistas, kio signifas ĉi tiu linio de kodo, se s estas char **, tiam * s estas char * kaj vi opcio ĉi char * atentigi al "BOOM". Se mi volis kopii "BOOM" en s, tiam mi bezonus destini spaco por s. Mi tion faros * s = malloc (sizeof (char) * 5); Kial 5? Kial ne 4? Ĝi aspektas kiel "BOOM" estas 4 signoj. >> [Studento] La nula karaktero. Yeah. Ĉiuj viaj kordoj tuj bezonas la nula karaktero. Nun mi povas fari ion kiel strcat - Kio estas la funkcio por kopiado ĉeno? [Studento] cpy? >> Strcpy. viro strcpy. Do strcpy aŭ strncpy. strncpy estas iom pli sekura ĉar vi povas specifi ĝuste kiom da karakteroj, sed tie ne gravas ĉar ni scias. Do strcpy kaj rigardu en la argumentoj. La unua argumento estas nia destino. La dua argumento estas nia fonto. Ni tuj kopii en nian destinon * s la puntero "BOOM". Kial povus vi volas fari ĉi tion kun strcpy anstataŭ ĝuste kion ni havis antaŭ de * s = "BOOM"? Estas kialo vi volus fari tion, sed kio estas tio? [Studento] Se vi volas ŝanĝi ion en "BOOM". >> Jes. Nun mi povas fari ion kiel s [0] = 'X'; ĉar s poentojn al la amaso kaj tiu spaco sur la havaĵon kiun s montrante Estas puntero al pli spaco sur la havaĵon, kiu estas stoki "BOOM". Do ĉi tiu kopio de "BOOM" estas stokita en la havaĵo. Estas teknike du kopioj de "BOOM" en nia programo. Estas la unua ke tio simple donita per ĉi tiu "BOOM" string konstanto, kaj la dua ekzemplero de "BOOM", strcpy kreis la kopion de "BOOM". Sed la kopion de "BOOM" estas stokita en la amaso, kaj la amaso vi estas libera ŝanĝi. La amaso ne legis nur tiel, ke signifas, ke s [0] tuj lasu vin ŝanĝi la valoron de "BOOM". Ĝi okazas, por ke vi ŝanĝu la gravuloj. Demandoj? Okay. Pasi al buggy3, estu la gdb buggy3. Ni nur ruli ĝin kaj ni vidas ni preni segfault. Se ni retrospuro, estas nur du funkcioj. Se ni iras supren en nia ĉefa funkcio, ni vidas ke ni segfaulted ĉe ĉi tiu linio. Do ĵus rigardis tiun linion, por (_int_ linio = 0; fgets ĉi aĵoj ne egala NULL; linio + +). Nia antaŭa framo nomis _IO_fgets. Vi vidos ke tre kun enkonstruita en C funkcioj, ke kiam vi akiras la segfault, estos vere críptico funkcio nomoj kiel tiu _IO_fgets. Sed tio okazas rilatigi al ĉi fgets alvokon. Ie ene tie, ni segfaulting. Se ni rigardas la argumentoj por fgets, ni povas presi buffer. Ni presas kiel - Ho, ne. Print ne tuj funkcias precize kiel mi volas ĝin. Ni rigardu la reala programo. Buffer estas gravulo tabelo. Estas karaktero tabelo de 128 signoj. Do kiam mi diras print buffer, ĝi tuj presi tiujn 128 signoj, kion mi supozas estas kio atendas. Kion mi serĉis estas presi la adreson de bufro, sed tio ne vere diras al mi multe. Do kiam mi okazi diri tien x buffer, ĝi montras al mi 0xbffff090, kiu, se vi memoras de antaŭaj aŭ iu punkto, Oxbffff emas esti pilo-ish regiono. La pilo inklinas komenci ie ĝuste sub 0xc000. Nur vidante tiu adreso, mi scias ke buffer okazas sur la stako. Restartigi mian programon, kuri, ĝis, buffer ni vidis, estis tiu vico de signoj ke estas sufiĉe da sensignifaj. Tiam presi dosiero, kion signifas dosiero aspektas? [Studento] Nula. >> Jes. Dosiero estas de tipo DOSIERO *, do ĝi estas puntero, kaj la valoro de tiu puntero estas nula. Do fgets tuj provos legi de tiu puntero en nerekta vojo, sed por aliri ke pointer, ĝi devas dereference ĝin. Aŭ, por konsenti kio devus esti indikante, ĝi dereferences ĝin. Do ĝi estas dereferencing nula puntero kaj segfaults. Mi povus esti rekomencita ŝin tie. Se ni dispecigas ĉe nia ĉefa punkto kaj kuri, la unua linio de kodo estas char * dosiernomo = "nonexistent.txt"; Tio devus doni sufiĉe granda aludo pri kial ĉi programo malsukcesas. Tajpi sekva alportas mi al la sekva linio, kie mi malfermu tiun dosieron, kaj tiam mi tuj eniri nian linion, kie iam mi batis proksima, ĝi tuj segfault. Ĉu iu volas elĵetas tial ni povus segfaulting? [Studento] Dosiero ne ekzistas. >> Jes. Tiu estas supozata esti aludo ke kiam ajn vi malfermas dosieron vi bezonas kontroli, ke la dosiero reale ekzistas. Do jen, "nonexistent.txt"; Kiam ni fopen dosiernomo por legi, ni tiam devas eldiri if (dosiero == NULL) kaj diru printf ("Dosiero ne ekzistas!" aŭ - pli bone tamen - dosiernomo); reveno 1; Do nun ni kontrolu por vidi se ĝi estas NULL antaux vere daŭrigi kaj provante legi de tiu dosiero. Ni povas refari ĝin nur por vidi ke tiu verkoj. Mi intencis inkluzivi nova linio. Do nun nonexistent.txt ne ekzistas. Vi devus ĉiam kontroli por ĉi tiaj aferoj. Vi devus ĉiam kontroli por vidi se fopen revenas NULL. Vi devus ĉiam kontroli por certiĝi ke malloc ne revenas NULL, alie vi segfault. Nun buggy4.c. Kurante. Mi konjektas ĉi atendas enigo aŭ eble malfinio looping. Jes, estas malfinio looping. Do buggy4. Ĝi aspektas kiel ni estas senfinaj looping. Ni povas rompi en ĉefa, kuri nia programo. En gdb, tiel longe kiel la mallongigo vi uzas estas unusenca aŭ speciala mallongigoj kiuj ili havigas al vi, tiam vi povas uzi n uzi sekva anstataŭ devi tajpi ekster sekva la tuta vojo. Kaj nun kiam mi batis n fojon, mi povas nur bati Entajpu teni nun iros anstataŭ havi bati n Enter, n Enter, n Enigu. Ĝi aspektas kiel mi estas en ia por buklo ke tio opcio tabelo [i] al 0. Ĝi aspektas kiel mi neniam rompas el ĉi por buklo. Se mi presi i, do i estas 2, tiam mi iros proksima. Mi presi i, i estas 3, tiam mi iros proksima. Mi presi i kaj i estas 3. Tuj poste, presi i, i estas 4. Vere, presita sizeof (areo), do grandeco de tabelo estas 20. Sed ĝi aspektas kiel ekzistas iuj specialaj gdb komandon por iri ĝis io okazos. Estas kiel opcio kondiĉo sur la valoro de la variablo. Sed mi ne memoras kio ĝi estas. Do, se ni plenumas tuj - Kion vi diras? Kion vi alkondukis? [Studento] Does montri i aldoni - >> Jes. Do montri i povas helpi. Se ni nur montros i, ĝi metos ĉi tien kion la valoro de i estas do mi ne devas presi ĝin ĉiufoje. Se ni simple observu tuj poste, ni vidas 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5. Io tuj terure erara, kaj i estas reset al 0. Rigardante buggy4.c, ni vidas ĉion, kion okazas estas int tabelo [5]; por (i = 0; i <= sizeof (areo); i + +) tabelo [i] = 0; Kion ni vidas ke estas malĝusta ĉi tie? Kiel aludo, kiam mi estis faranta la gdb buggy4 - ni rompos ĉefa, run - Mi ne print sizeof (areo) nur por vidi kion la kondiĉo estas kie mi fine rompi. Kie mi estas? Ĉu mi kuri? Mi ne deklaris ankoraŭ. Do presi sizeof (areo) kaj tio estas 20, kiu atendas de post mia tabelo estas de amplekso 5 kaj ĝi estas de 5 entjeroj, do la tuta afero estu 5 * sizeof (int) bajtoj, kie sizeof (int) emas esti 4. Do sizeof (tabelo) estas 20. Kion tio povas farigxi? [Studento] Dividitaj de sizeof (int). >> Jes, / sizeof (int). Ĝi aspektas kiel ekzistas ankoraŭ problemo tie. Mi kredas ke tiu devus esti nur < pro tio ke ĝi estas sufiĉe multe ĉiam > [Bowden] Jes. Kiam ni iras preter la fino de nia tabelo, iel tiu spaco kiu ni supera estas supera al la valoro de i. Kaj do se ni rigardas buggy4, rompi ĉefa, kuri, ni presi la adreso de i. Ĝi aspektas kiel ĝi estas bffff124. Nun ni presas la adreson de tabelo [0]. 110. Kio pri [1]? 114. [2], 118. 11C, 120. tabelo [5] estas bfff124. Do tabelo [5] havas la sama adreso kiel i, kio signifas ke tabelo [5] estas mi. Se ili havas la sama adreso, ili estas la sama afero. Do kiam ni aro tabelo [5] al 0, ni opcio i al 0. Kaj se vi pensas pri ĉi en terminoj de la pilo, int i estas deklarita unue, kion signifas i ricevas iujn spaco sur la stako. Tiam tabelo [5] estas atribuitaj, do tiam 20 bitokoj estas disponigataj sur la stako. Do mi prenas asignitaj unua, tiam tiuj 20 bitokoj get asignotaj. Do i okazas ĝuste antaŭ la tabelo, kaj pro la maniero, kiel mi diris pasintsemajne, kie teknike la pilo kreskas malsupren, kiam vi indekson en tabelo, ni garantias ke la 0th pozicio en la tabelo ĉiam okazas antaŭ la unua pozicio en la tabelo. Tio estas speco de kiel mi tiris ĝin pasintsemajne. Rimarku ke en la fundo ni havas adreson 0 kaj supre ni havas adreson Max. La stako estas ĉiam kreskanta sube. Supozu ke ni rezervu i. Ni rezervu entjero mi, kion signifas let la just say tien entjero mi gets asignotaj. Tiam ni destini nia tabelo de 5 entjeroj, kio signifas, ke sub tiu, ekde la pilo kreskas malsupren, tiuj 5 entjeroj get asignotaj. Sed pro kio arrays labori, ni garantias ke la unua pozicio en la tabelo ĉiam havas adreson malpli ol la dua afero en la tabelo. Do tabelo pozicio 0 ĉiam devas okazi unue en memoro, dum tabelo pozicio 1 devas okazi poste kaj batalarangxis pozicio 2 devas okazi post tio, kio signifas, ke tabelo pozicio 0 okazus ie cxi tie, tabelo pozicio 1 okazus super ĉar movante supren signifas alta adresoj ekde la maksimuma adreso estas ĉe tie. Do tabelo [0] cxi tie, tabelo [1] ĝis tie, tabelo [2] ĝis tie, tabelo [3] ĝis ĉi tie. Rimarku kiel ni antaŭe atribuis entjero mi la tuta vojo ĝis tie, kiel ni movos pli kaj pli en nia tabelo, ni pli kaj pli proksimajn al nia entjero mi. Simple tiel okazas ke tabelo [5], kiu estas unu pozicio preter nia tabelo, Estas ĝuste kie entjero mi pasis al asignotaj. Do tio estas la punkto kie oni hazarde esti bati la spaco en la stako kiu estis atribuitaj por entjero mi, kaj ni opcio ke al 0. Tiel estas kiel tiu funkcias. Demandoj? Yeah. [Studento] Ne gravas. Okay. [Studento] Kiel vi eviti tiujn speco de eraroj? Tiuj speco de eraroj? Ne uzu C kiel viaj programlingvo. Uzi lingvon kiu havas tabelo baroj checking. Tiel longe kiel vi estas zorga, vi nur bezonas eviti tuj preter la limojn de via tabelo. [Studento] Do jen kiam ni iris preter la limojn de via tabelo - [Bowden] Tie estas kie aĵoj komenci tuj malbone. >> [Studento] Ho, bone. Tiel longe kiel vi restu ene de la memoro destinis por via tabelo, vi estas bela. Sed C faras neniun eraron kontrolanta. Se mi faras tabelo [1000], ĝin volonte simple modifi ajn okazas - Ĝi iras al la komenco de la tabelo, tiam ĝi iras 1000 pozicioj post kaj starigos ĝin al 0. Ĝi ne faras neniun kontrolanta ke ho, tio ne vere havas 1000 aĵoj en ĝi. 1000 estas maniero tie kion mi devus ŝanĝi, dum Java aŭ io vi ricevos tabelo el baroj indekso aŭ indico el baroj escepto. Tial multaj pli alta nivelo lingvoj havas tion kie se vi iros preter la limojn de la tabelo, vi malsukcesos por ke vi ne povas ŝanĝi tion for sube vi kaj tiam aĵoj iras multe pli malbone ol nur nun escepton dirante, ke vi iris preter la fino de la tabelo. [Studento] Kaj tiel ni ĵus ŝanĝis la <= al nur > [Bowden] Yeah. Ĝi devus esti > [Studento] Ĝuste. Pli demandoj? Okay. [Studento] Mi havas demandon. >> Jes. [Studento] Kio estas la fakta tabelo variablo? [Bowden] Kiel kio estas tabelo? Array mem estas simbolo. Ĝi estas nur la adreson de la komenco de la 20 bitokoj ke ni referenco. Vi povas pensi pri tio kiel puntero, sed estas konstanta puntero. Apenaŭ tion get kompilitaj, la variablo tabelo ne plu ekzistas. [Studento] Do kiel faras ĝi trovi la grandecon de tabelo? Grandeco de tabelo rilatas al la grandeco de tiu bloko, ke tiu simbolo referencas al. Kiam mi faras ion kiel printf ("% p \ n" msgstr); ni ruli ĝin. Kion mi simple faras maljustecon? Array 'tabelo' deklaris tie. Ho, ĉe tie. Clang estas inteligenta, kaj okazas rimarki ke mi deklaris la tabelo kiel 5 elementoj sed mi indeksado en pozicio 1000. Ĝi povas fari tion ĉar tiuj estas nur konstantoj. Ĝi povas nur iri ĝis nun en rimarkante, ke mi tuj preter la limojn de la tabelo. Sed rimarki antaŭe kiam ni havis mi esti malĝusta, ĝi do ne povas determini kiom da valoroj i povus alpreni, tial ĝi ne povas determini kiu i tuj preter la fino de la tabelo. Tio estas nur Clang esti saĝa. Sed nun fari buggy4. Do kio alia mi faras malbone? Implice deklarante biblioteko funkcion 'printf'. Mi tuj volas # include . Okay. Nun kurante buggy4. Presi la valoro de la tabelo kiel Mi faris ĉi tie, presante ĝin kiel puntero impresoj iu kiu similas tiun - bfb8805c - kiu estas iu adreso jen en la stako-ish regiono. Array mem estas kiel puntero, sed ne estas reala pointer, ekde regula puntero ni povas ŝanĝi. Array estas nur iu konstanto. La 20 blokoj de memoro starti je adreso 0xbfb8805c. Do bfb8805c tra tiu adreso +20--aŭ mi supozas -20 - estas ĉiuj la memoro destinis por ĉi tabelo. Tabelo, la variablo mem ne stokas ie ajn. Kiam vi kompili, la tradukilo - mano ondo ĝin - sed la tradukilo simple uzi kie konas tabelo esti. Ĝi scias kie tiu tabelo komencas, kaj tiel ĝi povas ĉiam nur faru tion en terminoj de ofsetoj de tiu komenco. Ĝi ne bezonas variablo mem reprezenti tabelo. Sed kiam mi faras ion kiel int * p = array; nun p estas puntero kiu notas al tiu tabelo, kaj nun p fakte ne ekzistas sur la stako. Mi estas libera ŝanĝi p. Mi povas fari p = malloc. Do origine indikis tabelo; nun notas al iu spaco sur la monteto. Mi ne povas fari tabelo = malloc. Se Clang estas ruza, ĝi krias al mi ekde la komenco la batilo. Vere, mi estas bela certa gcc farus tiun ankaŭ. Do tabelo tipo 'int [5]' ne asignable. Vi ne povas atribui ion al tabelo tipo ĉar tabelo estas nur konstanta. Ĝi estas simbolo kiu referencoj tiuj 20 bajtoj. Mi ne povas ŝanĝi ĝin. [Studento] Kaj kie estas la grandeco de la tabelo stokita? [Bowden] Ne estas stokitaj ie ajn. Estas kiam ĝi estos kompili. Do kie estas la grandeco de tabelo stokita? Vi povas uzi nur sizeof (areo) ene de la funkcio, ke la tabelo estas deklarita mem. Do, se mi faras iujn funkcion, foo, kaj mi do (int tabelo []) printf ("% d \ n", sizeof (tabelo)); kaj tiam ĉi tie mi vokas foo (areo); ene de ĉi funkcio - ni ruli ĝin. Ĉi tiu estas Clang esti ruza denove. Oni diras al mi ke sizeof sur tabelo funkcio parametro revenos grandeco de 'int *'. Tiu estus eraro se ĝi ne estas kion mi volis okazos. Ni efektive elŝalti Werror. Averto. Avertoj estas fajna. Ĝi ankoraŭ kompili tiel longe, kiel ĝi havas averto. . / A.out tuj presi 4. La averto kiu generis estas klara indikilo de kio misfunkciis. Ĉi int tabelo estas ĝuste tuj presi sizeof (int *). Eĉ se mi metis tabelo [5] en tie, ĝi estas ankoraŭ apenaŭ tuj presi sizeof (int *). Tuj, kiam vi pasos ĝin en funkcio, la distingo inter tabeloj kaj punteros estas neekzistanta. Ĉi tio okazas al esti tabelo kiu deklaris en la pilo, sed tuj kiam ni pasos tiun valoron, kiun 0xbf bla, bla, bla en cxi tiun funkcion, tiam ĉi puntero notas al tiu tabelo sur la stako. Do tio signifas ke sizeof nur validas en la funkcio kiun la tabelo estis deklarita, kio signifas ke kiam vi kompili tiun funkcion, kiam Clang iras tra ĉi tiu funkcio, ĝi vidas tabelo estas int tabelo de amplekso 5. Tial vidu sizeof (areo). Nu, jen 20. Tio estas vere kiel sizeof esence laboras por preskaŭ ĉiuj kazoj. Sizeof estas ne funkcio; estas operatoro. Vi ne nomas la sizeof funkcio. Sizeof (int), la tradukilo ĝuste traduki ke 4. Got it? Okay. [Studento] Do kio estas la diferenco inter sizeof (areo) en ĉefaj kaj en foo? Ĉi tiu estas ĉar ni dirante sizeof (areo), kiu estas de tipo int *, dum la tabelo cxi tie ne estas de tipo int *, temas pri int tabelo. [Studento] Do, se vi havis la parametro en tabelo [] anstataŭ int * tabelo, deziras, ke signifas, ke vi ankoraŭ povis ŝanĝi tabelo ĉar nun ĝi estas puntero? [Bowden] Kiel tio? >> [Studento] Yeah. Ĉu vi povas ŝanĝi tabelo ene de la funkcio estas nun? [Bowden] Vi povus ŝanĝi tabelo en ambaŭ kazoj. En ambaŭ kazoj vi estas libera diri tabelo [4] = 0. [Studento] Sed cxu vi povas fari tabelo punkto al iu alia? [Bowden] Oh. Yeah. En ĉu kazo - >> [studento] Yeah. [Bowden] La distingo inter tabelo [] kaj int * tabelo, ekzistas neniu. Vi ankaŭ povas ricevi iun multdimensia tabelo ĉi tien por iu konvena sintakso, sed estas ankoraŭ nur puntero. Tio signifas ke mi estas libera fari tabelo = malloc (sizeof (int)), kaj nun notas aliloke. Sed gxuste kiel ke tiu funkcias por eterne kaj ĉiam, ŝanĝi ĉi tabelo farante ĝin indikas ion alian ne ŝanĝas tiun tabelo cxi tie ĉar ĝi estas kopio de la argumento, ĝi ne estas puntero al tiu argumento. Kaj efektive, same kiel pli indiko ke ĝi estas precize la sama - ni jam vidis kio impreso tabelo impresoj - kio se ni presi la adreson de la tabelo aŭ la adreson de la adreson de la tabelo al ĉu de tiuj? Ni ignoru ĉi tiun. Okay. Ĉi tio estas tre bone. Ĝi estas nun kuras. / A.out. Impreso tabelo, do presante la adreson de la tabelo, estas la sama afero. Array simple ne ekzistas. Ĝi scias, kiam vi presi tabelo, vi videbligi la simbolo kiu signifas tiuj 20 bajtoj. Presi la adreson de la tabelo, nu, tabelo ne ekzistas. Ĝi ne havas adreson, do nur presas la adreson de tiuj 20 bajtoj. Tuj kiam vi kompili malsupren, kiel en via kompilita buggy4. / A.out, tabelo estas neekzistanta. Punteros ekzisti. Arrays ne. La blokoj de memoro reprezentantaj la tabelo ankoraŭ ekzistas, sed la variablo tabelo kaj variabloj de tiu tipo ne ekzistas. Tiuj estas kiel la ĉefaj diferencoj inter tabeloj kaj punteros estas tiel frue kiel vi faras funkcio alvokoj, ne estas diferenco. Sed ene de la funkcio, ke la tabelo mem deklaris, sizeof funkcias malsame ekde vi videbligi la grandecon de la blokoj anstataŭ la grandeco de la tipo, kaj vi ne povas ŝanĝi ĝin ĉar ĝi estas simbolo. Presi la aferon kaj la adreso de la aĵo presas la saman aferon. Kaj tio estas preskaux ĝin. [Studento] Ĉu vi povas diri ke unu pli da tempo? Mi ne maltrafis ion. Impreso tabelo kaj adreso de tabelo presas la saman aferon, dum se vi presi puntero kontre la adreson de la puntero, la sola afero presas la adreso de kion vi indikante, la aliaj presas la adreso de la puntero de la pilo. Vi povas ŝanĝi puntero; vi ne povas ŝanĝi tabelo simbolo. Kaj sizeof puntero tuj presi la grandeco de tiu puntero tipo. Do int * p sizeof (p) tuj presi 4, sed int tabelo [5] print sizeof (areo) tuj presi 20. [Studento] Do int tabelo [5] presos 20? >> Jes. Tial ene de buggy4 kiam kutimis esti sizeof (areo) ĉi faris i <20, kio ne estas, kion ni deziris. Ni volas i <5. >> [Studento] Okay. [Bowden] Kaj poste kiam vi komencos pasante en la funkcioj, se ni faris int * p = array; ene de ĉi tiu funkcio, ni povas esence uzas p kaj batalarangxis en ĝuste la sama vojoj, krom la sizeof problemo kaj la ŝanĝiĝantaj problemo. Sed p [0] = 1; estas la sama kiel diri tabelo [0] = 1; Kaj tuj kiam ni diras foo (tabelo), aux foo (p); ene de la foo funkcio, ĉi tiu estas la sama nomita dufoje. Ne estas diferenco inter tiuj du alvokoj. Cxiu bona en tiu? Okay. Ni havas 10 minutojn. Ni provos atingi tra ĉi Hacker Typer programo, tiu retejo, kiu eliris lasta jaro aŭ io. Oni simple supozas ke kiel vi tajpas hazarde kaj presas el - Kion ajn dosiero okazas esti ŝarĝitaj estas kia gxi aspektas vi tajpas. Ĝi aspektas kiel ia mastruma sistemo kodo. Tion ni volas apliki. Vi devus havi duuma ruleblan nomata hacker_typer kiu prenas en sola argumento, la dosiero al "hacker tipo." Kurante la ruleblan devus liberigi la ekrano kaj poste presi unu signo de la pasinta-en dosiero ĉiufoje la uzanto premas klavon. Do kion ajn ŝlosila vi premas, ĝi devus forĵeti kaj anstataŭ presi karaktero de la dosiero tio estas la argumento. Mi preskaux diras al vi, kion la aĵoj kiujn ni tuj bezonas scii estas. Sed ni volas kontroli la termios biblioteko. Mi neniam uzis tiun bibliotekon en mia tuta vivo, do ĝi havas tre minimuma celoj. Sed ĉi tiu tuj estos la biblioteko povas uzi por forĵeti la karakteron vi batis kiam vi tajpas en normo in Do hacker_typer.c, kaj ni tuj volas # include . Rigardante la viron paĝo termios - I'm guessing ĝia fina VIN aŭ iu - Mi ne scias kiel legi ĝin. Rigardante tion, ĝi diras inkluzivi tiuj 2 dosierojn, do ni devos fari tion. Unua afero unue, ni volis preni en sola argumento, kiu estas la dosiero ni malfermos. Do kion mi volas fari? Kiel mi kontrolu vidi Mi havas sola argumento? [Studento] Se argc egalas ĝin. >> [Bowden] Yeah. Do, se (argc! = 2) printf ("uzado:% s [dosiero por malfermi]"). Do nun, se mi kuros ĉi sen havigi dua argumento - ho, mi bezonas la nova linio - vi vidos diras uzado:. / hacker_typer, kaj tiam la dua argumento devus esti la dosiero mi volas malfermi. Nun kion mi faru? Mi volas legi de ĉi tiu dosiero. Kiel mi legis de dosiero? [Studento] Vi malfermu ĝin unue. >> Jes. Do fopen. Kion fopen aspektas? [Studento] Dosiernomo. >> [Bowden] Dosiernomo tuj estos argv [1]. [Studento] Kaj poste kion vi volas fari kun ĝi, do la - >> [Bowden] Yeah. Do se vi ne memoras, vi povus simple fari viro fopen, kie okazas esti const char * vojon kie vojo estas dosiernomo, const char * modo. Se vi hazarde ne memoras kio modo estas, tiam vi povas serĉi modo. Ene de homo paĝoj, la oblikvo karaktero estas kion vi povas sercxi por aĵoj. Do mi tajpi / regimon serĉi modo. n kaj N estas kion vi povas uzi por ciklo tra la serĉo alumetoj. Jen ĝi diras la argumento mode punktoj al ĉeno komencante kun unu el la sekvaj vicoj. Do r, Malferma teksta dosiero por legado. Tio estas kion ni volas fari. Por legi, kaj mi volas konservi tion. La afero estas tuj estos DOSIERO *. Nun kion mi volas fari? Donu al mi dua. Okay. Nun kion mi volas fari? [Studento] Kontrolu se estas NULL. >> [Bowden] Yeah. Ajn vi malfermas dosieron, certigu ke vi sukcese povis malfermi. Nun mi volas fari tion termios stuff kie mi volas unue legis mian aktualan agordon kaj krom tiuj en ion, mi volas ŝanĝi mian agordojn ĵeti for ajna karaktero, ke mi tajpas, kaj tiam mi volas ĝisdatigi tiujn agordojn. Kaj poste en la fino de la programo, mi volas ŝanĝi al mia originala agordojn. Do la struct tuj estos de tipo termios, kaj mi tuj volas du el tiuj. La unua estas tuj estos mia current_settings, kaj tiam ili tuj estos mia hacker_settings. Unue, mi tuj volas savi mian aktualan agordon, tiam mi tuj volas ĝisdatigi hacker_settings, kaj tiam vojon al la fino de mia programo, mi volas restarigu nuna agordo. Do ŝparante nuna agordo, la maniero kiu funkcias, ni viro termios. Ni vidas, ke ni havas ĉi int tcsetattr, int tcgetattr. Mi pasas en termios struct por lia puntero. La vojo ĉi aspektos estas - I've jam forgesis kion la funkcio vokita. Kopiu kaj algluu ĝin. Do tcgetattr, tiam mi volas pasi en la struct ke mi savi la informon en, kiu tuj estos current_settings, kaj la unua argumento estas la dosiero descriptor cxar la afero mi volas savi la atributoj de. Kion la dosiero descriptor estas estas kiel ajn vi malfermas dosieron, ĝi ricevas dosieron descriptor. Kiam mi fopen argv [1], ĝi ricevas dosieron descriptor kiu vi referenco kiam ajn vi volas legi aŭ skribi al ĝi. Tio ne estas la dosiero descriptor Mi volas uzi ĉi tie. Estas tri dosieron descriptores vi havas implicite, kiu estas normo en, normo elirinte, norma eraro. Implicite, mi kredas ke estas normo en estas 0, normo ekster estas 1, kaj la norma eraro estas 2. Do kion mi volas ŝanĝi la agordojn de? Mi volas ŝanĝi la agordojn de kiam mi batis al gravulo, Mi volas ĵeti tiun karakteron for anstataŭ presi ĝin al la ekrano. Kio rivereto - normo en, normo ekster, aŭ norma eraro - respondas al aĵoj kiam mi tajpas en la klavaro? >> [Studento] Norma in >> Jes. Do mi povas aŭ fari 0 aŭ mi povas fari stdin. Mi ricevas la current_settings de normo in Nun mi volas ĝisdatigi tiuj agordoj, do unue mi kopii en hacker_settings kion mia current_settings estas. Kaj kiel structs laboro estas ĝi nur kopii. Ĉi kopias ĉiuj kampoj, kiel vi devus atendi. Nun mi volas ĝisdatigi kelkaj el la kampoj. Rigardante termios, vi devus legi tra multaj ĉi nur por vidi kion vi volus serĉi, sed la flagoj vi tuj volas serĉi estas eĥo, tiel eĥo Ĵetas enigo gravuloj. Unue mi volas establi - I've jam forgesis kion la kampoj estas. Ĉi tio estas kion la struct aspektas. Do enigo modoj mi kredas ke ni volas ŝanĝi. Ni rigardu la solvo por certigi tion ni volas ŝanĝi. Ni volas ŝanĝi lflag por malhelpi bezoni trarigardi cxiujn tiujn. Ni volas ŝanĝi loka modoj. Vi devus legi tra ĉi tiu tuta afero por kompreni kie ĉiu apartenas ke ni volas ŝanĝi. Sed estas ene de lokaj modoj, kie ni tuj volas ŝanĝi tion. Do hacker_settings.cc_lmode estas kio ĝi estas nomata. c_lflag. Tie estas kie ni enir bitlarĝa operatoroj. Ni estas speco de ekstere de tempo, sed ni iros tra ĝi realan rapida. Tie estas kie ni enir bitlarĝa operatoroj, kie mi kredas ke mi diris iam antaŭ longe ke kiam ajn oni komencas trakti kun flagoj, vi tuj estos uzante bitlarĝa operatoro tre. Ĉiu bito en la flago respondas al ia konduto. Do jen, ĉi flago havas aron da malsamaj aĵoj, kie ĉiuj ili signifas ion malsaman. Sed kion mi volas fari estas simple elŝalti la bito kiu korespondas al eĥo. Do por igi tiun ekstere mi faras & = ¬ EĤO. Fakte, mi kredas ke estas kiel tECHO aŭ iu. Mi nur tuj kontroli denove. Mi povas termios ĝin. Ĝi estas nur eĥo. ĴETAS tuj estos sola iom. ¬ ĴETAS tuj signifas ĉiuj bitoj estas aro al 1, kiu signifas ĉiuj flagoj estas aro al vera krom la ĴETAS iom. Por fini mian lokan flagoj kun ĉi tio, ĝi signifas ĉiuj flagoj kiuj aktuale difinitaj al vera ankoraŭ enkadrigeblajn por vera. Se mia ĴETAS flago estas metita al vera, tiam ĉi tiu estas bezone starigis al falsa la ĴETAS flago. Do ĉi tiu linio de kodo nur malŝaltas la ĴETAS flago. La aliaj linioj de kodo, mi nur kopii ilin en la intereso de tempo kaj tiam ekspliki ilin. En la solvo, li diris 0. Estas probable pli bone eksplicite diras stdin. Rimarku, ke mi ankaŭ faras ĴETAS | ICANON tie. ICANON referencas al iu aparta, kiu signifas kanona modo. Kio kanona mode rimedoj estas kutime kiam vi tajpas el la komandlinio, normo en ne procesi ion ĝis vi batis lino. Do kiam vi GetString, vi tajpi faskon da aĵoj, tiam vi batis lino. Tio estas, kiam ĝi estos sendita al la normo in Tio estas la defaŭlta. Kiam mi elŝalti kanona modo, nun ĉiu unuopa signo vi premas Estas kio gets procesis, kiu estas kutime ia malbona ĉar ĝi estas malrapida procesi tion, tial ĝi estas bona por buffer gxin en tuta linioj. Sed mi volas ĉiu karaktero esti procesita ĉar mi ne volas ĝin por atendi min bati linion antaŭ ol ĝi procesas ĉiuj karakteroj Mi estis tajpado. Ĉi malŝaltas kanona modo. Ĉi stuff simple signifas kiam fakte procesas gravuloj. Tio signifas procesi ilin tuj; tuj kiam mi tajpas ilin, procesi ilin. Kaj jen estas la funkcio kiu estas ĝisdatigi mian agordojn por normo en, kaj TCSA rimedoj faru ĝin nun. La aliaj ebloj estas atendi ĝis ĉiu kiu estas nuntempe en la rojon procesis. Tio ne vere gravas. Ĝuste nun ŝanĝos mian agordojn por esti kio ajn nuntempe en hacker_typer_settings. Mi supozas mi nomis ĝin hacker_settings, do ni ŝanĝas tion. Ŝanĝi ĉiu hacker_settings. Nun je la fino de nia programo ni tuj volas restarigu kio estas nuntempe ene de normal_settings, kiu iras al nur aspektas kiel & normal_settings. Rimarku Mi ne ŝanĝis iun el miaj normal_settings ekde origine atingi ĝin. Tiam al nur ŝanĝi ilin, mi pasas ilin je la fino. Ĉi tiu estis la ĝisdatigon. Okay. Nun interne de tie mi nur klarigas la kodon en la intereso de la tempo. Ne tiom da kodo. Ni vidas ni legas karakteron de la dosiero. Ni nomis ĝin f. Nun vi povas homo fgetc, sed kiel fgetc tuj labori Estas ĝuste tio okazas reveni la karaktero kiu vi ĵus legis aŭ EOF, kiu korespondas al la fino de la dosiero aŭ iu eraro okazas. Ni looping, daŭrigante legi sola karaktero de la dosiero, gxis ni ne plu havas signojn por legi. Kaj dum ni faras tion, ni atendas sur sola karaktero de normo in Ĉiu unuopa kiam vi tajpas ion en la komandlinio, ke tio legi en karaktero de normo in Tiam putchar estas ĝuste tuj metis la char ni legas ĉi tien el la dosieron al la normo eksteren. Vi povas homo putchar, sed ĝi estas nur metante al normo eksteren, ĝi estas videbligi tiun karakteron. Vi povus ankaŭ nur faru printf ("% c", c); Sama ideo. Tio faros la ŝvelaĵo de nia laboro. La lasta afero ni tuj volas fari estas simple fclose nia dosiero. Se vi ne fclose, tio estas memoro fugo. Ni volas fclose la dosiero ni origine malfermigxis, kaj mi pensas ke estas tio. Se ni faras tion, mi jam ricevis problemojn. Ni vidu. Kion ĝi plendas pri? Atendis 'int' sed argumento estas de tipo 'struct _IO_FILE *'. Ni vidos se tiu funkcias. Nur permesis en C99. Augh. Konsentite, fari hacker_typer. Nun ni preni pli utilajn priskribojn. Do la uzo de nedeklarita ensalutilo 'normal_settings'. Mi ne nomis ĝin normal_settings. Mi vokis ĝin current_settings. Do ni ŝanĝas ĉiuj tion. Nun pasi argumento. Mi faros ĉi 0 por nun. Okay. . / Hacker_typer cp.c. Mi ankaŭ ne klara la ekrano en la komenco. Sed vi retrorigardas al la lasta problemo aro por vidi kiel vi certe la ekrano. Ĝi simple presi iujn signojn dum ĉi faras kion mi volas fari. Okay. Kaj pensante pri kial ĉi bezonis esti 0 anstataŭ stdin, kiuj devus esti # difini 0, ĉi tio plendis, ke - Antaŭ kiam mi diras ke ekzistas dosiero descriptores sed tiam vi ankaŭ havas vian DOSIERO *, dosiero descriptor estas nur simpla entjero, dum kiu DOSIERO * havas tuta amaso da taskoj asociita kun ĝi. La kialo necesas diri 0 anstataŭ stdin estas ke stdin estas DOSIERO * kiu notas al tio, kiu estas referenco dosieron descriptor 0. Do eĉ ĝis ĉi tie kiam mi faros fopen (argv [1], mi getting a DOSIERO * dorso. Sed ie en tiu DOSIERO * estas io responda al la dosiero descriptor por tiu dosiero. Se vi rigardas la viro paĝon por malferma, do mi kredas ke vi devos fari viron 3 malfermita - nope - viro 2 malfermita - yeah. Se vi rigardas la paĝon por malferma, malfermita estas kiel suba-nivelo fopen, kaj ĝin redoni la reala dosiero descriptor. fopen faras aron da aĵoj sur malferma, kiuj anstataŭ reveni nur tiu dosiero descriptor revenas tuta DOSIERO * puntero ene de kiuj estas niaj infanoj dosieron descriptor. Do normo en raportas al la DOSIERO * aferon, dum 0 raportas al nur la dosieron descriptor normo en si mem. Demandoj? [Ridas] Blew tra tiu. Bone. Ni faris. [Ridas] [CS50.TV]