[Powered by Google Translate] [SECTION 5: weniger komfortabel] [Nate Hardison, Harvard University] [Dies ist CS50.] [CS50.TV] So willkommen zurück, Jungs. Willkommen in Abschnitt 5. An diesem Punkt, nach Abschluss Quiz 0 und gesehen zu haben, wie du getan hast, hoffentlich ein gutes Gefühl, weil ich war sehr beeindruckt von den Partituren in diesem Abschnitt beeindruckt. Für unsere Online-Zuschauer, wir hatten ein paar Fragen über die letzten zwei Probleme auf das Problem set - oder auf das Quiz, eher. So werden wir über die wirklich schnell gehen, so dass jeder sieht, was passiert und wie durch die aktuelle Lösung nicht nur betrachten die Lösung selbst zu gehen. Wir werden in den letzten paar Probleme wirklich schnell gehen, 32 und 33. Just, kann wieder so, dass die Online-Zuschauer sehen dies. Wenn Sie Ihr Problem 32, die auf Seite 13 ist wiederum, 13 von 16, liegt das Problem 32 alles über Swaps. Es ging um das Wechseln von zwei ganzen Zahlen. Es ist das Problem, dass wir hatten über ein paar Mal in der Vorlesung gegangen. Und hier, was wir bitten Sie tun müssen, ist eine schnelle Speicher-Trace. Um die Werte der Variablen zu füllen, wie sie auf dem Stapel sind da der Code durch diesen Swap-Funktion geht. Insbesondere, was wir gerade sehen - ich werde dieses iPad legte - insbesondere, was wir suchen, ist diese Zeile nummeriert 6 hier richtig. Und es ist 6 für nur Kontiguität mit dem vorherigen Problem nummeriert. Was wir wollen, ist anzuzeigen oder beschriften den Zustand des Speichers wie es ist zu dem Zeitpunkt, wenn wir diese Linie 6 auszuführen, was effektiv eine Rückkehr von unserer Swap-Funktion finden Sie hier. Wenn wir hier unten scrollen, sahen wir, dass die Adressen der alles im Speicher für uns zur Verfügung gestellt. Dies ist sehr Schlüssel, wir kommen wieder, um es in einem Moment. Und dann hier unten am Boden, hatten wir eine kleine Erinnerung Diagramm, dass wir gehen, um zu verweisen. Ich habe tatsächlich das getan auf meinem iPad. Also werde ich hin und her wechseln zwischen dem iPad und dieser Code nur als Referenz. Lassen Sie uns beginnen. Lassen Sie uns zuerst auf den ersten paar Zeilen der wichtigsten hier zu konzentrieren. Um zu beginnen, werden wir x um 1 und y initialisieren 2. Also haben wir zwei Integer-Variablen haben, sind sie beide gehen auf den Stapel gelegt werden. Wir werden eine 1 und eine 2 in sie setzen. Also, wenn ich umdrehen zu meinem iPad, hoffentlich, mal sehen - Apple TV Spiegelung, und es geht los. Okay. Also, wenn ich umdrehen zu meinem iPad, Ich möchte x und y bis 1 zu 2 zu initialisieren. Wir machen das ganz einfach durch Schreiben einer 1 in das Feld x und eine 2 in das Feld y. Ziemlich einfach. So, jetzt gehen wir zurück zu dem Laptop, zu sehen, was als nächstes passiert. Also das nächste Zeile ist, wo die Dinge schwierig zu bekommen. Wir übergeben die Adresse von x und die Adresse von y als der Parameter a und b der Swap-Funktion. Die Adresse von x und der Adresse y gibt Dinge, die wir nicht berechnen können, ohne Bezugnahme auf diese Stichpunkte rechten hier unten. Und zum Glück, sagen die ersten zwei Stichpunkte uns genau das, was die Antworten sind. Die Adresse des im Speicher x ist 10, und die Adresse von y im Speicher 14 ist. Das sind also die Werte, die in so bekommen weitergegeben a und b bis oben in unserer Swap-Funktion. Also noch einmal, Wechsel zurück zu unserem Diagramm, kann ich eine 10 in einem und eine 14 in b. Nun ist dieser Punkt, wo wir mit der Swap. So blätterte zurück an den Laptop wieder sehen wir, dass die Art und Weise der Swap funktioniert Ich erste Dereferenzierung ist ein und speichern das Ergebnis in tmp. So Dereferenzierungsoperator sagt: "Hey. Behandeln Sie die Inhalte der Variable a als Adresse. Zum, was ist an dieser Adresse gespeichert, und laden Sie es. " Was Sie laden aus dem variable wird in unsere tmp-Variable gespeichert werden. Flipping zurück zum iPad. Wenn wir 10 Adresse zu gehen, wissen wir, dass die Adresse 10 die varible x weil wir uns Punkt, dass die Adresse von x im Speicher 10 ist gesagt. So können wir dorthin gehen, erhalten Sie den Wert davon, die 1 ist, wie wir auf unserer iPad sehen und dass in tmp laden. Auch dies ist nicht die endgültige Inhalt. Wir gehen zu Fuß durch und wir zu unserem letzten Zustand des Programms am Ende bekommen. Aber jetzt haben wir den Wert 1 in tmp gespeichert. Und es gibt eine kurze Frage hier. [Alexander] Ist das Dereferenzierungsoperator - das ist nur der Stern direkt vor der Variablen? >> Ja. So Dereferenzierungsoperator, als wir zurück blättern, um unseren Laptop wieder ist dieser Stern direkt vor. In diesem Sinne ist es - Sie kontrastieren mit der Multiplikations-Operator das erfordert zwei Dinge, die Dereferenzierungsoperator ist eine unäre Operator. Nur um einen Wert angewandt werden wie auf einem binären Operator Gegensatz wo Sie zwei unterschiedliche Werte gelten. Also das ist, was passiert in dieser Linie. Wir luden den Wert 1 und lagerte sie in unsere temporäre Integer-Variable. Die nächste Zeile, speichern wir den Inhalt von b in - oder vielmehr, speichern wir die Inhalte, die b wird auf den Hinweis in den Ort, wo ein zu zeigt. Wenn wir das von rechts nach links zu analysieren, werden wir zu dereferenzieren b gehen, werden wir 14 anzugehen, werden wir die ganze Zahl, die es zu packen, und dann werden wir an die Adresse 10 gehen, und wir werden das Ergebnis unserer Dereferenzierung von b in diesem Raum zu werfen. Flipping zurück zu unserem iPad, wo wir dies ein wenig konkreter werden, könnte es helfen, wenn ich Zahlen auf alle Adressen hier schreiben. So wissen wir, dass bei y wir an der Adresse 14 sind, ist x an der Adresse 10. Als wir bei b beginnen, werden wir dereference b, werden wir den Wert 2 greifen. Wir werden diesen Wert zu greifen, denn das ist der Wert, der an der Adresse 14 lebt. Und wir werden es in die Variable, die an der Adresse 10 lebt setzen, das ist genau dort, entsprechend unserer Variablen x. So können wir tun, ein wenig zu überschreiben hier wo wir loswerden unserer 1 und stattdessen schreiben wir ein 2. So ist alles schön und gut in der Welt, obwohl wir überschrieben x hab jetzt. Wir haben x alten Wert in unserer tmp-Variable gespeichert. So können wir den Swap mit der nächsten Zeile zu vervollständigen. Flipping zurück zu unserem Laptop. Jetzt bleibt nur die Inhalte nehmen aus unserer temporären Integer-Variable und speichert sie in der Variablen, die an die Adresse, die b hält lebt. Daher freuen wir uns, um effektiv dereference b gehen, um den Zugriff auf die Variablen zu erhalten das ist die Adresse, die b hält darin, und wir werden den Wert, den tmp in sie halten zu stopfen. Flipping zurück zum iPad noch einmal. Ich kann diesen Wert hier zu löschen, 2, und stattdessen werden wir die 1 direkt hinein kopieren. Dann wird die nächste Zeile, die ausgeführt wird, natürlich - wenn wir wieder klappen mit dem Laptop - ist dieser Punkt 6, das ist der Punkt, an dem wir haben wollten unserem Diagramm vollständig ausgefüllt. So blätterte zurück zum iPad noch einmal, nur so können Sie sehen, das ausgefüllte Diagramm sieht man, dass man eine 10 in eine, eine in 14 b, a 1 in tmp, a 2 in x und in y ein 1 haben. Gibt es irgendwelche Fragen dazu? Bedeutet dies mehr Sinn machen, die über sie ging? Weniger Sinn? Hoffentlich nicht. Okay. Zeiger sind ein sehr heikles Thema. Einer der Jungs mit denen wir arbeiten ist eine sehr häufige Sprichwort: "Um Zeiger zu verstehen, müssen Sie zuerst verstehen, Zeiger." Was ich denke, ist sehr wahr. Es dauert eine Weile, bis sich daran zu gewöhnen. Die Ziehung von Bildern, zeichnen viel Speicher Diagramme wie dieses ein sehr hilfreich, und nach wandern Sie durch ein Beispiel nach dem nach dem Beispiel es wird beginnen, ein wenig mehr Sinn und ein wenig mehr Sinn und ein wenig mehr Sinn machen. Endlich, eines Tages wirst du alles haben komplett gemeistert. Haben Sie Fragen, bevor wir zum nächsten Problem? Gut. Also zurück blättern, um den Laptop. Das nächste Problem, das wir haben, ist Problem Nummer 33 auf Datei-I / O. Zoomen Sie in diesem ein wenig. Problem 33 - Ja? [Daniel] Ich hatte gerade eine kurze Frage. Dieser Stern, oder der Stern, es heißt Dereferenzierung, wenn Sie ein Sternchen vor dem Gebrauch. Wie heißt es, wenn Sie das kaufmännische, bevor benutzen? >> Das kaufmännische vor ist die Adreßoperator. Also lasst uns blättern wieder nach oben. Oops. Ich bin im Zoom-Modus, so kann ich nicht wirklich blättern. Wenn wir uns auf diesen Code sehr schnell hier, wieder geschieht dasselbe. Wenn wir diesen Code hier schauen, auf dieser Linie, wo wir das Gespräch zu tauschen, das kaufmännische ist einfach nur sagen "erhalten die Adresse, an die Variable x lebt." Wenn Ihr Compiler kompiliert den Code, es muss tatsächlich physisch markieren einen Platz im Speicher für alle Ihre Variablen zu leben. Und was kann der Compiler dann tun, wenn es alles zusammengestellt ist, sie weiß, "Oh, I x legte an der Adresse 10. habe ich y an der Adresse 14." Es kann dann in diese Werte für Sie zu füllen. So können Sie dann - kann es dann passieren diese in und Pass & y als gut. Diese Jungs bekommen die Adresse, sondern auch, wenn Sie geben sie in die Swap-Funktion, diese Art Information, diese int * genau hier, sagt dem Compiler, "Okay, wir gehen zu interpretieren diese Adresse als eine Adresse einer Integer-Variable." Als Adresse einer int ist, die sich von der Adresse eines Zeichenvariable weil ein int nimmt, auf einem 32-Bit-Maschine, nimmt 4 Byte Speicherplatz, während ein Charakter benötigt nur 1 Byte. So ist es wichtig zu wissen auch, was ist - was lebt, welche Art von Wert an der Adresse, die übergeben wurde leben Oder die Adresse, die Sie zu tun haben. So wissen Sie, wie viele Bytes an Informationen tatsächlich zu laden aus dem RAM. Und dann, ja, wurden diese Dereferenzierungsoperator, wie Sie fragen, geht und auf Informationen zugreift, an einer bestimmten Adresse. So ist es, so mit diesem eine Variable hier, behandeln Sie die Inhalte einer als Adresse, gehen an diese Adresse, und ziehen Sie, laden Sie in den Prozessor, Last in ein Register die tatsächlichen Werte oder der Inhalt, die unter dieser Adresse wohnen. Noch Fragen? Das sind gute Fragen. Es gibt eine Menge neue Terminologie zu. Es ist auch eine Art funky, sehen & und * an verschiedenen Orten. Gut. Also zurück zum Problem 33, Datei-I / O. Dies war eines jener Probleme, dass ich denke, ein paar Dinge passiert. One, es ist ein ziemlich neues Thema. Es wurde ziemlich bald vor dem Quiz präsentiert, und dann denke ich, es war ein bisschen wie eine jener Textaufgaben in Mathematik wo sie Ihnen eine Vielzahl von Informationen, aber man eigentlich nicht am Ende mit einer Tonne zu nutzen. Der erste Teil dieses Problems ist zu beschreiben, was eine CSV-Datei ist. Nun, eine CSV-Datei, nach der Beschreibung, ist eine durch Kommata getrennte Werte-Datei. Der Grund sind überhaupt interessant, und der Grund, die Sie jemals verwenden sie, ist, weil, wie viele von euch schon mal Sachen wie Excel verwendet? Abbildung meisten von euch haben, wahrscheinlich oder an einem gewissen Punkt in Ihrem Leben verwenden. Du wirst so etwas wie Excel. Um die Daten zu bekommen aus einer Excel-Tabelle oder tun jede Art der Verarbeitung mit sich, wenn man wollte ein C-Programm oder Python-Programm, Java-Programm schreiben, mit den Daten, die Sie dort gespeichert haben umzugehen, eine der gängigsten Methoden, um es aus in einer CSV-Datei. Und Sie können öffnen Sie Excel, und wenn du gehst, um den Dialog "Speichern unter", Sie können sich aus einer tatsächlichen CSV-Datei. Gut zu wissen, wie man mit diesen Dingen umzugehen. Wie es funktioniert, ist, dass es ähnlich ist - ich meine, es ist im wesentlichen imitiert eine Tabellenkalkulation, wo, wie wir hier sehen, in der ganz links fast Stück, Wir haben alle Nachnamen. So haben wir Malan, dann Hardison und dann Bowden, MacWilliam und dann Chan. Alle Nachnamen. Und dann ein Komma trennt die Nachnamen von den Vornamen. David, Nate, Rob, Tommy und Zamyla. Ich habe immer durcheinander Robby und Tom. Und dann, endlich, die dritte Spalte ist die E-Mail-Adressen. Sobald Sie das verstehen, ist der Rest des Programms recht einfach zu implementieren. Was wir getan haben, um diese gleiche Struktur in unser C-Programm zu imitieren ist haben wir eine Struktur verwendet. Wir spielen mit diesen ein wenig mehr als gut. Wir sahen sie zum ersten etwas in problematischen Satz 3, als wir mit den Wörterbüchern zu tun haben. Aber das Personal struct speichert einen Nachnamen, einen Vornamen und eine E-Mail. Genau wie unsere CSV-Datei wurde die Speicherung. Das ist also nur das Umwandeln von einem Format in ein anderes. Wir haben zum Konvertieren, in diesem Fall einen Stab struct in eine Leitung, eine durch Komma getrennte Linie, einfach so. Macht das Sinn? Ihr habt all das Quiz genommen, so dass ich denke, Sie haben zumindest hatte etwas Zeit, um darüber nachzudenken. In der Miete Funktion, fragt das Problem uns in zu nehmen - wir werden zoom in dieser ein wenig - nehmen an einem Mitarbeiter-Struktur, ein Mitarbeiter struct, mit dem Namen s, und fügen Sie den Inhalt unserer staff.csv Datei. Es stellt sich heraus, dass diese relativ einfach zu bedienen ist. Wir Art von herumspielen mit diesen Funktionen ein wenig mehr heute. Aber in diesem Fall ist die fprintf Funktion wirklich der Schlüssel. Also mit fprintf, können wir drucken, so wie du Jungs haben mit printf dieses gesamten Laufzeit. Sie können printf eine Zeile in einer Datei. Anstatt also nur machen die üblichen printf wo man ihm den Format-String und dann ersetzen Sie alle Variablen mit den folgenden Argumenten, mit fprintf ist Ihre erste Argument anstelle die gewünschte Datei zu schreiben. Wenn wir auf diese in das Gerät schauen, zum Beispiel, man fprintf, können wir den Unterschied zwischen printf und fprintf. Ich werde hier heranzoomen ein wenig. Also mit printf, geben wir ihm einen Format-String, und dann die folgenden Argumente sind alle Variablen für Ersatz oder Substitution in unserem Format-String. Während bei fprintf, ist das erste Argument der Tat diese Datei * bezeichnet ein Strom. Verschieben wieder über hier, um unsere Miete, haben wir bereits unsere Datei * stream eröffnet für uns. Das ist, was diese erste Zeile macht, es öffnet die staff.csv Datei, Es öffnet es im Append-Modus, und alles, was noch für uns zu tun hat ist schreiben Sie die personelle Struktur der Datei. Und mal sehen, will ich das iPad benutzen? Ich benutze das iPad. Wir haben Leere - lasst uns diese auf den Tisch legen, damit ich ein wenig besser schreiben können - Erlöschen mieten und es dauert ein Argument, ein Mitarbeiter Struktur namens s. Haben unsere Hosenträger, haben wir unsere Datei * abgerufenen Datei, wir haben unsere fopen Linie, die uns gegeben, und ich werde einfach schreiben Sie es als Punkte, da es bereits in der pedia. Und dann auf unserer nächsten Zeile, werden wir um einen Anruf zu fprintf machen und wir werden in der Datei passieren, dass wir drucken wollen, und dann unsere Format-String, die - Ich lasse euch mir sagen, wie es aussieht. Was meinen Sie, Stella? Weißt du, was der erste Teil der Format-String aussieht? [Stella] Ich bin mir nicht sicher. >> Fühlen Sie sich frei, um Jimmy zu fragen. Weißt du, Jimmy? [Jimmy] Wäre es nur der Letzte sein? Ich weiß nicht. Ich bin mir nicht ganz sicher. >> Okay. Wie wäre es, hat jemand bekommen diese korrekt auf der Prüfung? Nr. Ordnung. Es stellt sich heraus, dass hier alles, was wir tun müssen, ist, dass wir wollen, dass jeder Teil unserer Mitarbeiterstruktur um als eine Zeichenkette in unserer Datei ausgedruckt werden. Wir verwenden einfach die Zeichenfolge Ersetzungszeichen drei verschiedenen Zeiten, weil wir einen Nachnamen haben gefolgt von Komma und dann ein Vorname gefolgt von einem Komma, und schließlich die E-Mail-Adresse, die gefolgt wird - was nicht Montage auf meinem Bildschirm - aber es ist von einem Zeilenumbruch. So werde ich es einfach da unten schreiben. Und dann nach unserer Format-String, wir müssen nur die Substitutionen, die wir mit der Punktnotation zugreifen , die wir sahen in problematischen Satz 3. Wir können s.last, s.first und s.email in diesen drei Werten in unser Format-String ersetzen. Also, wie war das? Sinn? Ja? Nein? Möglicherweise? Okay. Die letzte Sache, die wir tun, nachdem wir gedruckt und habe nachdem wir unsere Datei geöffnet: wenn wir eine Datei geöffnet, wir haben immer daran zu erinnern, um es zu schließen. Denn sonst werden wir am Ende undicht den Speicher mit bis Dateideskriptoren. So um es zu schließen, welche Funktion verwenden wir? Daniel? [Daniel] fclose? >> Fclose, genau. So der letzte Teil dieses Problems war richtig schließen Sie die Datei mit dem fclose Funktion das sieht einfach so. Nicht zu verrückt. Cool. Also das ist Problem 33 am Quiz. Wir müssen auf jeden Fall mehr Datei-I / O kommen. Wir ein bisschen mehr zu tun in der Vorlesung, heute oder in Abschnitt heute weil das ist, was los ist, um den Großteil des kommenden pset bilden. Gehen wir von der Quiz an dieser Stelle. Ja? [Charlotte]] Warum fclose (Datei) anstelle von fclose (staff.csv)? >> Ah. Denn es stellt sich heraus, dass - so die Frage, was ist ein großer, warum, wenn wir fclose schreiben, schreiben wir fclose (Datei) star variable um den Dateinamen, staff.csv dagegen? Ist das richtig? Yeah. Werfen wir also einen Blick. Wenn ich wieder zurück in meinem Laptop, und lasst uns an der fclose Funktion anschauen. Also das fclose Funktion schließt einen Strom, und es dauert in der Zeiger auf den Strom, die wir schließen möchten, um den tatsächlichen Dateinamen, dass wir schließen möchten entgegen. Und das ist, weil hinter den Kulissen, wenn Sie einen Anruf zu tätigen, um fopen wenn Sie eine Datei öffnen, werden Sie tatsächlich Zuweisung von Speicher, um Informationen über die Datei speichern. So haben Sie Dateizeiger, die Informationen über die Datei hat, wie es geöffnet ist, seine Größe, wo Sie sind derzeit in der Datei, so dass man das Lesen und Schreiben von Anrufen an diesen bestimmten Ort innerhalb der Datei. Sie enden Schließen der Zeiger anstelle der Schließung des Dateinamens. Ja? [Daniel] Also, um Miete zu verwenden, würden Sie sagen - wie geht es bekommen die Eingabe des Benutzers? Hat fprintf wie GetString handeln im Sinne, dass es dann nur für die Benutzereingaben warten und bitten Sie, dies zu geben - oder warten Sie diese drei Dinge in eingeben, um? Oder benötigen Sie etwas verwenden, um Miete zu implementieren? >> Ja. So sind wir nicht - die Frage war, wie bekommen wir die Eingabe des Benutzers zur Umsetzung mieten? Und was wir hier haben, ist der Aufrufer mieten, bestanden in dieser Mitarbeiter struct mit all den Daten, die in der Struktur gespeicherten schon. So fprintf kann nur schreiben, dass die Daten direkt in die Datei. Es gibt keine Wartezeiten für Benutzereingaben. Der Benutzer hat bereits die Eingabe durch richtig, es in dieser Mitarbeiter struct gegeben. Und die Dinge natürlich brechen würde, wenn einer dieser Zeiger waren null, so scrollen wir wieder hier, und wir schauen Sie sich unsere Struktur. Wir haben String letzten, string erste, string E-Mail. Wir wissen jetzt, dass alle diejenigen, wirklich, unter der Haube sind char * Variablen. Das kann oder auch nicht zeigen, um null. Sie können den Speicher auf dem Heap gerichtet sein, vielleicht Speicher auf dem Stapel. Wir wissen nicht wirklich wissen, aber wenn dieser Zeiger sind null oder ungültig, , dass das definitiv abstürzen werden unser Verleih-Funktion. Das war etwas, das Art über den Umfang der Prüfung war. Wir sind nicht Sorgen darüber. Great. Okay. So bewegen auf dem Quiz. Schließen wir diesen Kerl, und wir gehen auf pset 4 aussehen. Also, wenn ihr Jungs am pset spec aussehen, wenn Sie darauf zugreifen können, cs50.net/quizzes, werden wir durch ein paar der Abschnitt Probleme heute gehen. Ich bin unten scrollen - Abschnitt von Fragen beginnt auf der dritten Seite des pset spec. Und der erste Teil fordert Sie auf, zu gehen und beobachten Sie die kurz auf Umleiten und Rohre. Welche war irgendwie kühl kurz, zeigt Ihnen einige neue, coole Befehlszeile Tricks, die Sie verwenden können. Und dann haben wir ein paar Fragen für Sie als gut. Diese erste Frage zu Streams, um die printf schreibt standardmäßig wir irgendwie auf nur ein wenig berührt vor einem Augenblick. Diese fprintf, dass wir gerade diskutieren erfolgt in einer Datei * stream als Argument. fclose erfolgt in einer Datei * stream als gut, und der Rückgabewert von fopen gibt Ihnen eine Datei * stream als gut. Der Grund, warum wir nicht diejenigen gesehen haben, wenn wir mit printf behandelt habe Denn printf hat einen Standardwert Stream. Und das Standard-Stream auf die sie schreibt finden Sie heraus, zu kurz. Also auf jeden Fall einen Blick auf sie. In der heutigen Abschnitt wollen wir ein wenig über GDB reden, da die mehr vertraut Sie mit ihm sind, desto mehr Übung mit ihm zu bekommen, desto besser können Sie sein, um tatsächlich jagen Bugs in Ihrem eigenen Code. Dies beschleunigt das Verfahren der Fehlersuche bis enorm. So mit printf, jedes Mal, wenn Sie das tun, um Ihren Code neu kompilieren müssen, Sie haben es wieder zu laufen, manchmal muss man die printf bewegen, Kommentar von Code, es dauert nur eine Weile. Unser Ziel ist es zu versuchen und zu überzeugen, dass mit GDB, Sie im Wesentlichen kann printf nichts an beliebiger Stelle in Ihrem Code und Sie müssen nie um sie neu zu kompilieren. Sie haben nie zu starten und zu halten erraten, wo die printf nächsten. Das erste, was zu tun ist, um diese Zeile zu kopieren und sich den Abschnitt Code aus der Bahn. Ich bin Kopieren dieser Codezeile, die sagt: "wget ​​http://cdn.cs50.net". Ich werde es zu kopieren. Ich gehe hin zu meinem Gerät, Verkleinern, so dass Sie sehen können, was ich tue, Einfügen es dort, und wenn ich Enter drücken, diese wget Befehl ist buchstäblich ein Web zu bekommen. Es wird nach unten ziehen diese Datei aus der Internet, und es wird sie in das aktuelle Verzeichnis zu speichern. Nun, wenn ich meinen aktuellen Verzeichnis Liste können Sie sehen, dass ich habe dieses section5.zip Datei direkt dort. Die Art und Weise, mit diesem Kerl umzugehen ist, sie zu entpacken, mit der Sie in der Befehlszeile zu tun, genau wie dieser. Section5.zip. Das wird sie zu entpacken, den Ordner für mich, Aufblasen der gesamte Inhalt, steckte sie in dort. So, jetzt kann ich in meinem Abschnitt 5 Verzeichnis mit dem Befehl cd zu gehen. Löschen Sie den Bildschirm mit klar. So löschen Sie den Bildschirm. Jetzt habe ich ein schönes, sauberes Terminal zu behandeln. Nun, wenn ich eine Liste aller Dateien, die ich in diesem Verzeichnis Sie sehen, dass ich habe vier Dateien: buggy1, buggy2, buggy3 und buggy4. Ich habe auch die entsprechenden. C Dateien. Wir gehen nicht auf den. C Dateien für jetzt aussehen. Stattdessen werden wir sie benutzen, wenn wir GDB öffnen. Wir haben sie immer um, so dass wir den Zugang zum eigentlichen Quellcode haben, wenn wir mit GDB sind, aber das Ziel dieses Teils des Abschnitts zu basteln, um mit GDB und sehen, wie wir können es verwenden, um herauszufinden, was falsch läuft mit jeder dieser vier fehlerhafte Programme. So sind wir gerade dabei, den Raum sehr schnell, und ich werde jemanden bitten, eine der fehlerhafte Programme laufen, und dann werden wir als Gruppe durch GDB gehen, und wir werden sehen, was wir tun können, um diese Programme zu beheben, oder zumindest erkennen, was falsch läuft in jedem von ihnen. Lasst uns beginnen hier mit Daniel. Laufen Sie buggy1? Mal sehen, was passiert. [Daniel] Er sagt, es ist eine Anwendung Fehler. >> Ja. Genau. Also, wenn ich buggy1 ausführen, bekomme ich einen Segmentation Fehler. An dieser Stelle könnte ich gehen und eröffnen buggy1.c, versuchen, herauszufinden, was falsch läuft, aber einer der abscheulichen Dinge über dieses Segment Fehlerfehler ist, dass es Ihnen nicht sagen, was Zeile des Programms Dinge tatsächlich falsch gelaufen ist und zerbrach. Sie Art müssen auf den Code schauen und außen mit guess herausfinden und prüfen oder printf, um zu sehen, was falsch läuft. Eines der coolsten Dinge über GDB ist, dass es wirklich, wirklich einfach ist um herauszufinden, die Linie, an der das Programm stürzt ab. Es ist jeden Cent wert, es zu benutzen, wenn auch nur für diese. So zum Hochfahren GDB, Typ I GDB, und dann gebe ich es den Pfad zur ausführbaren Datei, die ich ausführen möchten. Hier bin ich der Eingabe gdb ./buggy1. Drücken Sie die Eingabetaste. Gibt mir all diese Copyright-Informationen, und hier unten sehen Sie diese Zeile, die sagt: "Lesen Symbole aus / home / jharvard/section5/buggy1. " Und wenn alles gut geht, werden Sie sehen, es ausdrucken eine Nachricht, die wie folgt aussieht. Es wird Symbole zu lesen, es wird sagen: "Ich bin Lesen von Symbolen aus der ausführbaren Datei" und dann wird es dieses "done" Nachricht über hier zu haben. Wenn Sie eine andere Variante dieses sehen, oder sehen Sie es nicht finden konnten, die Symbole oder so ähnlich, was das bedeutet ist, dass Sie nur noch nicht die ausführbare Datei kompiliert einwandfrei. Wenn wir Programme für die Verwendung mit GDB zu kompilieren, müssen wir diese spezielle Option-g verwenden, und das ist standardmäßig möglich, wenn Sie Ihre Programme zu kompilieren, indem Sie einfach machen oder machen Buggy oder zu erholen, eine von denen. Aber wenn Sie manuell Kompilieren mit Clang, dann haben Sie zu gehen und beinhalten, dass-g-Flag. An diesem Punkt, dass wir jetzt haben unsere GDB Eingabeaufforderung Es ist ziemlich einfach, das Programm auszuführen. Wir können entweder laufen, oder wir können geben Sie einfach r. Die meisten GDB-Befehle können abgekürzt werden. Regel nur ein oder ein paar Briefe, die sehr schön ist. So Saad, wenn Sie r eingeben und die Eingabetaste drücken, was passiert? [Saad] Ich habe SIGSEGV, Segmentation Fault, und dann all diese Kauderwelsch. >> Ja. Wie wir auf dem Bildschirm sehen, gerade jetzt, und wie Saad sagte, wenn wir laufen oder r eingeben und Enter drücken wir immer noch die gleichen Segment Schuld. Also mit GDB nicht lösen unser Problem. Aber es gibt uns einige Kauderwelsch, und es stellt sich heraus, dass dieses Kauderwelsch tatsächlich sagt uns, wo es passiert. Um diese ein wenig zu analysieren, ist dieser erste Bit die Funktion, in der alles, was falsch ist. Es ist das __ strcmp_sse4_2, und es sagt uns, dass es in dieser Datei geschieht genannt sysdeps/i386, all dies wieder eine Art Katastrophe - aber die Leitung 254. Das ist ziemlich schwer zu analysieren. Normalerweise, wenn Sie sehen, Sachen wie diese, das bedeutet, dass es seg fehlgeschlagenes in einer der System-Bibliotheken. So etwas mit strcmp tun. Ihr habt strcmp gesehen. Nicht zu verrückt, aber bedeutet dies, dass strcmp defekt ist oder dass es ein Problem mit strcmp? Was denkst du, Alexander? [Alexander] Ist das - ist 254 die Linie? Und das - nicht das binäre, aber es ist nicht ihre Decken, und dann gibt es eine andere Sprache für jede Funktion. Ist das 254 in dieser Funktion, oder -? >> Es ist Zeile 254. Es sieht aus wie in diesem. S Datei, so ist es Assembler-Code wahrscheinlich. Aber ich denke, die dringender Sache ist, weil wir eine seg Fehler bekommen haben, und es sieht aus wie aus dem strcmp Funktion kommt, Bedeutet das dann, ist, dass strcmp gebrochen? Es sollte nicht, hoffentlich. Also nur weil du einen Segmentation Fault in einem der System-Funktionen, bedeutet in der Regel, dass Sie es nur noch nicht korrekt aufgerufen. Das schnellste, was zu tun, um herauszufinden, was eigentlich vor sich geht wenn Sie etwas Verrücktes wie diese finden, wenn Sie eine seg Fehler zu sehen, besonders wenn Sie ein Programm, das mit mehr als nur Main, ist eine Rückverfolgung verwenden. Ich abkürzen backtrace schriftlich bt, um den vollen Backtrace Wort entgegen. Aber Charlotte, was passiert, wenn Sie bt eingeben und Enter drücken? [Charlotte] Es zeigt mir, zwei Linien, Linie 0 und Linie 1. >> Ja. So Linie 0 und Linie 1. Dies sind die eigentlichen Stack-Frames, die derzeit im Spiel waren, als das Programm abgestürzt ist. Ausgehend von der obersten Rahmen, Rahmen 0, und Gehen zum untersten, der Rahmen 1 ist. Unsere obersten Rahmen ist das strcmp Rahmen. Sie können sich das denken, ähnlich wie dieses Problem, das wir gerade dabei auf das Quiz mit den Zeigern wurden, wo wir Stapelrahmen auf der Oberseite des Haupt Stapelrahmen tauschen, und wir hatten die Variablen, die Swap wurde am Anfang der Variablen, die wichtigsten wurde mit verwenden. Hier unsere Absturz passiert in unserem strcmp Funktion, die durch unsere Funktion aufgerufen wurde, und Backtrace gibt uns nicht nur die Funktionen, in denen die Dinge nicht, aber es ist auch uns mitzuteilen, wo alles von genannt wurde. Also, wenn ich scrollen Sie über ein wenig mehr nach rechts, können wir sehen, dass ja, wir on line 254 dieser strcmp-sse4.s Datei wäre. Doch der Ruf wurde buggy1.c, Zeile 6 gemacht. Das heißt also, wir tun können - ist, dass wir gerade gehen können Check-out und sehen, was los war am buggy1.c, Zeile 6. Auch hier gibt es ein paar Möglichkeiten, dies zu tun. Eine besteht darin, Ausfahrt aus GDB oder Ihren Code in einem anderen Fenster und Cross-Reference zu öffnen. Das an und für sich ist ziemlich praktisch, denn jetzt, wenn Sie im Büro Stunden sind und du hast eine seg Fehler und Ihre TF fragt sich, wo alles brach, Sie können einfach sagen: "Oh, Zeile 6. Ich weiß nicht, was los ist, aber etwas über die Leitung 6 verursacht mein Programm zu brechen. " Der andere Weg, es zu tun ist, können Sie diesen Befehl als Liste in GDB benutzen. Sie können auch abgekürzt mit l. Also, wenn wir l getroffen, was haben wir hier? Wir bekommen eine ganze Reihe von weird stuff. Dies ist die eigentliche Assembler-Code das ist in strcmp_sse4_2. Das sieht irgendwie funky, und der Grund, warum wir immer diese sind, weil gerade jetzt, GDB hat uns in Frame 0. So jederzeit betrachten wir Variablen, zu jeder Zeit schauen wir uns Quellcode, Wir sind am Quellcode suchen, die sich auf dem Stapelrahmen wir sind momentan in. Also, um etwas Sinnvolles zu bekommen, müssen wir zu bewegen, um einen Stack-Frames, mehr Sinn macht. In diesem Fall wäre der wichtigste Stapelrahmen machen ein wenig mehr Sinn, denn das war tatsächlich der Code, den wir geschrieben haben. Nicht die strcmp Code. Die Art und Weise zwischen den Bildern bewegen können, in diesem Fall, weil wir zwei haben, Wir haben 0 und 1, Sie tun, dass mit dem oben und unten Befehle. Wenn ich nach oben ein Rahmen, jetzt bin ich in der Haupt-Stack-Frame. Ich kann nach unten zurück zu gehen, wo ich war, wieder hinauf, wieder hinunter und wieder hinauf. Wenn Sie jemals tun Ihr Programm in GDB Sie einen Absturz erhalten, erhalten Sie den Backtrace, und Sie sehen, dass es in einigen Datei, die Sie nicht wissen, was los ist. Sie versuchen Liste der Code nicht bekannt vor, einen Blick auf Ihre Bilder und herauszufinden, wo Sie sind. Du bist wahrscheinlich in der falschen Stack-Frame. Oder zumindest, du bist in einem Stack-Frame, der nicht ein, dass Sie wirklich debuggen können. Jetzt, da wir in dem entsprechenden Stack-Frame sind, sind wir in den wichtigsten, Jetzt können wir mit dem Befehl list, um herauszufinden, was der Linie war. Und Sie können es sehen, es druckte es für uns hier richtig. Aber wir können Hitliste alle die gleiche, und die Liste gibt uns dieses schöne Ausdruck der eigentliche Quellcode, was los ist hier. Insbesondere können wir in Zeile 6 aussehen. Wir können sehen, was hier los ist. Und wie es aussieht machen wir einen String-Vergleich sind zwischen den String "CS50 rocks" und argv [1]. Etwas über diese stürzte. So Missy, hast du keine Gedanken darüber, was sein könnte denn hier los? [Missy] Ich weiß nicht, warum es abstürzt ist. >> Du weißt nicht, warum es abstürzt ist? Jimmy, alle Gedanken? [Jimmy] Ich bin nicht ganz sicher, aber das letzte Mal, dass wir Zeichenfolge vergleichen, oder strcmp, hatten wir wie drei verschiedene Fälle unter ihm. Wir haben nicht ein ==, ich glaube nicht, direkt in dieser ersten Zeile. Stattdessen wurde in drei getrennt und man war == 0, war <0, denke ich, und man war> 0. Also vielleicht so etwas? >> Ja. Also gibt es dieses Problem der machen wir den Vergleich richtig? Stella? Irgendwelche Gedanken? [Stella] Ich bin mir nicht sicher. >> Nicht sicher. Daniel? Gedanken? Okay. Es stellt sich heraus, was hier passiert, ist, wenn wir das Programm lief und wir haben die seg Fehler, wenn Sie das Programm zum ersten Mal, Daniel lief, hast du ihm keine Befehlszeilenargumente? [Daniel] No >> Nr. In diesem Fall, was ist der Wert von argv [1]? >> Es gibt keinen Wert. >> Richtig. Nun, es gibt keine entsprechenden String-Wert. Aber es gibt einen gewissen Wert. Was ist der Wert, der den dort gespeicherten wird? >> Eine Garbage Wert? >> Es ist entweder ein Garbage Wert oder, in diesem Fall, das Ende des argv-Array wird immer mit null beendet. So was tatsächlich wurde gespeichert ist null. Die andere Möglichkeit, dieses Problem lösen, anstatt zu Ende denken, ist zu versuchen, es auszudrucken. Dies ist, wo ich gesagt habe, dass die Verwendung GDB ist groß, weil Sie ausdrucken können alle Variablen, alle Werte, die Sie Verwendung dieses handy-dandy p Befehl. Also, wenn ich p eingeben und dann tippe ich den Wert einer Variablen oder den Namen einer Variablen, sagen, argc, sehe ich, dass argc 1 ist. Wenn ich den Ausdruck argv wollen [0], kann ich tun, einfach so. Und wie wir gesehen haben, argv [0] ist immer der Name des Programms, immer der Name der ausführbaren Datei. Hier sehen Sie es bekommen hat den vollständigen Pfad. Ich kann auch ausdrucken argv [1] und sehen, was passiert. Hier bekamen wir diese Art von mystischen Wert. Wir haben dieses 0x0. Angemeldet am Beginn der Laufzeit, wenn wir über Hexadezimalzahlen gesprochen? Oder dass kleine Frage am Ende des pset 0 darüber, wie 50 in hex dar? Die Art und Weise schreiben wir Hexadezimalzahlen in CS, nur um nicht zu verwechseln uns mit Dezimalzahlen, ist, dass wir immer voranstellen sie mit 0x. Also das Präfix 0x immer nur bedeutet, interpretieren die folgende Zahl als Hexadezimalzahl nicht als String, nicht als Dezimalzahl, nicht als Binärzahl. Da die Zahl 5-0 ist eine gültige Nummer in Hexadezimal. Und es ist eine Zahl in dezimaler, 50. So ist dies nur, wie wir eindeutig zu machen. So 0x0 Mittel hexadezimal 0, ebenfalls dezimal 0, binäre 0 ist. Es ist nur der Wert 0. Es stellt sich heraus, dass das ist, was null, ist eigentlich in Erinnerung. Null ist nur 0. Hier wird das Element an argv [1] gespeichert ist null. Also werden wir versuchen, unsere "CS50 rocks" String in eine leere Zeichenfolge zu vergleichen. So Dereferenzierung null, versucht, die Dinge auf null zuzugreifen, diese sind in der Regel werde eine Art Segmentation Fault oder andere schlimme Dinge passieren verursachen. Und es stellt sich heraus, dass strcmp nicht überprüfen, ob du in einem Wert, der null ist vergangen. Vielmehr, es geht voran, versucht, seine Sache zu tun, und wenn es Fehler seg, seg es Fehler, und es ist Ihr Problem. Du musst gehen zu beheben. Wirklich schnell, vielleicht, wie wir dieses Problem beheben? Charlotte? [Charlotte] Sie können mit if. Also, wenn argv [1] ist null, == 0, dann wieder 1 oder etwas [unverständlich]. >> Ja. Also das ist ein guter Weg, es zu tun, wie können wir überprüfen, um zu sehen, der Wert wir im Begriff, in strcmp passieren, argv [1], wird es null? Wenn es null, dann können wir sagen, okay, abzubrechen. Ein üblicher Weg, um dies zu tun ist, um die argc Wert zu verwenden. Sie können hier sehen, zu Beginn der Haupt-, wir weggelassen diesen ersten Test, dass wir in der Regel tun, wenn wir Befehlszeilenargumente verwenden, was zu testen, ob unsere argc Wert ist, was wir erwarten. In diesem Fall erwarten wir mindestens zwei Argumente, der Name des Programms plus einer anderen. Weil wir über das zweite Argument hier verwenden. So mit einer Art von Test vorher, bevor unsere strcmp Anruf dass die Tests, ob argv mindestens 2 ist, würde auch die gleiche Art von Ding. Wir können sehen, ob das funktioniert, indem Sie das Programm erneut. Sie können jederzeit starten Sie Ihr Programm in GDB, das ist wirklich schön. Sie können laufen, und wenn Sie übergeben Argumente, um Ihr Programm, Sie geben sie in, wenn Sie anrufen laufen, nicht, wenn Sie booten GDB. Auf diese Weise können Sie halten den Aufruf Ihres Programms mit verschiedenen Argumenten jeder Zeit. So laufen, oder wieder, ich kann r eingeben und mal sehen, was passiert, wenn wir "Hallo". Es wird immer gefragt, ob Sie es wieder von vorne beginnen wollen. Normalerweise wollen Sie es wieder von vorne beginnen. Und an diesem Punkt, es startet ihn wieder, druckt sie aus das Programm, das wir laufen, buggy1, mit dem Argument, hallo, und es gibt diese Norm aus, es sagt: "Sie können ein D bekommen", trauriges Gesicht. Aber wir haben nicht seg Fehler. Er sagte, dass Prozess beendet normal. Also das sieht ziemlich gut aus. No more seg Fehler, wir haben es geschafft Vergangenheit so wie es aussieht, das war in der Tat die seg Fehler Bug, den wir bekamen. Leider sagt es uns, dass wir immer ein D. Wir können gehen Sie zurück und schauen Sie sich den Code und sehen, was dort vor sich geht um herauszufinden, was war - warum es erzählt wurde, dass wir eine D. bekam Mal sehen, hier wurde diese printf sagen, dass Sie ein D. bekam Wenn wir Liste eingeben, wie Sie mit der Eingabe der Liste zu behalten, hält es Iteration nach unten durch das Programm, so zeigen Ihnen die ersten paar Zeilen des Programms. Dann wird es zeigen Ihnen die nächsten paar Zeilen, und das nächste Segment und das nächste Stück. Und es wird immer wieder versuchen zu gehen. Und nun bekommen wir auf "line Nummer 16 liegt außerhalb des Bereichs." Denn es hat nur 15 Zeilen. Wenn Sie zu diesem Punkt und Ihr fragen: "Was soll ich tun?" können Sie den Befehl help. Verwenden Sie helfen, und dann geben sie den Namen eines Befehls. Und du siehst die GDB gibt uns all diese Art von Sachen. Er sagt: "Ohne Argument, listet zehn Zeilen nach oder rund um den früheren Eintrag. List - listet die zehn Zeilen vor - " Lassen Sie uns also versuchen, mit Liste minus. Und das listet die 10 Zeilen zurück, Sie können spielen, um mit der Liste ein wenig. Können Sie die Liste, Liste zu tun -, können Sie sogar Liste eine Nummer, wie list 8, und es wird die 10 Linien um die Linie 8 aufzulisten. Und Sie können sehen, was hier los ist du ist eine einfache if else habe. Wenn Sie in CS50 Felsen geben, druckt es aus "Sie können einen A. bekommen" Ansonsten druckt "Sie können eine D. bekommen" Bummer Stadt. Gut. Ja? [Daniel] So, wenn ich tue CS50 Felsen ohne die Anführungszeichen versucht, er sagt: "Sie können eine D. bekommen" Ich brauchte die Anführungszeichen, um es zu arbeiten, warum ist das so? >> Ja. Es stellt sich heraus, dass, wenn - das ist ein lustiges kleines Schmankerl - wenn Sie das Programm ausführen, wenn wir es laufen und wir geben in CS50 Felsen, wie Daniel sagte er getan hat, und Sie die Eingabetaste drücken, es immer noch sagt, wir erhalten einen D. Und die Frage ist, warum? Und es stellt sich heraus, dass sowohl unsere Terminal und GDB diese als zwei getrennte Argumente zu analysieren. Denn wenn es einen Raum, der als implizit ist das erste Argument beendet, das nächste Argument ist zu beginnen. Der Weg zu den in zwei kombinieren oder sorry, in ein Argument, ist es, die Zitate zu verwenden. So jetzt, wenn wir es in Anführungszeichen und führen Sie es erneut, bekommen wir einen A. Also nur zur Erinnerung, sind keine Anführungszeichen, CS50 und Felsen als zwei getrennte Argumente analysiert. Mit Zitaten, ist es als ein Argument überhaupt analysiert. Wir können dies mit einem Haltepunkt zu sehen. Bisher haben wir läuft unser Programm, und es läuft bis sie entweder seg Fehler oder Zugriffe einen Fehler oder bis es beendet wurde und alle war völlig in Ordnung. Dies ist nicht unbedingt die hilfreiche Sache, denn manchmal Sie haben einen Fehler in Ihrem Programm, aber es ist nicht die Ursache einen Segmentation Fault. Es ist nicht die Ursache Ihres Programms zu stoppen oder so etwas. Der Weg zum GDB zu pausieren Sie Ihr Programm an einer bestimmten Stelle ist es, einen Haltepunkt zu setzen. Sie können dies entweder, indem Sie einen Haltepunkt auf einem Funktionsnamen oder Sie können einen Haltepunkt für einen bestimmten Code-Zeile gesetzt. Ich mag, um Haltepunkte in Funktionsnamen gesetzt, weil - leicht zu merken, und wenn Sie tatsächlich gehen und ändern Sie Ihren Quellcode up ein wenig, dann ist dein Haltepunkt wird tatsächlich an der gleichen Stelle im Code zu bleiben. Während, wenn Sie mit Zeilennummern und die Zeilennummern ändern weil Sie hinzufügen oder löschen einen Code, dann wird Ihre Haltepunkte sind alle total vermasselt. Einer der häufigsten Dinge, die ich tun müssen, ist einen Haltepunkt an der Hauptfunktion gesetzt. Oft werde ich hochfahren GDB, werde ich geben b Haupt-, Enter drücken, und dass dann einen Haltepunkt setzen auf der Hauptfunktion, die nur sagt, "das Programm anzuhalten, sobald Sie laufen beginnen" und auf diese Weise, wenn ich mein Programm laufen mit, sagen wir, CS50 Felsen als zwei Argumente und drücken Sie Enter, wird es an die Hauptfunktion und es hält direkt vor der ersten Zeile, rechts, bevor es wertet die strcmp Funktion. Da ich angehalten bin, jetzt kann ich anfangen herumschlagen und zu sehen, was los ist mit all den verschiedenen Variablen, die in mein Programm übergeben werden. Hier kann ich drucken argc und sehen, was los ist. Seht zu, dass argc 3 ist, denn es hat die 3 verschiedene Werte drin. Es den Namen des Programms hat, ist es das erste Argument und das zweite Argument bekam. Wir können die auszudrucken Dazu suchen Sie in argv [0], argv [1] und argv [2]. So, jetzt können Sie auch sehen, warum dies strcmp Anruf wird zum Scheitern verurteilt, weil Sie sehen, dass es hat den CS50 und die Felsen in zwei getrennte Argumente aufgeteilt. An diesem Punkt, wenn Sie einen Haltepunkt getroffen haben, können Sie weiterhin durch Ihr Programm fort Zeile für Zeile, wie dem Starten Sie das Programm erneut gegenüber. Also, wenn Sie nicht möchten, dass Sie das Programm erneut und starten Sie einfach weiter von hier, können Sie die continue-Befehl und weiterhin wird das Programm bis zum Ende laufen. So wie es hier getan hat. Allerdings, wenn ich das Programm, CS50 Felsen starten, trifft es meiner Haltepunkt wieder und dieses Mal, wenn ich will nicht einfach gehen den ganzen Weg durch den Rest des Programms, Ich kann den nächsten Befehl, die ich auch mit n abkürzen. Und dies wird durch das Programm Zeile für Zeile fort. So können Sie sehen, wie die Dinge auszuführen, als Variablen ändern, wie die Dinge aktualisiert. Welches ist ziemlich nett. Die andere coole Sache ist, anstatt wiederholen Sie den gleichen Befehl immer und immer und immer wieder, wenn Sie traf nur eingeben - so hier sehen, habe ich an nichts eingegeben - wenn ich getroffen Geben Sie einfach wird es wiederholen Sie den vorherigen Befehl oder die vorherige GDB Befehl, dass ich gerade auf in. Ich kann mich Enter drücken und es wird immer das Schreiten durch meinen Code Zeile für Zeile. Ich möchte Sie ermutigen euch zu gehen einige der anderen buggy Programme. Wir haben keine Zeit, um durch alle von ihnen heute in Abschnitt erhalten. Der Quellcode ist es, so kann man irgendwie sehen, was los ist Blick hinter die Kulissen, wenn Sie wirklich nicht weiterkommen, aber zumindest, nur üben Hochfahren GDB, läuft das Programm bis es auf Sie bricht, immer die Rückverfolgung, herauszufinden, welche Funktion der Absturz war, welche Linie war es, der Druck einige Variablenwerte nur damit du ein Gefühl dafür bekommen, weil das wirklich helfen Ihnen für die Zukunft. An dieser Stelle werden wir beenden von GDB, die Sie mit zu beenden oder einfach nur q. Ist Ihr Programm in der Mitte läuft noch, und es hat nicht verlassen, es wird immer fragen: "Sind Sie sicher, dass Sie wirklich wollen, zu beenden?" Sie können einfach auf yes. Jetzt werden wir bei der nächsten Problem, das wir haben, was die Katze Programm aussehen. Wenn Sie die Kurzform zum Umleiten und Rohre zu sehen, werden Sie sehen, dass Tommy dieses Programm verwendet das im Grunde druckt alle die Ausgabe einer Datei auf dem Bildschirm. Also, wenn ich cat laufen, ist dies eigentlich ein eingebautes Programm auf das Gerät, und wenn du Macs haben, können Sie diese auf Ihrem Mac zu tun, wenn Sie eröffnen Terminal. Und wir - Katze, sagen wir mal, cp.c, und drücken Sie Enter. Was dies tat, wenn wir nach oben ein wenig und sehen, wo wir die Linie lief, oder wo wir den Befehl cat lief es buchstäblich nur den Inhalt des cp.c unsere Siebdruck. Wir können es wieder zu laufen und Sie können in mehrere Dateien zusammen. So kann man tun, cat cp.c, und dann können wir auch verketten Sie die Cat.C Datei, das ist das Programm, die wir hier schreiben, und es wird beide Dateien zurück drucken zu unserem Bildschirm zurück. Also, wenn wir ein wenig blättern, sehen wir, dass, wenn wir liefen diese Katze cp.c, Cat.C, Zuerst ausgedruckt der cp-Datei, und dann darunter, druckte es aus den Cat.C Datei direkt hier unten. Wir werden diese nutzen, um nur unsere Füße nass. Spielen Sie mit einfachen Druck auf das Terminal, zu sehen, wie das funktioniert. Wenn euch eröffnen mit gedit Cat.C, drücken Sie Enter, Sie können das Programm sehen, dass wir über Sie schreiben sollen. Wir haben dieses schöne Kesselblech enthalten, so haben wir keine Zeit zu verbringen Eingabe all diese heraus. Wir prüfen auch die Anzahl der übergebenen Argumente in. Wir drucken eine schöne Nutzung Nachricht. Dies ist die Art von Dingen, die wieder, wie über die wir gesprochen haben, es ist fast wie Muskel-Speicher. Denken Sie daran zu halten, die die gleiche Art von Sachen und immer Ausdruck einer Art hilfreiche Botschaft so, dass die Menschen wissen, wie man das Programm auszuführen. Mit Katze, ist es recht einfach, wir sind gerade dabei, durch all die verschiedenen Argumente gehen Das waren unsere Programm übergeben, und wir Drucklegung deren Inhalte heraus zu dem Bildschirm nacheinander. Um Dateien ausdrucken, um den Bildschirm, werden wir etwas sehr Ähnliches zu tun was wir haben am Ende des Quiz. Am Ende des Quiz, das Programm einzustellen, mussten wir öffnen eine Datei, und dann mussten wir sie zu drucken. In diesem Fall werden wir eröffnen eine Datei aus, und wir werden von ihm lesen, statt. Dann haben wir Drucklegung, statt in einer Datei sind, werden wir auf dem Bildschirm auszugeben. So Drucken auf dem Bildschirm alles getan habe, bevor mit printf. Also das ist nicht zu verrückt. Aber das Lesen einer Datei ist irgendwie seltsam. Wir werden durch die ein wenig in einer Zeit, zu gehen. Wenn euch zurück zu diesem letzten Problem auf Ihrem Quiz, Problem 33, die erste Zeile, dass wir hier tun, die Datei zu öffnen, ist sehr ähnlich zu dem, was wir taten es. So Stella, was bedeutet, dass die Zeile aussehen, wenn wir eine Datei zu öffnen? [Stella] Capital FILE *, Datei - >> Okay. >> - Gleich fopen. >> Yup. Die in diesem Fall? Es ist in dem Kommentar. >> Es ist in dem Kommentar? argv [i] und r? >> Genau. Right on. So Stella ist völlig richtig. Dies ist, was die Linie aussieht. Wir werden ein Datei-Stream Variablen zu erhalten, bewahren Sie sie in einem FILE *, so dass alle Kappen, FILE, * und der Name dieser Variable Datei zu sein. Wir könnten es, was wir wollen. Wir könnten es first_file oder file_i, was wir möchten. Und dann der Name der Datei in der Kommandozeile zu diesem Programm weitergegeben. So ist es in argv gespeicherten [i] und dann werden wir diese Datei im Lese-Modus öffnen. Nun, da wir die Datei geöffnet, was ist das, was wir immer daran denken, zu tun wenn wir eine Datei geöffnet? Schließen Sie es. So Missy, wie können wir eine Datei schließen? [Missy] fclose (Datei) >> fclose (Datei). Genau. Great. Okay. Wenn wir uns dies Kommentar hier tun, es sagt, "Open argv [i], und drucken den Inhalt auf die Standardausgabe." Standardausgabe ist ein komischer Name. Stdout ist nur unsere Art zu sagen, wir wollen es auf dem Terminal, wir wollen es auf die Standardausgabe zu drucken. Wir können tatsächlich loszuwerden dieser Kommentar hier richtig. Ich werde es zu kopieren und da das ist, was wir taten. An diesem Punkt, jetzt haben wir die Datei Bit für Bit zu lesen. Wir haben ein paar Möglichkeiten, das Lesen von Dateien diskutiert. Welche sind Ihre Favoriten so weit? Welche Möglichkeiten haben Sie gesehen oder erinnern Sie sich an, um Dateien zu lesen? [Daniel] fread? >> Fread? So fread ist eins. Jimmy, kennen Sie einen anderen? [Jimmy] Nein >> Okay. Nope. Charlotte? Alexander? Alle anderen? Okay. So die anderen sind fgetc, wird ein, dass wir eine Menge zu verwenden. Es gibt auch fscanf; euch hier ein Muster? Sie sind alle mit f beginnen. Alles, was mit einer Datei zu tun. Es gibt fread, fgetc, fscanf. Das sind all die Lesefunktionen. Zum Schreiben haben wir fwrite, haben wir fputc statt fgetc. Wir haben auch fprintf wie wir sahen, auf dem Quiz. Da es sich um ein Problem, das Lesen von einer Datei umfasst, werden wir eine dieser drei Funktionen zu nutzen. Wir gehen nicht, um diese Funktionen zu nutzen hier unten. Diese Funktionen sind alle in der Standard-I / O Bibliothek gefunden. Also, wenn Sie schauen an der Spitze dieses Programms Sie können sehen, dass wir bereits die Header-Datei für die Standard I / O-Bibliothek enthalten. Wenn wir herausfinden wollen, welche, die wir verwenden möchten, können wir immer öffnen die man pages. So können wir geben Menschen stdio und lesen Sie alles über die stdio Input-und Output-Funktionen in C. Und jetzt können wir sehen, oh, schau mal. Es ist zu erwähnen fgetc, es zu erwähnen fputc. So können Sie einen Drilldown ein wenig und schauen, sagen wir, fgetc und ihrem Mann zu sehen. Sie können sehen, dass es entlang geht mit einer ganzen Reihe von anderen Funktionen: fgetc, fgets, getc, getchar, bekommt, ungetc, und seine Eingabe von Zeichen und Zeichenketten. Also das ist, wie wir in Zeichen und Zeichenketten gelesen von Dateien von der Standardeingabe, die im wesentlichen von dem Benutzer. Und dies ist, wie wir es tun in der tatsächlichen C. So ist dies nicht mit der GetString und GetChar Funktionen dass wir verwendet von der CS50-Bibliothek. Wir werden dieses Problem in ein paar Möglichkeiten zu tun so dass Sie sehen können auf zwei verschiedene Arten, es zu tun. Sowohl die fread Funktion, Daniel erwähnt und fgetc sind gute Möglichkeiten, es zu tun. Ich denke fgetc ist ein wenig einfacher, weil es nur, wie Sie sehen, ein Argument, das FILE *, dass wir versuchen, den Charakter von dieser gelesen und der Rückgabewert ist ein int. Und das ist ein wenig verwirrend, nicht wahr? Weil wir immer ein Zeichen sind, also warum nicht diese Rückkehr ein char? Ihr habt irgendwelche Ideen, woran das liegen könnte nicht wieder ein char? [Missy Antworten unverständlich] >> Ja. So Missy ist völlig richtig. Wenn es ASCII ist, dann ist diese Zahl könnte zu einem tatsächlichen char zugeordnet werden. Könnte ein ASCII-Zeichen sein, und das ist richtig. Das ist genau das, was passiert. Wir verwenden einen int einfach weil es mehr Bits hat. Es ist größer als ein char, unsere char nur 8 Bit, dass 1 Byte auf unserer 32-Bit-Maschinen. Und ein int hat alle 4 bytes 'im Wert von Raum. Und es stellt sich heraus, dass der Weg fgetc funktioniert, Wenn wir in unserem Exposé blättern in dieser Manpage ein wenig, scrollen Sie ganz nach unten. Es stellt sich heraus, dass sie diesen besonderen Wert namens EOF verwenden. Es ist eine spezielle Konstante als Rückgabewert der fgetc Funktion wenn Sie traf das Ende der Datei oder, wenn Sie eine Fehlermeldung erhalten. Und es stellt sich heraus, dass diese Vergleiche mit EOF richtig zu machen, Sie wollen, dass zusätzliche Menge an Informationen, die Sie in einem int haben um mit einem char-Variable entgegen. Obwohl fgetc effektiv immer ein Zeichen aus einer Datei, Sie wollen sich daran zu erinnern, dass es wieder etwas, das vom Typ int ist für Sie. Das heißt, es ist ziemlich einfach zu bedienen. Es wird uns ein Zeichen, so alles, was wir tun müssen, ist immer wieder die Datei, "Gib mir das nächste Zeichen, gib mir das nächste Zeichen, gib mir das nächste Zeichen" bis wir an das Ende der Datei erhalten. Und das wird in ein Zeichen zu einem Zeitpunkt aus unserer Datei ziehen, und dann können wir tun, was wir mit ihm gefällt. Wir können es speichern, können wir es in einen String hinzufügen, können wir es auszudrucken. Führen Sie dafür. Zoomen wieder aus und gehen zurück zu unserem Cat.C Programm wenn wir gehen zu fgetc verwenden, wie können wir nähern dieses nächste Codezeile? Wir gehen zu bedienen - fread etwas etwas anders zu tun. Und dieses Mal sind wir gerade dabei, fgetc verwenden, um ein Zeichen zu einem Zeitpunkt erhalten. Um eine komplette Datei zu verarbeiten, könnte das, was wir zu tun haben? Wie viele Zeichen sind in einer Datei? Es gibt eine Menge. So wollen Sie wahrscheinlich, eins zu bekommen und erhalten dann eine andere und bekommen eine andere und bekommen eine andere. Welche Art von Algorithmus denken Sie, wir müssten hier verwenden? Welche Art von -? [Alexander] Eine for-Schleife? >> Genau. Eine bestimmte Art der Schleife. Eine for-Schleife ist eigentlich toll, in diesem Fall. Und wie du sagst, es klingt wie Sie eine Schleife über die gesamte Datei möchten, immer ein Zeichen in einer Zeit. Irgendwelche Vorschläge auf, was das aussehen könnte? [Alexander, unverständlich] >> Okay, sag mir in Englisch, was du versuchst zu tun? [Alexander, unverständlich] Also in diesem Fall, es klingt wie wir nur versuchen, eine Schleife über die gesamte Datei. [Alexander] So i > Die Größe -? Ich denke, die Größe der Datei, nicht wahr? Die Größe - wir werden einfach schreiben es so. Größe der Datei für die vorerst i + +. So stellt sich heraus, dass die Möglichkeit, dies mit nicht fgetc, und das ist neu, ist, dass es keine einfache Möglichkeit, nur erhalten, die Größe einer Datei mit diesem "sizeof" Art der Konstruktion, dass Sie bisher gesehen haben. Wenn wir diese fgetc Funktion zu nutzen, sind wir die Einführung eine Art von neuen, funky Syntax diese for-Schleife, wo anstatt nur eine einfache Zähler zum Zeichen für Zeichen zu gehen, werden wir ein Zeichen in einer Zeit zu ziehen, ein Zeichen in einer Zeit, und die Art, wie wir wissen, dass wir am Ende nicht, wenn wir eine bestimmte Anzahl von Zeichen gezählt, aber wenn der Charakter ziehen wir darauf hin, dass spezielle Ende der Datei Zeichen ist. So können wir dies tun, indem Sie - ich nenne diese ch, und wir werden um es zu initialisieren mit unserem ersten Anruf um das erste Zeichen aus der Datei zu erhalten. So dass dieser Teil hier, das wird ein Zeichen raus aus der Datei und speichern Sie es in die Variable ch. Wir werden weiter machen, bis wir an das Ende der Datei, denen wir durch die Prüfung für den Charakter nicht gleich zu diesem speziellen EOF-Zeichen. Und dann anstatt das zu tun ch + +, würde die nur erhöhen Sie den Wert, so, wenn wir lesen, ein A aus der Datei, ein großes A, sagen wir, ch + + würde uns b, und dann würden wir c und dann d erhalten. Das ist eindeutig nicht das, was wir wollen. Was wir wollen hier in diesem letzten Bit wollen wir das nächste Zeichen aus der Datei zu erhalten. Also, wie können wir Sie das nächste Zeichen aus der Datei? Wie bekommen wir das erste Zeichen aus der Datei? [Student] fgetfile? >> Fgetc oder, sorry, du warst ganz rechts. I falsch es genau dort. So yeah. Hier anstatt das zu tun ch + +, wir gerade dabei, fgetc (Datei) erneut aufrufen und speichern das Ergebnis in unserem selben Lm variabel. [Studenten Frage unverständlich] >> Das ist, wo diese FILE * Jungs Besonderes sind. Die Art, wie sie arbeiten, ist, dass sie - wenn man zum ersten Mal öffnen - wenn Sie zunächst, dass fopen Anruf Die Datei * dient effektiv als ein Zeiger auf den Anfang der Datei. Und dann jedes Mal, rufen Sie fgetc, bewegt sie sich ein Charakter durch die Datei. Also, wenn Sie diese aufrufen, du Inkrementieren der Dateizeiger um ein Zeichen. Und wenn du dich wieder fgetc, du Verschieben anderes Zeichen und ein anderer Charakter und einen anderen Charakter und ein anderes Zeichen. [Studenten Frage unverständlich] >> Und that's - yeah. Es ist eine Art dieser Magie unter der Haube. Sie halten gerade Inkrementieren durch. An diesem Punkt sind Sie in der Lage, tatsächlich mit einem Charakter zu arbeiten. Also, wie können wir drucken Sie auf den Bildschirm, jetzt? Wir können die gleiche printf, was wir vorher benutzt. Dass wir seit über alle Semester. Wir können printf nennen, und wir können in den Charakter einfach so passieren. Ein anderer Weg, es zu tun, anstatt printf und mit diesen Format-String zu tun, können wir auch eine der anderen Funktionen. Wir können fputc, die ein Zeichen auf dem Bildschirm ausgibt, außer wenn wir fputc aussehen - lassen Sie mich Verkleinern ein wenig. Wir sehen, was schön ist, dauert es im Charakter, dass wir lesen mit fgetc, aber dann müssen wir ihm einen Stream zu drucken. Wir können auch die putchar Funktion, die direkt gestellt wird die Standardausgabe. So gibt es eine ganze Reihe von verschiedenen Optionen, die wir für den Druck verwenden können. Sie sind alle in der Standard-I / O-Bibliothek. Wann immer Sie drucken wollen - so printf, standardmäßig wird die spezielle Standard-Out-Stream zu drucken, nämlich dass stdout. So können wir nur darauf verweisen, wie Art dieser magischen Wert, stdout hier. Oops. Legen Sie das Semikolon außen. Das ist eine Menge von neuen, funky Informationen hier. Eine Menge davon ist sehr idiomatisch, in dem Sinne, daß dieser Code ist das ist so geschrieben, nur weil es sauber ist zu lesen, leicht zu lesen. Es gibt viele verschiedene Möglichkeiten, es zu tun, viele verschiedene Funktionen, die Sie nutzen können, aber wir neigen dazu, folgen Sie einfach diesen gleichen Muster über und über. Also nicht wundern, wenn Sie Code wie diesen kommen immer wieder sehen werden. Gut. An diesem Punkt müssen wir für den Tag zu brechen. Danke fürs Kommen. Danke fürs Zuschauen, wenn Sie online sind. Und wir sehen uns nächste Woche. [CS50.TV]