[Powered by Google Translate] [Дел 5 - поудобно] [Роб Бауден - Универзитетот Харвард] [Ова е CS50. - CS50.TV] Како што реков во мојот мејл, постојат многу работи што можете да ги користите освен апаратот всушност направиме проблем комплети. Ние Ви препорачуваме да го стори тоа во апаратот само затоа што тогаш ние полесно може да ви помогне и знаеме колку се оди на работа. Но, како еден пример каде што можете да ги правите нештата ако, да речеме, немате пристап кон апаратот или сакате да работите во Научниот центар подрумот - што всушност тие имаат апаратот премногу - ако сакате да работат насекаде. Еден пример е си ја видел / чул за SSH? SSH е во основа, само како поврзете со нешто. Всушност, токму сега сум SSHed во уредот. Јас никогаш не работат директно во апаратот. Тука е апаратот, и ако се погледне долу тука ќе видите оваа IP адреса. Јас никогаш не работат во апаратот себе; Јас секогаш дојде до iTerm2 прозорец / терминален прозорец. Можете да SSH на таа IP адреса, ssh, jharvard@192.168.129.128. Се сеќавам дека бројот е многу лесно, бидејќи тоа е толку убаво шема. Но, тоа ќе ме прашате за мојата лозинка, и сега сум во апаратот. Во суштина, во овој момент, ако отвори терминал внатрешноста на апаратот себе, овој интерфејс, сепак ќе го користи, е иста како интерфејс сум користење на повеќе од тука, но сега сте SSHed. Вие не треба да SSH на уредот. Еден пример на друго место можете да SSH да е јас сум прилично сигурен дека имате стандардно - О. Поголеми. Сите треба да имаат стандардно ФАС сметки на ФАС сервери. За мене, јас би SSH за rbowden@nice.fas.harvard.edu. Тоа се случува да ве прашам што прв пат, и велиш ДА. Мојата лозинка е само ќе ми биде ФАС лозинка. И така сега, јас сум SSHed на убаво сервери, и можам да направам ништо што сакате овде. Многу класи може да се земе како 124, се случува да имаат да испратите нешто овде всушност да ја поднесете вашата проблемот комплети. Но, велат дека не имаат пристап до вашиот апарат. Потоа можете да ги правите нештата, како овде ќе каже - Ова е само нашиот дел од прашањата. Тоа ќе побара од вас да го направите ова во апаратот. Наместо тоа, само ќе го направи на серверот. Одам да отпакувате тоа. Проблемот се случува да биде дека сте навикнати да користи нешто како gedit или што и во внатрешноста на апаратот. Вие нема да го имаат тоа на ФАС серверот. Сето тоа е само ќе биде оваа текстуална интерфејс. Така што би можеле ниту една, обидете се да дознаете текст едитор дека тие немаат. Тие имаат Нано. Нано обично е прилично лесен за употреба. Можете да го користите вашиот стрели и напишете нормално. Значи тоа не е тешко. Ако сакате да добиете навистина фенси можете да го користите Emacs, што јас веројатно не треба да се отвори, бидејќи јас дури и не знаат како да ја затворам Emacs. Контрола X, контрола Ц? Да. Или можете да го користите Vim, што е она што јас го користам. И така тие се вашите опции. Ако не сакате да го направите тоа, можете исто така, ако се погледне на manual.cs50.net-- О. На PC, можете да SSH користење на кит, кои ви се случува да мора да преземете одделно. На Mac, можете да само стандардно приклучок или може да го симнете iTerm2, кој е како убав, фенси терминал. Ако одите на manual.cs50.net ќе видите линк до Notepad + +, што е она што можете да го користите на PC. Тоа ви овозможува да SFTP од Notepad + +, што е основа на SSH. Што ова ќе ви овозможи да направите е да ги уредувате своите датотеки на локално ниво, а потоа кога ќе сакате да ги зачувате, тоа ќе заштедите за nice.fas, каде што можете да ги извршувате. И еквивалент на Mac ќе биде TextWrangler. Па што ви овозможува да го прават истото. Тоа ви овозможува да уредувате датотеки локално и спаси ги nice.fas, каде што можете да ги извршувате. Значи, ако сте некогаш залепи без струја, ќе ги имаат овие опции се уште го направите вашиот проблем комплети. На еден проблем се случува да биде дека не сте ќе имаат CS50 библиотека бидејќи nice.fas не по дифолт имаат тоа. Можете или да го преземете CS50 библиотека - Мислам дека не ми треба тоа во овој момент. Можете или да го преземете CS50 библиотека и да ја фотокопирам во текот на nice.fas, или Мислам дека во овој момент ние не го користат повеќе во секој случај. Или ако тоа го правиме, можете да за тоа време го замени со имплементации на функциите во CS50 библиотека во секој случај. Така што не треба да биде дека голем дел од ограничување. И тоа е тоа. Јас ќе се вратам на апаратот сега, ние ќе направиме се што е во уредот. Гледајќи нашата секција на прашања, на почетокот, како што реков во мојот мејл, ние треба да зборуваме за еден краток што требаше да се види. Имаме пренасочува & цевки и овие три прашања. Кој поток се функции како printf пишуваат по дифолт? Значи поток. Што е поток? А поток е во основа како тоа е само некои - Тоа не е дури извор на 1S и 0-ти. Потокот тоа барајќи тука е стандарден излез. И така стандарден излез е поток што кога ќе пишувам за тоа, се појавува на екранот. Стандарден излез, со поток, тоа значи дека само напиши 1S и 0-ти на него, и на другиот крај на стандарден излез едноставно чита од тој поток. Тоа е само низа од 1S и 0-ти. Можете да пишете на текови или можете да прочитате од потоци зависност од она што поток навистина е. Другите две стандардно потоци се стандардни и стандардна грешка. Стандард во е секогаш кога ќе се GetString, тоа е на чекање за вас да го внесете нешта. Така што на чекање за вас, тоа е всушност чека стандард во, што е навистина она што го добивате кога ќе напишете на тастатурата. Ти си пишувате во стандард внатре Стандардна грешка е во основа еквивалентни на стандарден излез, но тоа е специјализирана во тоа што кога ќе се печати стандардна грешка, си требал само да печати грешка пораки дека па можете да се разликува помеѓу обичните пораки печатени на екранот наспроти грешка пораки во зависност од тоа дали тие отиде до стандарден излез или стандардна грешка. Додадени фајлови: премногу. Стандарден излез, стандардна во, и стандардна грешка се само посебни потоци, но, навистина било која датотека, кога ќе отворите датотека, станува поток од бајти каде што само може да се прочита од таа струја. Вие, во најголем дел, само да се сетам на датотека како поток од бајти. Значи она што струи тие пишуваат по дифолт? Стандарден излез. Која е разликата помеѓу> и >>? Дали некој се види на видео однапред? Во ред. > Ќе биде како ви се пренасочува во датотеки, и >> е, исто така, ќе пренасочи излез во датотеки, но тоа е наместо случува да додадете на датотека. На пример, да речеме јас се случи да имаат речник токму тука, и само работи во внатрешноста на речник е мачка, мачка, куче, риба, куче. Една наредба што треба на командната линија е мачка, што е само ќе печати она што е во датотека. Значи, кога велам мачка речник, тоа нема да се печати мачка, мачка, куче, риба, куче. Тоа е се мачка прави. Тоа значи дека печатени до стандарден излез мачка, мачка, куче, риба, куче. Ако јас наместо сакате да го пренасочи дека во датотека, можам да користам> и пренасочување до она што датотеката е. Ќе му се јавам на датотеката датотека. Па сега ако јас ls, јас ќе видам имам нов фајл наречен датотека. И ако ја отвори, тоа се случува да имаат токму она мачка стави на командната линија. Па сега, ако го направам тоа повторно, тогаш тоа ќе се пренасочи на излез во датотека, и јас одам да имаат ист точната нешто. Значи технички, тоа целосно overrode она што го имавме. И ние ќе видиме ќе се промени речник, го извадив куче. Сега ако ние мачка речник во датотека еднаш, ние ќе имаме нова верзија со куче отстранети. Така што целосно го надминува. Наместо тоа, ако ние ги користиме >>, тоа се случува да додадете датотека. Сега, отворање на датотека, можеме да видиме ние имаме само истото печатени двапати поради тоа што беше таму еднаш, тогаш во прилог на оригиналот. Значи тоа е она> и >> направи. Дали следниот прашам - Тоа не прашува за тоа. Другиот што го имаме е <, што ако> пренесувања стандарден излез, <Ќе биде пренасочување стандард внатре Ајде да видиме дали имаме еден пример. Јас можам да пишувам еден вистински брз. Да го земеме некоја датотека, hello.c. Релативно јасна датотека. Јас сум само добивање на стринг, а потоа печати "Здраво" без оглед на стринг Јас само влезе беше. Така осигурајте се Здраво и тогаш. / Здраво. Сега е ме прашува да внесете нешто, што значи дека чека на работи кои треба да се влезе во стандард внатре Па влезат она што го сакам во стандарден внатре Ние сме само ќе кажам здраво, Роб! Тогаш тоа е печатење на стандарден излез Здраво, Роб! Ако го направам. / Здраво и тогаш пренасочување, за сега може само да се пренасочи од датотека. Значи, ако јас се стави во некои датотеки, TXT, и да го ставам Роб, ако јас се кандидира здраво, а потоа се сврти txt датотеката во. / здраво, тоа се случува да се каже Здраво, Роб! веднаш. Кога за прв пат добива GetString и чека на стандард во, стандард во веќе не чекаат на тастатурата за податоци да се внесе. Наместо тоа, ние сме пренасочени стандард во да го прочита од txt датотеката. И така тоа се случува да прочитам од датотеката txt, што е само линија Роб, а потоа тоа се случува да се печати Здраво, Роб! И ако сакав, јас исто така може да го направи. / Здраво правиш 2>, тоа е пренасочува стандардна грешка. Па ако нешто отиде во стандардна грешка, тоа не би се стави во txt2. Но забележите ако го направам 2>, тогаш тоа е уште печатење Здраво, Роб! на командната линија бидејќи јас сум само пренасочува стандардна грешка, не сум пренасочува стандарден излез. Стандардна грешка и стандарден излез се различни. Ако сакаше да всушност пишува за стандардна грешка, тогаш би можел да ја промените оваа да биде fprintf до stderr. Значи printf, по дифолт, отпечатоци до стандарден излез. Ако сакам да се печати стандардна грешка рачно, тогаш треба да се користи fprintf и да го одредите она што сакам да се печати. Ако наместо тоа го направив fprintf stdout, тогаш тоа е во основа еквивалентни на printf. Но fprintf да стандардна грешка. Па сега, ако јас пренасочи ова во txt2, Здраво, Роб! се уште добивање испечатени на командната линија бидејќи тоа е добивање печатени стандардна грешка и јас сум само пренасочува стандарден излез. Ако јас сега пренасочи стандардна грешка, сега тоа не се отпечатени, а txt2 ќе биде Здраво, Роб! Па сега, можете да печатите вашиот вистински грешки стандардна грешка и печатење на вашите редовни пораки до стандарден излез. И така, кога ќе ја стартувате вашата програма, можете да го стартувате како. / Здраво овој тип со 2> така што вашата програма ќе одвива нормално, но ниедна грешка пораки кои ги добивате може да се провери подоцна во вашата грешка најавите, па грешки, и потоа да се погледне подоцна и вашите грешки датотеката да има никакви грешки што се случило. Прашања? Последната е цевката, што можете да замислите како преземање на стандарден излез од една команда и што го прави стандард во на следниот команда. Пример тука е ехо е командната линија работа што е само ќе ехо она што го стави како свој аргумент. Јас не ќе се стави цитати. Ехо бла, бла, бла е само ќе печати бла, бла, бла. Пред тоа, кога реков дека мораше да се стави Роб во txt датотеката бидејќи јас само може да се пренасочи txt датотеки, наместо тоа, / ако ехо Rob а потоа цевка во. / здраво, кои, исто така, ќе го стори истото тип на работа. Ова е преземање на излезот од оваа команда, ехо Роб, и го користи како влез за. / здраво. Можете да мислите на тоа како првиот пренасочи ехо Роб во датотека а потоа влез во. / здраво таа датотека која беше само outputted. Но, потребно е на привремена датотека од слика. Прашања за тоа? Следното прашање се случува да се вклучи тоа. Што гасоводот можете да го користите да се најде бројот на уникатни имиња во датотека наречена names.txt? Команди ние ќе сакате да го користите овде се единствени, така Uniq, а потоа тоалет. Можете да го направите човек Uniq да всушност се погледне во она што го прави, и тоа само ќе ги филтрираат соседните појавување линии од влезот. И човекот тоалет се случува да се печати линија, збор, и бајт точки за секоја датотека. А последната ние ќе сакате да го користите е вид, кој се случува само сортирање линии на txt датотеката. Ако можам да направам некои txt датотеката, names.txt, а тоа е Роб, Томи, Јосиф, Томи, Јосиф, RJ, Роб, она што сакам да го направите тука е да се најде бројот на уникатни имиња во оваа датотека. Значи она што е одговорот треба да биде? >> [Студент] 4. >> Да. Тоа треба да биде 4 од Роб, Томи, Јосиф, RJ се само уникатен имиња во оваа датотека. Првиот чекор, ако јас само го прават збор брои на names.txt, ова е, всушност, ми кажуваше се. Ова е, всушност, печатење - Ајде да видиме, човек WC - новите редови, зборови, и бајт брои. Ако јас само се грижат за линии, тогаш само може да го направи WC-L names.txt. Значи тоа е чекор 1. Но, јас не сакам да names.txt WC-L, бидејќи names.txt само ги содржи сите имиња, и сакам да ги филтрираат сите не-уникатен оние. Значи, ако јас не Uniq names.txt, тоа сосема не ми даде она што го сакате бидејќи дупликат имиња се уште се таму. Зошто е тоа така? Зошто не Uniq прави она што го сакате? [Студент] дупликати не се [недоловим] >> Да. Запомни човекот страница за Uniq вели филтер соседните појавување линии. Тие не се во непосредна близина, така што не ќе ги филтрира. Ако јас сортирање нив прво, вид names.txt се случува да се стави сите дупликат линии заедно. Па сега вид names.txt е тоа. Одам да сакате да го користите дека влезот Uniq, која е | Uniq. Тоа ми дава Јосиф, RJ, Роб, Томи, и јас сакам да го користат како влез на WC-L, кој ќе ми даде 4. Како што се вели овде, она гасоводот можете да го користите? Можете да направите многу нешта, како употреба на серија на команди каде што имате потреба при користење на излез од една команда како влез во следната команда. Можете да направите многу работи, многу умен нешта. Прашања? Во ред. Тоа е тоа за цевки и редирекција. Сега ние одиме на вистинските нешта, кодирање нешта. Внатрешноста на овој PDF, ќе видите оваа команда, и ќе сакате да ја извршите оваа команда во Вашиот уред. wget е команда за само добивање на нешто од интернет, во основа, па wget и тоа рачно. Ако отиде во овој URL во вашиот прелистувач, тоа ќе преземете таа датотека. Јас само кликнал на него, па затоа преземена датотеката за мене. Но пишувањето wget на тоа нешто внатрешноста на терминал е само ќе го преземете во вашиот терминал. Имам section5.zip, и ќе сакате да го отпакувате section5.zip, која ќе ви даде папка наречена section5, која се случува да имаат сите датотеки што ќе треба да се користи денес во него. Како имиња на датотеки овие програми 'сугерира, тие се малку кабриолет, па вашата мисија е да дознаам зошто користење gdb. Не секој ги симнат / знаат како да се натераат симнат во нивните апаратот? Во ред. Вклучување ./buggy1, ќе каже Сегментација на вина (јадро фрлени) кои во секое време ќе добие segfault, тоа е лоша работа. Под кои околности што ќе добие segfault? [Студент] Dereferencing е нулти покажувач. >> Да. Па тоа е еден пример. Dereferencing е нулти покажувачот си оди за да се добие segfault. Што segfault значи сте допирање меморија не треба да се допираат. Значи dereferencing е нулти покажувачот се допира адреса 0, и во основа, сите компјутери во денешно време се каже дека адресата 0 е меморија не треба да се допираат. Па затоа dereferencing е нулти покажувачот резултати во segfault. Кога ќе се случи да не се иницијализира покажувачот, тогаш тоа има ѓубре вредност, и така, кога ќе се обидат да Dereference тоа, во сите веројатноста сте допирање меморија тоа е во средината на никаде. Ако се случи да добиете среќа и ѓубре вредност се случи да се укаже некаде на магацинот или нешто, тогаш кога ќе Dereference дека покажувач кој не сте го иницијализира, ништо нема да тргне наопаку. Но, ако тоа е што укажува на, да речеме, некаде помеѓу магацинот и грамада, или тоа е покажувајќи само за некаде дека не е користена од страна на вашата програма, сепак, тогаш сте допирање меморија не треба да се допира и segfault. Кога пишувате рекурзивен функција и recurses премногу пати и вашиот магацинот расте премногу големи и магацинот се судира во нештата дека не треба да се судир со, ти си допирање меморија не треба да се допира, па segfault. Тоа е она што segfault е. Тоа е, исто така, од истата причина дека ако имате низа како - да се вратиме на претходната програма. Во hello.c--I'm само случува да се направи нешто друго. char * s = "Здраво Светот!"; Ако јас го користам * S = нешто или е [0] = 'X'; така бидете Здраво,. / здраво, зошто тоа segfault? Зошто оваа segfault? Она што би очекувале да се случи? Ако сум го правела printf ("% s \ n", s), што би очекувале да бидат испечатени? [Студент] X здраво. >> Да. Проблемот е што кога ќе се изјасни за низа вака, s е показател дека се случува да одат на магацинот, и она што е се укажува на е овој стринг кој е содржан во read-only меморија. Па само со името, само за читање меморија, треба да добиете идеја дека ако се обиде да го промени она што е во read-only меморија, правиш нешто што не треба да се прави со меморија и segfault. Ова е всушност голема разлика меѓу char * s и знак на []. Значи знак на [], сега оваа низа ќе биде ставен на магацинот, и магацинот не е само за читање, што значи дека тоа треба да работат совршено добро. И тоа го прави. Запомнете дека кога правам char * s = "Здраво Светот!", А самата е на магацинот но и укажува на друго место, и дека некаде на друго место се случува да биде само за читање. Но знак на [] е само нешто на магацинот. Значи тоа е уште еден пример на segfault случува. Видовме дека ./buggy1 резултираше со segfault. Во теорија, вие не треба да се погледне во buggy1.c веднаш. Наместо тоа, ние ќе се погледне во него преку gdb. Забележете дека кога ќе добие Сегментација на вина (јадро фрлени) ќе добиете оваа датотека овде наречен јадро. Ако ние ls-l, ќе видиме дека јадрото е обично прилично голема датотека. Ова е број на бајти на датотека, па тоа изгледа како да е 250-нешто килобајти. Причината за ова е тоа што јадрото депонијата всушност е е кога вашата програма се урна, состојбата на меморијата на вашата програма само добива копирани и атипичен во оваа датотека. Станува фрлени во таа датотека. Оваа програма, а тоа е водење, се случи да имаат меморија од околу 250 килобајти, и така тоа е она што влегов фрлена во оваа датотека. Сега можете да се погледне во таа датотека ако правиме gdb buggy1 јадро. Ние само може да го направи gdb buggy1, а тоа само ќе ја стартувате gdb редовно, користење buggy1 како свој влезна датотека. Но, ако не gdb buggy1 јадро, тогаш тоа е конкретно ќе започнат gdb од страна гледајќи во тоа основни датотека. И сакаш да кажеш buggy1 средства gdb знае дека тоа основни датотека доаѓа од buggy1 програма. Значи gdb buggy1 јадро се случува веднаш да ни донесе каде на програмата се случи да се прекине. Гледаме тука програма прекинат со 11 сигнал, Сегментација на вина. Ние се случи за да ја видите линија на собранието, која, најверојатно, не е многу корисна. Но, ако го напишете БТ или трагата што ќе биде во функција што ни дава листа на нашите сегашни магацинот рамки. Па трагата. Изгледа ние само две магацинот рамки. Првиот е нашата главна магацинот рамка, а втората е на магацинот рамка за оваа функција што се случи да биде во, кој изгледа како имаме само собранието код за. Значи, да се вратиме во нашата главна функција, и да направиме што можеме да направиме рамка 1, и мислам дека ние исто така може да го направи надолу, но јас речиси никогаш не се направи надолу - или нагоре. Да. Нагоре и надолу. До носи до една магацинот рамка, долу носи надолу оџак рамка. Имам навика да не ја користат таа. Јас само специјално велат рамка 1, кој се оди на рамка етикетирани 1. Рамка 1 ќе нè внесе во главниот магацинот рамка, и вели дека токму тука на линија на кодот ние се случи да биде. Ако сакавме уште неколку линии на код, можеме да кажеме листа, и тоа ќе ни даде на сите линии на код околу неа. Линијата ние segfaulted на е 6: ако (strcmp ("CS50 карпи", avg [1]) == 0). Ако тоа не е очигледно, сепак, може да го добие директно од тука само од страна на размислување зошто тоа segfaulted. Но, ние може да го земе еден чекор понатаму и велат: "Зошто би avg [1] segfault?" Печати ајде avg [1], и тоа изгледа како тоа е 0x0, кој е нула покажувачот. Ние сме strcmping CS50 карпи и нула, и така тоа ќе segfault. И зошто е avg [1] нула? [Студент] Бидејќи ние не го даде каква било командната линија аргументи. Да. Ние не го даде каква било командната линија аргументи. Значи ./buggy1 е само ќе треба avg [0] се ./buggy1. Тоа нема да имаат avg [1], па тоа ќе segfault. Но, ако, наместо тоа, јас само CS50, тоа се случува да се каже Ќе добиете D бидејќи тоа е она што би требало да се направи. Гледајќи buggy1.c, тоа би требало да се печати "Ќе добиете Д" - Ако avg [1] не е "CS50 карпи", "Ќе добиете Д", друго "Ти среди А!" Значи, ако сакаме А, ние треба ова да се споредуваат како вистински, што значи дека тоа се споредува со 0. Значи avg [1] треба да биде "CS50 карпи". Ако сакате да го направите тоа на командната линија, треба да користите \ да избега од простор. Значи CS50 \ карпи и ќе добиете А! Ако не го направите обратна коса црта, зошто не оваа работа? [Студент] Тоа е две различни аргументи. >> Да. Avg [1] ќе биде CS50, и avg [2] ќе биде карпи. Во ред. Сега ./buggy2 ќе segfault повторно. Наместо отворање со неговото јадро датотека, ние само ќе се отвори buggy2 директно, па gdb buggy2. Сега ако ние едноставно се кандидира нашата програма, тогаш тоа се случува да се каже програма примениот сигналот SIGSEGV, која е segfault сигнал, и ова е местото каде што се случи да се случи. Гледајќи нашата трагата, можеме да видиме дека сме биле во функција oh_no, кој беше наречен од страна на функција спретнат, кој беше наречен од страна на функција binky, кој бил повикан од главните. Ние, исто така може да се види аргументите на овие функции. Аргументот за спретнат и binky беше 1. Ако ние листа на функцијата oh_no, можеме да видиме дека oh_no е само прави знак ** S = NULL; * Кликнете = "бум"; Зошто тоа ќе пропадне? [Студент] Вие не може Dereference на нула покажувачот? >> Да. Ова е само велејќи s е NULL, без оглед дали тоа се случува да биде знак **, кои, во зависност од тоа како ќе го толкува, тоа би можело да биде покажувач на покажувач кон низа или низа од стрингови. Тоа е е е NULL, па * s е dereferencing е нулти покажувач, и така ова ќе се сруши. Ова е една од најбрзо начини што веројатно може да segfault. Тоа е само за прогласување на нула покажувачот и веднаш segfaulting. Тоа е она што oh_no прави. Ако одиме до една рамка, тогаш ние ќе ја добиеме во функција она што е наречено oh_no. Ми треба да го направат тоа долу. Ако не внесете ја командата и вие само притиснете ентер, повторно, тоа само ќе се повторува претходниот команда која ќе истрча. Ние сме во рамка 1. Листата оваа рамка, ние гледаме тука е нашата функција. Можете да хит листа повторно, или можете да го направите листа 20 и тоа ќе листата повеќе. Функцијата спретнат вели дека ако јас е 1, тогаш одете на функцијата oh_no, друго оди во slinky функција. И знаеме i е 1 затоа што се случи за да ја видите се тука дека спретнат беше повикана со аргументот 1. Или едноставно можете да можам да печати и ќе кажам дека е 1. Ние сме во моментов во спретнат и ако одиме до друга рамка, знаеме дека ќе заврши во binky. Нагоре. Сега сме во binky. Листата оваа функција - листата од пред половина ме отсечени - тоа започна како ако јас е 0, тогаш ние ќе го наречеме oh_no, друг да го повикате спретнат. Ние знаеме бев 1, па затоа се нарекува спретнат. И сега ние сме назад во главната, а главната е само ќе биде int i = rand ()% 3; Тоа е само ќе ви даде случаен број кој е или 0, 1, или 2. Тоа се случува да се јавите binky со тој број и ќе се вратат 0. Гледајќи ова, само одење преку програмата рачно без трчање веднаш, ќе се постави брејк во главните, што значи дека кога ќе ја стартувате програмата вашата програма работи се додека не хитови брејк. Значи водење на програмата, ќе се кандидира и потоа ќе ја погоди главната функција и да престане да работи. Сега сме во внатрешноста на главниот, и чекор или следната ќе ни донесе на следната линија код. Можете да направите чекор или следната. Удирањето следниот, сега јас е поставен на rand ()% 3, па можеме да се печати вредноста на i, и ќе каже дека е 1. Сега тоа не е важно дали ние ги користиме следната или чекор. Претпоставувам дека тоа важно во претходната, но ние би сакале да се користи следната. Ако ние ги користиме чекор, ние чекор во функција, што значи поглед на вистински работа што се случува во внатрешноста на binky. Ако ние ги користиме следната, тогаш тоа значи одиме во текот на функција и само да одат во следната линија код во нашата главна функција. Токму тука на оваа линија, јас бев во која се вели Rand ()% 3; ако сум го правела чекор, тоа ќе оди во спроведувањето на ранд и се погледне во она што се случува таму, и јас би можеле да чекор преку функцијата rand. Но јас не се грижат за функцијата rand. Јас само сакам да одат во следната линија код во главната, па јас го користам следната. Но, сега се грижат за binky функција, па сакам да влезете во тоа. Сега сум во binky. На првата линија на код се случува да се каже ако (i == 0), земам чекор, можеме да видиме на крајот ќе заврши во спретнат. Ако ние листа нешта, можеме да видиме дека го проверуваат е i = 0. Не е еднаков на 0, па затоа отиде на друго состојба, која ќе ја повика спретнат (i). Може да се збунети. Ако само погледнете во овие линии директно, можеби мислат ако (i == 0), во ред, а потоа отидов чекор и сега сум во спретнат (i), можеби мислат дека мора да значи i = 0 или нешто. Не Тоа само значи дека тоа го знае тоа може да се држи директно на линија спретнат (i). Затоа што не е 0, следниот чекор не се случува да се стави крај на друг. Друго не е линија тоа се случува да застане на. Тоа е само случува да одам до следната линија тоа всушност може да се изврши, што е спретнат (i). Повлекува во спретнат (i), можеме да видиме ако (i == 1). Ние не знам = 1, па кога ќе чекор, знаеме ние ќе завршат во oh_no затоа што i = 1 повикува функција oh_no, кој можете да влезете во, кој ќе се постави знак ** S = до ништовни и веднаш "БУМ". А потоа всушност да гледа во спроведувањето на buggy2, ова, јас се само добивање на случаен број - 0, 1 или 2 - повик binky, што ако јас е 0 го нарекува oh_no, друго што го нарекува спретнат, кој доаѓа до овде. Ако јас е 1, повик oh_no, друг да го повикате slinky, кои доаѓаат тука, ако јас е 2, јавете oh_no. Јас дури и не мислам дека постои начин - Дали некој ја видите начин за правење на оваа програма која нема да segfault? Затоа што ако сум недостасува нешто, ако јас е 0, веднаш ќе segfault, друго што оди на функција која ако јас е 1 ви segfault, друго што оди до некоја функција каде што ако јас е 2 ти segfault. Значи без разлика што правиш, можете segfault. Претпоставувам еден начин на одредување на тоа ќе биде наместо да прави знак ** S = NULL, можете да Примерок простор за тоа стринг. Ние не можеше да стори Примерок (sizeof) - sizeof што? [Студент] (знак) * 5? >> Дали ова изгледа добро? Јас сум претпоставувајќи ова ќе работи ако јас всушност го имаше, но тоа не е она што јас го барам. Погледни го типот на пријавите. Да додадете int *, па int * x. Јас би го направил Примерок (sizeof (int)). Или ако сакав низа на 5, јас би го направил (sizeof (int) * 5); Што ако имам int **? Што би ми Примерок? [Студент] Големина на покажувачот. >> Да. (Sizeof (int *)); Истото овде. Сакам (sizeof (char *)); Ова ќе одвои простор за покажувач кој покажува кон "БУМ". Јас не треба да одвои простор за "бум" се бидејќи ова е во основа еквивалент на она што реков пред на char * x = "БУМ". "Бум" веќе постои. Тоа се случува да постои во read-only регионот на меморија. Но, тоа веќе постои, што значи дека оваа линија код, ако е е знак **, потоа * s е char * и си поставување на овој знак * да се укаже на "бум". Ако сакав да го копирате "бум" во с, тогаш ќе треба да одвои простор за s. Јас ќе сторам * S = Примерок (sizeof (знак) * 5); Зошто 5? Зошто не 4? Личи на "бум" е 4 карактери. >> [Студент] Карактерот null. Да. Сите ваши жици се случува да треба на нула карактер. Сега можам да направам нешто како strcat - Која е функцијата за копирање низа? [Студент] КПЈ? >> Strcpy. човек strcpy. Значи strcpy или strncpy. strncpy е малку побезбедни, бидејќи можете да наведете точно колку карактери, но тука тоа не е важно, затоа што знаеме. Значи strcpy и гледам во аргументите. Првиот аргумент е нашата дестинација. Вториот аргумент е нашиот извор. Одиме да го копирате во нашата дестинација * S покажувачот "БУМ". Зошто можеби ќе сакате да го направите ова со strcpy наместо само она што го имавме пред на * S = "бум"? Постои причина зошто можеби ќе сакате да го направите ова, но она што е таа причина? [Студент] Ако сакате да промените нешто во "БУМ". >> Да. Сега можам да направам нешто слично на [0] = 'X'; бидејќи ги упатува на куп и тој простор на грамада дека е се укажува на е покажувач кон повеќе простор на грамада, која е чување "БУМ". Значи ова копија на "бум" се складирани во грамада. Постојат технички две копии на "бум" во нашата програма. Тука е првиот што е само дадена од страна на оваа "бум" стринг константа, и вториот примерок на "бум", strcpy создаде копија на "бум". Но копија на "бум" се чуваат на куп, и грамада ти си слободен да се промени. Грамада не е само за читање, па тоа значи дека е [0] се случува да ви се промени вредноста на "бум". Тоа ќе ви овозможи да се променат овие карактери. Прашања? Во ред. Премина на buggy3, ајде gdb buggy3. Ние само стартувајте го ZiPhone и гледаме да добиеме segfault. Ако ние трагата, постојат само две функции. Ако одиме нагоре во нашата главна функција, можеме да видиме дека ние segfaulted во оваа линија. Значи само гледајќи во оваа линија, за (int линија = 0; fgets овој материјал не е еднакво на нула; линија + +). Нашите претходни рамка беше наречен _IO_fgets. Ќе видите дека многу со вграден во C функции, дека кога ќе го добиете segfault, ќе има навистина криптичната имиња на функции вака _IO_fgets. Но, тоа се случува да се однесуваат на оваа fgets повик. Некаде во внатрешноста тука, ние сме segfaulting. Ако ги погледнеме аргументите на fgets, можеме да печатиме тампон. Ајде да се печати како - О, не. Печати нема да работат токму онака како што сакате тоа да. Ајде да погледнеме во вистинските програма. Тампон е лик низа. Тоа е лик низа од 128 карактери. Значи, кога велам печатење тампон, тоа се случува да се печати оние 128 карактери, која претпоставувам дека е она што се очекува. Она што јас го барате е печатење на адреса на тампон, но тоа навистина не ми каже многу. Па кога ќе се случи да се каже се тука x тампон, тоа ми покажува 0xbffff090, кои, ако се сеќавате од претходните или некоја точка, Oxbffff има тенденција да биде оџак-носталгичната регионот. Магацинот има тенденција да почнеме од некаде само под 0xc000. Само со гледање на оваа адреса, знам дека тампон се случува на магацинот. Рестартирање на мојата програма, трчаат, нагоре, тампон видовме беше оваа секвенца од знаци кои се доста безначајна. Потоа печатење датотека, што значи датотека изгледа? [Студент] NULL. >> Да. Датотеката е од типот СЛИКА *, па тоа е покажувач, и вредноста на тоа покажувачот е нула. Значи fgets се случува да се обидат да го читам од таа покажувачот на индиректен начин, но со цел да пристапите дека покажувачот, тоа треба да Dereference неа. Или, со цел да пристапите она што треба да се укажува на тоа дека dereferences. Така, тоа е dereferencing е нулти покажувач и segfaults. Јас би можеле да го рестартира таму. Ако ние се пробие во нашиот главен момент и да ја стартувате, на првата линија на кодот е char * фајлот = "nonexistent.txt"; Тоа треба да даде прилично голема навестување за тоа зошто оваа програма не успее. Пишување следната ме носи до следната линија, каде што ја отворите оваа датотека, а потоа веднаш влезе во нашата линија, каде што некогаш јас хит следната, тоа се случува да segfault. Сака ли некој да фрли причина зошто ние би можеле да бидат segfaulting? [Студент] Датотеката не постои. >> Да. Ова би требало да биде навестување дека секогаш кога ќе се отвори датотеката што треба да се провери дека датотеката всушност постои. Значи тука ", nonexistent.txt"; Кога ќе fopen име на датотека за читање, тогаш ние треба да се каже ако (датотека == NULL) и да каже printf ("Датотеката не постои!" или - уште подобро - име на датотека); враќање 1; Па сега ние се провери да се види дали тоа е NULL пред всушност продолжува и се обидува да се прочита од таа датотека. Можеме да го преобразиме само да се види дека тоа работи. Јас се наменети да се вклучат во нова линија. Па сега nonexistent.txt не постои. Секогаш треба да проверите за овој вид на работа. Секогаш треба да се провери да се види дали fopen враќа NULL. Секогаш треба да се провери да бидете сигурни дека Примерок не се врати NULL, или на друго место segfault. Сега buggy4.c. Трчање. Јас сум Сомневајќи се ова е на чекање за влез или можеби бесконечна looping. Да, тоа е бесконечна looping. Значи buggy4. Тоа изгледа како да сме бесконечна looping. Ние може да се скрши на главната, работи нашата програма. Во gdb, додека кратенката користите е недвосмислена или посебни кратенки кои тие ги обезбедуваат за вас, тогаш можете да го користите n да се користи следната наместо да напишеш од следната целиот пат. И сега што сум ги погоди n еднаш, јас само може да се погоди Enter за да продолжувам да одам наредната наместо да ја погоди N Enter, n Enter, n Enter. Изгледа како да сум во некој вид на за телефонска линија која е поставување низа [i] на 0. Тоа изгледа како јас никогаш не сум кршење на овој за телефонска линија. Ако јас јас печати, па е 2, тогаш јас ќе одиме понатаму. Ќе јас печати, i е 3, а потоа јас ќе одам понатаму. Ќе ми печати и јас е 3. Потоа, печати јас, јас е 4. Всушност, печатење sizeof (низа), па големината на низата е 20. Но, изгледа дека има некои посебни gdb команда за одење додека нешто се случува. Тоа е како поставување на состојбата на вредноста на променливата. Но, јас не се сеќавам што е тоа. Значи, ако ние Продолжувам да одам - Што се сакаш да кажеш? Што ви донесе до? [Студент] се прикажува додадам - ​​>> Да. Значи прикаже можам да помогнам. Ако само јас се прикаже, тоа ќе се стави до тука што вредноста на i е па јас не треба да го испечатите секој пат. Ако ние само продолжувам да одам наредната, можеме да видиме 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5. Нешто се случува ужасно погрешен, и јас се ресетира на 0. Гледајќи buggy4.c, можеме да видиме сите што се случува е int низа [5]; за (i = 0; з <= sizeof (низа); i + +) низа [i] = 0; Што гледаме дека не е во ред овде? Како навестување, кога го правев на gdb buggy4 - да се скрши главната, рок - Јас не печати sizeof (низа) само за да видам што состојбата е местото каде што треба конечно да се пробие. Каде сум јас? Никако не можев да се кандидира? Јас не се изјасниле уште. Значи печати sizeof (низа) и тоа е 20, кој се очекува со оглед на моето низа е со големина од 5 и е на 5 броеви, па целата работа треба да биде 5 * sizeof (int) бајти, каде sizeof (int) има тенденција да биде 4. Значи sizeof (низа) е 20. Што ова треба да биде? [Студент] Поделен со sizeof (int). >> Да, / sizeof (int). Тоа изгледа како таму е уште еден проблем тука. Мислам дека ова само треба да биде < бидејќи тоа е доста секогаш <никогаш и <=. Сега ајде да размислиме за тоа зошто ова е всушност скршена. Дали некој има нагаѓања зошто бев ресетирање на 0 преку секоја повторување на јамка? Единственото нешто внатре од овде што се случува е дека низа [i] е поставен на 0. Така некако, оваа линија код предизвикува нашите int i да се постави на 0. [Студент] Може да биде, бидејќи тоа е највисок меморија на овој дел на i кога смета дека тоа е следниот елемент од низата? >> [Бауден] Да. Кога ние ќе по завршувањето на нашата низа, некако тој простор, дека ние сме највисок е највисок вредноста на i. И така, ако ги погледнеме buggy4, пауза главната, рок, ајде да испечатите адреса на i. Тоа изгледа како тоа е bffff124. Сега ајде да печати адресата на низа [0]. 110. Што [1]? 114. [2], 118. 11c, 120. низа [5] е bfff124. Значи низа [5] ја има истата адреса како што, што значи дека низа [5] е i. Ако тие имаат иста адреса, тие се иста работа. Значи, кога ние во собата низа [5] на 0, ние сме јас Поставување на 0. И ако мислите дека за ова во поглед на магацинот, int i е прогласена прво, што значи дека добива некои простор на магацинот. Потоа низа [5] е наменет, па потоа 20 бајти се распределуваат врз оџакот. Па јас добива распределени, а потоа овие 20 бајти се распределени. Па јас се случува непосредно пред низа, и поради начинот на кој, како што реков минатата недела, каде што технички магацинот расте надолу, кога ќе индекс на низата, ние се гарантира дека 0. позиција во низа секогаш се случува пред првата позиција во низа. Ова е вид на како јас го привлече минатата недела. Забележете дека на дното имаме адреса 0 и на врвот имаме адреса Макс. Магацинот е секогаш расте надолу. Да речеме дека ние i распредели. Ние додели број I, што значи да речеме овде горе број i добива распределени. Тогаш ние додели нашата низа од 5 броеви, што значи дека под тоа, од магацинот расте надолу, оние 5 броеви се доделени. Но, поради начинот на низи работа, ние сме гаранција дека на првата позиција во низа секогаш има адреса помалку од Втората работа во низа. Значи низа положба 0 секогаш треба да се случи прво место во меморијата, додека низа позиција 1 мора да се случи после тоа и низа став 2 треба да се случи после тоа, што значи дека низа положба 0 ќе се случи некаде долу тука, низа позиција 1 ќе се случи над тоа бидејќи движат нагоре значи повисоки адреси од максималната адреса е до тука. Значи низа [0] долу тука, низа [1] се тука, низа [2] се тука, низа [3] се тука. Забележи како пред доделени целобројни јас целиот пат до тука, како што се движи понатаму и понатаму во нашата низа, ние сме добивање поблиску и поблиску до нашата цел број i. Тоа само така се случува, дека низа [5], која е една позиција надвор од нашата низа, е токму каде што број се случи да бидат распределени. Значи тоа е точка каде што се случи да биде притискање на просторот на магацинот кој беше наменет за број I, и ние сме поставување дека на 0. Тоа е како тоа функционира. Прашања? Да. [Студент] не е важно. Во ред. [Студент] Како да се избегнат овие вид на грешки? Овие вид на грешки? Не користите C како програмски јазик. Користете јазик кој има низа границите проверка. Додека сте внимателни, можете само треба да се избегне ќе изминатите границите на вашиот низа. [Студент] Па еве кога отидовме минатото границите на својата низа - [Бауден] Тоа е каде што работите тргнат наопаку. >> [Студент] О, во ред. Онолку колку што ќе остане во рамките на меморијата распределени за вашиот низа, ти си во ред. Но Ц не не грешка проверка. Ако го направам низа [1000], тоа ќе задоволство само менувате она што се случува - Тоа важи до почетокот на низата, тогаш тоа оди 1000 позиции по и ги става на 0. Тоа не прави никаква проверка дека ох, тоа не всушност имаат 1000 работи во неа. 1000 е далеку од она што треба да се менува, додека Јава или нешто ќе добиете низа надвор од границите индекс или индекс надвор од границите исклучок. Тоа е зошто многу повисоко ниво јазици имаат овие работи каде што ако се оди подалеку од границите на низата, ќе пропадне така што не може да се променат работите од под вас а потоа работите одат многу полошо отколку само добивање исклучок велејќи дека ќе отиде подалеку од крајот на низата. [Студент] И така треба да имаме само смени <= само > [Бауден] Да. Тоа треба да биде > [Студент] Десен. Повеќе прашања? Во ред. [Студент] Имам едно прашање. >> Да. [Студент] Што е вистинската низа променлива? [Бауден] Како што е низа? Низа сам по себе е симбол. Тоа е само на адресата на почетокот на 20 бајти дека ние сме референцирање. Можеш да мислиш за тоа како покажувач, но тоа е постојана покажувач. Штом работите да се состави, променлива низа веќе не постои. [Студент] Па како не го најдете на големината на низата? Големина на низата се однесува на големината на тој блок дека тој знак се однесува. Кога правам нешто како printf ("% p \ n", низа); ајде да ја стартувате. Што јас само направив погрешно? "Низа" низа прогласи тука. О, се тука. Ѕвекот е умен, а тоа се случува да забележите дека јас прогласи низа како 5 елементи но јас сум индексирање во позиција 1000. Тоа може да го направи тоа затоа што овие се само константи. Тоа само може да оди толку далеку во забележи дека јас одам надвор од границите на низата. Но, забележи порано кога имавме јас се неточни, тоа не може да се утврди колку вредности би можел да ја преземе, така што не може да се утврди дека ќе одам по завршувањето на низата. Тоа е само ѕвекот биде умен. Но сега се направи buggy4. Па што друго правам погрешно? Имплицитно наведува библиотека функција 'printf'. Одам да сакаат да # се . Во ред. Сега работи buggy4. Печатење на вредност на низата како што го направив тука, печатење тоа како покажувач отпечатоци нешто што личи ова - bfb8805c - што е некои адреса тоа е во магацинот-носталгичната регионот. Низа себе е како покажувач, но тоа не е вистински покажувач, од редовен покажувачот можеме да го промениме. Низа е само некои константа. На 20 блокови од меморијата на проектот на адреса 0xbfb8805c. Значи bfb8805c преку оваа адреса +20--или Претпоставувам -20 - е сите меморија распределени за оваа низа. Низа, променливата по себе не се чуваат насекаде. Кога сте составувањето, компајлерот - рака бран во него - но компајлерот само ќе го користи кога тоа го знае низа да биде. Таа не знае каде таа низа започнува, и така да се секогаш само се прават работите во однос на неутрализира од тоа почеток. Тоа не треба променлива себе да претставува низа. Но, кога ќе се направи нешто како int * P = array, а сега p е покажувач што укажува дека низа, и сега стр всушност постои на магацинот. Јас сум слободен да се промени стр. Можам да направам p = Примерок. Значи тоа првично посочи низа, а сега тоа укажува на некои простор на грамада. Не можам низа = Примерок. Ако ѕвекот е паметен, тоа ќе викне во мене право надвор од лилјак. Всушност, јас сум прилично сигурен gcc би го направил тоа премногу. Значи низа тип "int [5] 'не е преносливи. Не можете да доделите нешто да се низа тип бидејќи низа е само постојана. Тоа е симбол кој референци оние 20 бајти. Не можам да ја промените. [Студент] А каде е големината на низата чуваат? [Бауден] Тоа не е се чуваат насекаде. Тоа е времето кога тоа е составувањето. Значи, каде што е големината на низата чуваат? Можете да користите само sizeof (низа) во внатрешноста на функција која низата е се прогласи. Значи, ако јас се направи некои функција, foo, а јас не (int низа []) printf ("% d \ n", sizeof (низа)); а потоа овде јас го нарекувам foo (низа); внатрешноста на оваа функција - да го работи. Ова е ѕвекот биде умен повторно. Тоа ми кажува дека sizeof на низа параметар за функцијата ќе се врати големината на "int *. Ова ќе биде грешка ако тоа не е она што сакав да се случи. Да, всушност го исклучите Werror. Предупредување. Предупредувања се во ред. Тоа сепак ќе се собере колку што има предупредување. . / A.out се случува да се печати 4. Предупредувањето што се остварени е јасен показател на она што не беше во ред. Ова int низа е само ќе печати sizeof (int *). Дури и ако го ставам низа [5] овде, тоа е сепак само ќе печати sizeof (int *). Така што веднаш штом ќе го помине во функција, разликата меѓу низи и совети е непостоечки. Ова се случува да биде низа што беше прогласена на магацинот, но штом ќе помине таа вредност, тоа 0xbf бла, бла, бла во оваа функција, тогаш ова покажувач укажува дека низа на магацинот. Тоа значи дека sizeof се однесува само во функција која беше прогласена за низа, што значи дека кога ќе се составувањето на оваа функција, кога ѕвекот оди преку оваа функција, го гледа низа е int низа на големината 5. Па тогаш го гледа sizeof (низа). Па, тоа е 20. Тоа е всушност како sizeof основа работи на речиси сите случаи. Sizeof не е во функција, тоа е оператор. Вие не јавите на sizeof функција. Sizeof (int), компајлерот само ќе го преведе дека до 4. Добив тоа? Во ред. [Студент] Па што е разликата помеѓу sizeof (низа) во главниот и во foo? Тоа е затоа што си ти што зборуваш sizeof (низа), кој е од тип int *, со оглед на низа овде долу не е од тип int *, тоа е int низа. [Студент] Значи, ако сте имале на параметар во низа [] наместо int * низа, тоа би значело дека сеуште може да се промени низа, бидејќи сега тоа е покажувачот? [Бауден] Како тоа? >> [Студент] Да. Можете да ги менувате низа во функција сега? [Бауден] Вие може да се промени низа во двата случаи. Во двата од овие случаи можете слободно да се каже низа [4] = 0. [Студент] Но, можете да направите низа точка за нешто друго? [Бауден] О. Да. Во секој случај - >> [студент] Да. [Бауден] Разликата помеѓу низа [] и int * низа, не постои. Исто така можете да добиете некои мултидимензионална низа тука за некои удобен синтакса, но тоа е сепак само покажувач. Ова значи дека јас сум слободен да го стори низа = Примерок (sizeof (int)); и сега укажуваат на друго место. Но исто како и како тоа функционира засекогаш и секогаш, промена на оваа низа со тоа што укажуваат на нешто друго не се менува оваа низа долу тука, бидејќи тоа е копија на аргументот, тоа не е покажувачот во тој аргумент. И всушност, само што повеќе индикации дека тоа е иста - ние веќе видовме што печатење низа отпечатоци - што ако ние печати адресата на низа или адресата на адреса на низата на било кој од овие? Да се ​​игнорира оваа. Во ред. Ова е во ред. Тоа е сега работи. / A.out. Печатење низа, а потоа печати на адресата на низата, се иста работа. Низа едноставно не постои. Знае кога сте печатење низа, сте печатење симбол кој се однесува на оние 20 бајти. Печатење на адреса на низата, добро, низа не постои. Тоа не мора на адреса, така што само отпечатоци адресата на оние 20 бајти. Веднаш штом ќе се собере надолу, како во вашиот Составувач buggy4. / A.out, низа е непостоечки. Совети постои. Низи не. На блокови од меморијата претставува низа сè уште постојат, но променлива низа и променливи од тој вид не постојат. Оние се како главните разлики помеѓу низи и совети се што е можно да се направи функциски повици, не постои никаква разлика. Но во внатрешноста на функција која е прогласена низата себе, sizeof функционира поинаку бидејќи сте печатење со големина на блокови наместо на големината на видот, и не можете да го промените, бидејќи тоа е симбол. Печатење на работа и адресата на работа отпечатоци истото. И тоа е доста тоа. [Студент] Може да се каже дека еден повеќе време? Јас може да се пропушти нешто. Печатење низа и адреса на низа отпечатоци истото, а доколку ги отпечатите покажувач наспроти адреса на покажувачот, една работа отпечатоци адресата на она што сте укажува на, Од друга отпечатоци на адреса на покажувачот на магацинот. Можете да го промените покажувач, вие не може да го промени низа симбол. И sizeof покажувачот се случува да се печати големината на таа покажувачот тип. Значи int * P sizeof (м) се случува да се печати 4, но int низа [5] печати sizeof (низа) се случува да се печати 20. [Студент] Значи int низа [5] ќе печати 20? >> Да. Тоа е зошто во внатрешноста на buggy4 кога беше порано да биде sizeof (низа) ова беше правам <20, што не е она што сакав. Ние сакаме з <5. >> [Студент] Во ред. [Бауден] А потоа веднаш штом ќе почнете да поминува во функциите, ако ние не int * P = array; внатрешноста на оваа функција, ние во основа може да се користи p и низа на ист начин, освен за проблемот sizeof и на менување на проблемот. Но p [0] = 1; е иста како вели низа [0] = 1; И штом се каже foo (низа); или foo (p); внатрешноста на функција foo, ова е истиот повик двапати. Не постои никаква разлика помеѓу овие два повици. Секој добар за тоа? Во ред. Имаме 10 минути. Ние ќе се обидеме да се добие преку овој Хакер Typer програма, овој веб-сајт, кој излезе минатата година или така нешто. Тоа е само би требало да биде како што пишувате случајно и тоа отпечатоци од - Без оглед на датотеката се случи да се вчитани е она што изгледа како што го пишувате. Тоа изгледа како некој вид на оперативен систем код. Тоа е она што ние сакаме да се имплементира. Вие треба да имаат бинарна извршна име hacker_typer кој ги зема во еден аргумент, датотеката на "хакер тип." Вклучување на извршна треба да го исчистите екранот а потоа печати од еден лик од положениот во датотека секој пат кога корисникот ќе ја притиска копче. Значи она што клучните ќе притиснете, треба да фрлаат и наместо печати лик од датотека тоа е аргумент. Јас доста ќе ви кажам што работите ние ќе треба да се знае се. Но, ние сакаме да се провери од библиотека termios. Јас никогаш не го користеле овој библиотека во целиот мој живот, така што има многу минимален цели. Но, ова ќе биде библиотеката може да се користат да се фрлаат ликот ќе го погоди кога ќе се пишува во стандард внатре Значи hacker_typer.c, и ние ќе сакате да # се . Гледајќи човекот страница за termios - I'm Сомневајќи се дека е терминалот оперативен систем или нешто - Не знам како да го прочита. Гледајќи ова, се вели да се вклучат овие додадени фајлови: 2, така што ќе го направи тоа. Првото нешто што прво, ние сакаме да се земе во еден аргумент, кој е датотека што треба да се отвори. Значи она што сакам да направам? Како можам да се провери да се види имам еден аргумент? [Студент] Ако argc изнесува. >> [Бауден] Да. Значи, ако (argc = 2!) Printf ("Употреба:% s [датотеката да се отвори]"). Па сега ако јас ја извршите оваа без обезбедување на вториот аргумент - О, ми треба нова линија - ќе видите што вели употреба:. / hacker_typer, и потоа вториот аргумент треба да биде на датотека Сакам да се отвори. Сега она што можам да направам? Сакам да чита од оваа датотека. Како можам да прочитам од датотеката? [Студент] Ти ја отвори првата. >> Да. Значи fopen. Што значи fopen изгледа? [Студент] Име. >> [Бауден] Име ќе биде avg [1]. [Студент] И тогаш она што сакате да правите со неа, па - >> [Бауден] Да. Значи, ако не се сеќавам, ти само може да го направи човекот fopen, каде што тоа се случува да биде const char * патека каде што патот е името на датотеката, const char * режим. Ако се случи да не се сетам што владата е, тогаш можете да барате режим. Внатрешноста на човекот страници, ликот црта е она што можете да го користите за да барате работи. Па јас тип / режим за пребарување на владата. n и n се она што можете да го користите за да кружите низ пребарување натпревари. Еве што вели аргументот на владата укажува на низа почнувајќи со еден од следниве секвенци. Значи R, отворен текст датотека за читање. Тоа е она што сакате да го направите. За читање, и сакам да ги чувате тоа. Нешто се случува да биде на датотека *. Сега она што сакам да направам? Дај ми една секунда. Во ред. Сега она што сакам да направам? [Студент] Проверете дали тоа е NULL. >> [Бауден] Да. Во секое време ќе отворите некоја датотека, бидете сигурни дека сте успешно во можност да го отворите. Сега сакам да го правам тоа termios работи каде што сакам прво да го прочитате мојот тековните поставувања и спаси оние во нешто, тогаш сакам да ги променам моите опции да се фрлаат било карактер што го пишувате, и тогаш сакам да се ажурираат овие поставувања. А потоа на крајот на програмата, сакам да се промени се враќам на оригиналниот поставувања. Па struct ќе биде од типот termios, а јас ќе одам да сакате две од нив. Првиот се случува да ми биде current_settings, а потоа тие ќе ми биде hacker_settings. Прво, јас одам да сакате да ја спаси мојата тековните поставувања, тогаш јас ќе одам да сакате да го обновите hacker_settings, а потоа начинот на кој на крајот на мојата програма, сакам да се вратите на тековните поставувања. Значи заштеда на тековните поставувања, начинот на кој функционира, ние човек termios. Можеме да видиме дека имаме оваа int tcsetattr, int tcgetattr. Јас помине во termios struct од страна на неговиот покажувач. Начинот на кој тоа ќе изгледа е - I've веќе заборавени што функцијата бил повикан. Копирате и залепите. Значи tcgetattr, тогаш сакам да помине во struct дека сум спасување на информации, која ќе биде current_settings, и првиот аргумент е датотека descriptor за нешто што сакате да ја зачувате атрибути. Што опишувач на датотека е е како и секој пат кога ќе отворите некоја датотека, таа добива опишувач за датотеката. Кога ќе fopen avg [1], таа добива опишувач на датотека која сте референцирање кога сакаш да прочита или запише на него. Тоа не е опишувач на датотека сакам да се користи тука. Постојат три датотека дескриптори имате по дифолт, кои се стандардни во, стандарден излез, и стандардна грешка. По дифолт, мислам дека тоа е стандард во е 0, стандарден излез е 1, и стандардна грешка е 2. Значи она што сакам да ги промените поставките на? Сакам да ги промените поставките на секогаш кога ќе се погоди некој лик, Сакам да фрлаат дека карактерот далеку наместо печатење до екранот. Што поточно - стандард во, стандарден излез, или стандардна грешка - реагира на нешта кога пишувате на тастатурата? >> [Студент] Стандардна внатре >> Да. Па јас или да направите 0 или можам да направам stdin. Јас сум добивање на current_settings на стандардни внатре Сега сакам да се ажурираат овие поставувања, па прво ќе го копирате во hacker_settings што ми current_settings се. И како structs работа е тоа само ќе копија. Оваа копии сите полиња, како што би очекувале. Сега сакам да се ажурира некои од полињата. Гледајќи termios, вие ќе треба да се чита преку многу на овој само за да видам што ќе сакате да барате, но знамиња сте ќе сакате да се погледне за се ехо, па ехо ехо внесување карактери. Прво сакам да поставите - I've веќе заборавени што полиња се. Тоа е она што struct изгледа. Значи режими мислам дека сакате да го промените. Ние ќе се погледне на решение да бидете сигурни дека е она што сакате да го промените. Ние сакаме да се промени lflag со цел да се спречи потреба да се погледне преку сите овие. Ние сакаме да се смени локалниот режими. Вие ќе треба да се чита преку целата оваа работа да се разбере каде што припаѓа дека сакаме да се промени. Но, тоа е во внатрешноста на локални режими каде што сте ќе сакате да го промени тоа. Значи hacker_settings.cc_lmode е она што се вика. c_lflag. Ова е местото каде што ќе го добиеме во bitwise оператори. Ние сме вид на надвор од времето, но ние ќе поминат низ вистински брз. Ова е местото каде што ќе го добиеме во bitwise оператори, каде што мислам дека реков едно време одамна дека секогаш кога ќе почнете да се занимаваат со знамиња, сте ќе биде со користење на bitwise оператор многу. Секој малку на знамето одговара на некој вид на однесување. Па еве, ова знаме има еден куп на различни нешта, каде што сите од нив значат нешто различно. Но, она што сакам да направите е само да го исклучите малку што одговара на ехо. Значи да се претвори дека надвор правам & = ¬ ЕЦХО. Всушност, мислам дека тоа е како tECHO или нешто. Јас сум само случува да се провери повторно. Можам да го termios. Тоа е само ехо. ЕЦХО се случува да биде една малку. ¬ ЕЦХО ќе значи сите битови се постави на 1, што значи дека сите знамиња се поставени на точно освен за ЕЦХО малку. Со завршува мојата локална знамиња со тоа, значи сите знамиња кои се моментално поставено на true уште ќе биде поставена на true. Ако мојата ЕЦХО знаме е поставено на true, тогаш ова е нужно наместено како FALSE на ЕЦХО знаме. Значи оваа линија од кодот само се исклучува ЕЦХО знаме. Другите линии на код, јас само ќе ги ископирате во интерес на времето, а потоа објасни нив. Во растворот, рече тој 0. Тоа е можеби подобро да се експлицитно се каже stdin. Забележете дека јас сум исто така, прави ЕХО | ICANON тука. ICANON се однесува на нешто посебно, што значи канонски режим. Што канонски режим значи обично кога сте пишување од командната линија, стандард во не ги обработува ништо додека не го погоди линија. Па кога ќе се GetString, ќе напишете еден куп работи, а потоа ќе го погоди линија. Тоа е кога е испратена до стандард внатре Тоа е стандардно. Кога ќе го исклучите канонски владата, сега секој лик ќе го притиснете копчето е она што се преработува, која обично е вид на лошо, бидејќи тоа е бавен за обработка на овие работи, кој е зошто тоа е добро да се амортизираат во целиот линии. Но сакам секој лик да бидат обработени бидејќи јас не сакам тоа да се чека за мене да ја погоди линија пред обработува сите ликови сум бил пишување. Ова се исклучува канонски режим. Овој материјал само значи кога тоа всушност обработува карактери. Ова значи процесот на нив веднаш, штом јас сум ги пишувате, процесот на нив. И ова е функција која е ажурирање на моите опции за стандард во, и TCSA средства го направите токму сега. Другите опции се почека до сè што е во моментов на струја се обработува. Тоа навистина не е важно. Само во моментов ги променам моите опции за да биде она што во моментов е во hacker_typer_settings. Претпоставувам дека тоа се нарекува hacker_settings, па ајде смени тоа. Промени сè до hacker_settings. Сега на крајот на нашата програма ние ќе сакате да се вратите за она што во моментов е во внатрешноста на normal_settings, кој се случува само да изгледа како и normal_settings. Забележиш јас не се променети било кој од моите normal_settings бидејќи првобитно добива. Потоа само да ги вратиме назад, јас ги помине назад на крајот. Ова е ажурирање. Во ред. Сега во внатрешноста од овде јас само ќе се објасни го кодот во интерес на времето. Тоа не е дека многу код. Гледаме дека чита карактер од датотеката. Ние го нарече ѓ. Сега можете човек fgetc, но како fgetc се случува на работа е само тоа нема да се врати на ликот дека сте само читаат или EOF, што одговара на крајот на датотеката или некои грешка се случува. Ние сме looping, продолжувајќи да се чита еден карактер од датотеката, додека ние сме снема карактери да читаат. И додека ние го правиме тоа, ние се чека на еден лик од стандардните внатре Секој пат кога ќе напишете нешто на командната линија, тоа е читање во лик од стандардните внатре Потоа putchar е само ќе се стави на знак читаме се тука од датотеката до стандарден излез. Можете да човек putchar, но тоа е само ставање до стандарден излез, тоа е печатење на тој лик. Вие исто така може само направете printf ("% c", в); истата идеја. Тоа се случува да се направи најголемиот дел од нашата работа. Последно нешто што сте ќе сакате да направите е само запишам нашите датотека. Ако не запишам, тоа е меморија излегуваат во јавноста. Ние сакаме да запишам во датотеката што првично се отвори, и мислам дека тоа е тоа. Ако се направи тоа, јас веќе доби проблеми. Ајде да видиме. Она што не го жалат? Очекува "int", но аргумент е од типот "struct _IO_FILE * '. Ќе видиме дали тоа функционира. Дозволено само во C99. Augh. Океј, се направи hacker_typer. Сега ние се повеќе корисни описи. Значи употребата на непријавена идентификатор 'normal_settings. Јас не го нарекуваат normal_settings. Јас го нарече current_settings. Значи, да се промени сето тоа. Сега поминува аргумент. Ќе се направи овој 0 за сега. Во ред. . / Hacker_typer cp.c. Јас, исто така не го исчистите екранот на почетокот. Но може да се погледне назад на последниот проблем во собата да се види како ќе го исчистите екранот. Тоа е само печатење некои карактери Иако ова е тоа што сакам да го направам. Во ред. И размислување за тоа зошто ова треба да биде 0, наместо на stdin, кои треба да се # define 0, ова се жали дека - Пред кога реков дека има датотека дескриптори, но тогаш вие исто така имате СЛИКА *, на опишувач на датотека е само еден број, додека датотека * има еден куп на работи поврзани со неа. Причината ние треба да се каже 0 наместо stdin е дека stdin е датотека * што укажува на нешто што е референцирање датотека descriptor 0. Па дури и до тука и кога правам fopen (avg [1], јас сум добивање на датотека * назад. Но, некаде во таа датотека * е нешто што одговара на опишувач на датотека за таа датотека. Ако се погледне на човекот страница за отворени, па мислам дека ќе треба да направите man 3 отворен - Не бе - човек 2 отворени - Да. Ако се погледне на страната за отворен, отворен е како пониско ниво fopen, и тоа е враќање на вистинските опишувач за датотеката. fopen прави еден куп на работи на врвот на отворено, кои наместо враќање токму тоа опишувач на датотека се враќа целата датотека * покажувачот внатрешноста на која е нашата мала опишувач за датотеката. Па стандард во однесува на Датотека * работа, додека 0 однесува само опишувач на датотека стандард во себе. Прашања? [Се смее] дувна преку тоа. Во ред. Ние завршиш. [Се смее] [CS50.TV]