[Powered by Google Translate] [Abschnitt 5 - komfortabler]
[Rob Bowden - Harvard University]
[Dies ist CS50. - CS50.TV]
>> Wie ich in meinem E-Mail-gesagt, es gibt eine Menge Dinge, die Sie verwenden können
andere als das Gerät tatsächlich nicht das Problem Sets.
Wir empfehlen, dass Sie sie in das Gerät nur, weil dann können wir leicht helfen Ihnen
und wir wissen, wie alles funktionieren wird.
Aber als ein Beispiel, wo man Dinge tun kann, wenn, sagen wir, müssen Sie nicht den Zugang
zu einem Gerät oder Sie wollen in der Science Center Keller arbeiten -
was eigentlich haben sie das Gerät auch -
Wenn Sie irgendwo arbeiten wollen.
Ein Beispiel ist hast du gesehen / gehört der SSH?
SSH ist im Grunde wie eine Verbindung zu etwas.
Eigentlich im Moment bin ich in das Gerät SSHed.
Ich habe nie direkt in der Appliance.
Hier ist das Gerät, und wenn man hier unten sehen Sie diese IP-Adresse.
Ich habe nie in das Gerät selbst zu arbeiten;
Ich komme immer mehr zu einem iTerm2 Fenster / Terminal-Fenster.
Sie können SSH zu dieser IP-Adresse, ssh jharvard@192.168.129.128.
Ich erinnere mich an diese Nummer sehr leicht, weil es so ein schönes Muster ist.
Aber das wird mich nach meinem Passwort fragen, und jetzt bin ich in das Gerät.
Grundsätzlich an diesem Punkt, wenn Sie eröffnet eine Klemme im Inneren des Gerätes selbst,
diese Schnittstelle, aber Sie würden es zu benutzen, ist genau das gleiche
als Schnittstelle Ich verwende hier aber jetzt bist du SSHed.
Sie brauchen nicht zu SSH auf das Gerät haben.
Ein Beispiel für einen anderen Ort konnte man SSH ist, ich bin mir ziemlich sicher, dass Sie standardmäßig -
Oh. Bigger.
Alle von euch sollte standardmäßig FAS Konten auf den FAS-Server haben.
Für mich würde ich SSH rbowden@nice.fas.harvard.edu.
Es wird, dass die erste Zeit zu fragen, und Sie sagen, ja.
Mein Passwort ist gerade dabei, meinen FAS Passwort sein.
Und jetzt bin ich auf die schöne Servern SSHed, und ich kann was ich will hier tun.
Eine Menge von Klassen, die Sie nehmen, könnte wie 124, gehen zu müssen, die Sie hochladen Zeug hier
tatsächlich senden Sie Ihre Problemstellungen.
Aber sagen Sie nicht haben Zugriff auf Ihr Gerät.
Dann können Sie Dinge tun, wie hier wird es sagen -
Dies ist nur unserer Sektion der Fragen.
Es wird Sie bitten, dies in dem Gerät zu tun.
Stattdessen werde ich es einfach tun auf dem Server.
Ich werde um sie zu entpacken, dass.
Das Problem wird sein, dass Sie mit so etwas wie gedit gewohnt
oder was auch immer im Inneren des Gerätes.
Du wirst nicht mit der auf dem FAS-Server haben.
Es ist alles nur gehen, um diese textuelle Schnittstelle.
So können Sie entweder ein, versuchen Sie einen Text-Editor, dass sie haben zu lernen.
Sie haben Nano.
Nano ist in der Regel recht einfach zu bedienen.
Sie können Ihre Pfeile und geben in der Regel.
Also das ist nicht schwer.
Wenn Sie sich wirklich hübsch machen wollen, können Sie Emacs,
was ich sollte wohl nicht geöffnet werden, weil ich nicht einmal weiß, wie man Emacs zu schließen haben.
Control X, Control C? Yeah.
Oder Sie können Vim, was ich verwenden soll.
Und also sind Ihre Möglichkeiten.
Wenn Sie nicht wollen, das zu tun, können Sie auch, wenn man sich manual.cs50.net--
Oh.
Auf einem PC, können Sie SSH mit PuTTY,
die Sie gehen zu müssen separat heruntergeladen werden.
Auf einem Mac können Sie einfach standardmäßig Einsatz Terminal oder können Sie iTerm2,
das ist wie eine schöne, ausgefallene Terminal.
Wenn Sie manual.cs50.net gehen Sie sehen einen Link zu Notepad + +,
das ist, was Sie auf einem PC verwenden.
Es ermöglicht Ihnen SFTP von Notepad + + ist was im Grunde SSH.
Was dies können Sie tun, ist zu bearbeiten Sie Ihre Dateien lokal,
und dann, wenn Sie sie speichern möchten, wird es nice.fas speichern,
wo man dann laufen sie.
Und das Äquivalent auf einem Mac wird TextWrangler sein.
So können Sie das gleiche tun.
Damit können Sie Dateien bearbeiten lokal und speichern Sie sie auf nice.fas,
wo man dann laufen sie.
Also, wenn Sie jemals ohne ein Gerät stecken sind, haben Sie diese Optionen
noch nicht Ihr Problem Sets.
Das einzige Problem wird sein, dass Sie nicht gehen, um den CS50 Bibliothek haben
weil nice.fas nicht standardmäßig das haben.
Sie können entweder den CS50-Bibliothek -
Ich glaube nicht, brauche ich an dieser Stelle.
Sie können entweder den CS50-Bibliothek und kopieren Sie ihn auf nice.fas,
oder ich denke wir an dieser Stelle nicht mehr benutzte sowieso.
Oder wenn wir das tun, können Sie für die Zeit, die es ersetzen
die Implementierungen der Funktionen in der CS50-Bibliothek sowieso.
So das sollte nicht so viel von einer Beschränkung.
Und das ist es.
>> Ich gehe zurück zu dem Gerät jetzt werden wir alles in dem Gerät zu tun.
Mit Blick auf unserer Sektion der Fragen am Anfang, wie ich in meinem E-Mail-sagte,
Wir müssen über die ein Kurz gesagt, Sie sollen sehen waren reden.
Wir haben das Umleiten & Pipes und diese drei Fragen.
>> Um die Stream Sie Funktionen wie printf standardmäßig schreiben?
So Stream. Was ist ein Stream?
Ein Strom ist im Grunde wie es nur einige -
Es ist nicht einmal eine Quelle von 1s und 0s.
Der Stream es hier zu fragen ist serienmäßig aus.
Und so Standardausgabe ist ein Strom, wenn Sie es schreiben,
es erscheint auf dem Bildschirm.
Standard aus, indem Strom, es heißt, Sie schreiben einfach 1s und 0s es,
und das andere Ende der Standardausgabe gerade liest aus diesem Stream.
Es ist nur eine Reihe von 1s und 0s.
Sie können Streams schreiben oder Sie können aus Bächen lesen
je nachdem, was der Strom tatsächlich ist.
Die beiden anderen Standard-Streams sind Standard in und Standardfehler.
Standard in ist, wenn Sie GetString tun, ist es für Sie zur Eingabe Sachen warten.
So ist es für Sie warten, ist es eigentlich wartet auf Standard-in,
das ist wirklich das, was Sie, wenn Sie über die Tastatur einzugeben bekommen.
Sie sind in Standard in. eingeben
Standardfehler ist im Grunde gleichwertig in die Standardausgabe,
aber es ist spezialisiert auf, dass, wenn Sie Standard-Fehler drucken,
Sie soll nur drucken, Fehlermeldungen, dass
so können Sie zwischen den regulären Nachrichten auf dem Bildschirm ausgegeben zu unterscheiden
gegenüber Fehlermeldungen je nachdem, ob sie gingen die Standardausgabe oder Standardfehler.
Dateien zu.
Standard aus, Standard und Standardfehler sind nur spezielle Streams
aber wirklich jeder Datei, wenn Sie eine Datei öffnen, wird es einen Stream von Bytes
wo man gerade aus diesem Stream zu lesen.
Sie zum größten Teil kann nur einer Datei als einen Strom von Bytes zu denken.
Also, was Streams sie schreibt standardmäßig? Standard aus.
>> Was ist der Unterschied zwischen> und? >>
Hat jemand das Video vorher? Okay.
> Sein wird, wie Sie in Dateien umzuleiten,
und >> wird sich auch die Ausgabe in eine Datei umleiten,
aber es ist anstatt gehen, um die Datei anzuhängen.
Zum Beispiel, sagen wir, ich zufällig dict hier haben,
und das einzige Zeug in der dict ist Katze, Katze, Hund, Fische, Hund.
Ein Befehl, den Sie in der Befehlszeile haben, ist cat,
das ist nur Drucklegung, was in einer Datei.
Also, wenn ich cat dict sagen, es geht um Katze, Katze, Hund, Fisch, Hund drucken. Das ist alles, Katze tut.
Das bedeutet, dass sie auf die Standardausgabe gedruckt Katze, Katze, Hund, Fische, Hund.
Wenn ich stattdessen möchten, dass in eine Datei umleiten, kann ich> und leiten es an, was die Datei ist.
Ich rufe die Datei Datei.
So wenn ich nun ls, werde ich sehen, ich habe eine neue Datei namens Datei.
Und wenn ich es öffnen, es zu haben, genau das, was Katze an der Kommandozeile eingegeben werden.
So, jetzt, wenn ich das wieder tun, dann wird es die Ausgabe in Datei umleiten,
und ich werde genau die gleiche Sache zu haben.
So technisch, es vollständig hinwegsetzte, was wir hatten.
Und wir werden sehen, ob ich dict ändern, nahm ich Hund.
Nun, wenn wir cat dict in die Datei wieder, werden wir die neue Version mit Hund entfernt haben.
So ist es komplett überschreibt es.
Stattdessen, wenn wir >> verwenden, es geht um die Datei anzuhängen.
Nun Öffnen der Datei, sehen wir uns genau das gleiche zweimal gedruckt
weil es dort einmal war, dann werden wir auf die ursprüngliche angehängt.
Also das ist, was> und >> tun.
Ist die nächste fragen - Es ist nicht danach zu fragen.
>> Die andere, die wir haben <, die, wenn> leitet die Standardausgabe,
<Wird sein Standard-Redirect in.
Mal sehen, ob wir ein Beispiel.
Ich kann ein sehr kurz.
Nehmen wir eine beliebige Datei, hello.c.
Relativ unkompliziert Datei.
Ich bin gerade erst einen String und dann gedruckt "Hallo", was der Saite, die ich gerade eingegeben war.
So hallo und dann. / Hallo.
Jetzt ist es auffordert mir etwas geben,
was bedeutet, dass es auf die Dinge warten, um in Standard in. eingegeben werden
So geben was ich in Standard möchten in. Wir haben gerade gehst zu sagen Hallo, Rob!
Dann ist es Standard-Ausdruck Hallo, Rob!
Wenn ich das tue. / Hallo und dann umleiten,
jetzt kann man nur aus einer Datei umzuleiten.
Also, wenn ich habe in einigen Datei, txt, und ich legte Rob,
wenn ich laufe hallo und dann leiten Sie die Datei txt in. / hallo, es geht zu sagen, Hallo, Rob! sofort.
Wenn es zuerst bekommt GetString und es ist auf Standard-Wartezeit in,
Standard ist nicht mehr warten auf die Tastatur für die Daten eingegeben zu werden.
Stattdessen haben wir weitergeleitet Standard aus der Datei txt lesen.
Und so geht aus der Datei txt, die nur die Linie Rob ist zu lesen,
und dann es wird Hallo, Rob drucken!
Und wenn ich wollte, könnte ich auch tun. / Hallo <txt
und dann der Standard, dass es der Druckerei, die Hallo ist, Rob!,
Das kann ich in eine eigene Datei umzuleiten.
Ich werde einfach rufen Sie die Datei hallo - nein, das werde ich nicht, denn das ist die ausführbare Datei - txt2.
Nun wird txt2 werde die Ausgabe von. / Hallo <txt, die gehen, um hallo zu sein, so Rob haben!
>> Haben Sie Fragen?
>> Okay. Also hier haben wir Pipeline.
Pipes sind die letzte Einheit der Umleitung.
>> Oh. Ich denke, eine weitere Einheit der Umleitung, wenn anstelle von> Sie 2>
Das ist umleiten Standardfehler.
Also, wenn etwas ging Standardfehler, wäre es nicht in txt2 gelegt bekommen.
Aber merken, wenn ich 2> zu tun, dann ist es immer noch gedruckt Hallo, Rob! in der Befehlszeile
weil ich nur umgeleitet werde Standardfehler, ich bin nicht umleiten Standardausgabe.
Standardfehler und Standardausgabe sind unterschiedlich.
Wollte man tatsächlich Standardfehler schreiben,
dann könnte ich dies ändern zu fprintf auf stderr.
So printf, die standardmäßig druckt die Standardausgabe.
Wenn ich auf Standard-Fehler manuell drucken möchten, dann muss ich fprintf verwenden
und geben, was ich drucken möchten.
Wenn ich stattdessen fprintf stdout hat, dann ist das im Grunde gleichwertig zum printf.
Aber fprintf Standard-Fehler.
So, jetzt, wenn ich diese Umleitung in txt2, Hallo, Rob! ist noch immer in der Befehlszeile gedruckt
Da es gewöhnungsbedürftig Standardfehler gedruckt und ich bin nur umleiten Standardausgabe.
Wenn ich umleiten jetzt Standardfehler, jetzt ist es nicht gedruckt wird, erhalten und txt2 sein wird Hallo, Rob!
So, jetzt können Sie Ihre tatsächliche Fehler auf stderr gedruckt
und drucken Sie Ihre regelmäßigen Nachrichten in die Standardausgabe.
Und so, wenn Sie Ihr Programm ausführen, können Sie es als laufen. / Hallo diese Art mit dem 2>
so dass Ihr Programm wird normal ausgeführt,
aber alle Fehlermeldungen, die Sie erhalten, können Sie später überprüfen in Ihrem Fehlerprotokoll
so Fehler, und dann später aussehen und Ihre Fehler Datei wird alle Fehler, die passiert sind.
>> Haben Sie Fragen?
>> Der letzte ist Rohr, die Sie sich als unter den Standard aus einem Befehl denken kann
und macht es der Standard in der nächsten Befehl.
Ein Beispiel ist hier echo ist ein Kommandozeilen-Sache
Das ist gerade dabei, echo, was ich als Argument. Ich werde nicht Anführungszeichen setzen.
Echo blah, blah, blah ist gerade dabei, blah, blah, blah drucken.
Früher, als ich sagte, ich musste Rob in eine txt Datei ablegen
da kann ich nur umzuleiten txt-Dateien, sondern / wenn ich echo Rob
und leiten sie in. / Hallo, das wird auch nicht die gleiche Art von Ding.
Dies wird unter die Ausgabe dieses Befehls echo Rob,
und es als Eingabe für. / hallo.
Sie können denken, es als erster umzuleiten echo Rob in einer Datei
und dann Eingang in. / hallo, dass die Datei, die gerade ausgegeben.
Aber es braucht die temporäre Datei aus dem Bild.
>> Fragen dazu?
>> Die nächste Frage wird diese einzubeziehen.
Welche Pipeline könnte man verwenden, um die Anzahl der eindeutigen Namen in einer Datei namens names.txt finden?
Die Befehle, die wir gehen zu wollen, hier verwenden wollen sind einzigartig, so uniq, und dann WC.
Sie können Menschen uniq eigentlich, was das bedeutet schauen,
und es ist gerade dabei, neben passenden Zeilen aus der Eingabe zu filtern.
Und der Mensch WC wird den Zeilenumbruch, Wort und Byteanzahl für jede Datei zu drucken.
Und das letzte, was wir gehen zu wollen, verwenden wollen ist eine Art,
das geht nur sortieren Zeilen txt-Datei.
Wenn ich etwas txt-Datei, names.txt, und es ist Rob, Tommy, Joseph, Tommy, Joseph, RJ, Rob,
was ich will hier tun ist, finden die Anzahl der eindeutigen Namen in dieser Datei.
Also, was soll die Antwort sein? >> [Schüler] 4. >> Ja.
Es sollte 4 sein, da Rob, Tommy, Joseph, sind RJ nur eindeutige Namen in dieser Datei.
Der erste Schritt, wenn ich nur tun Wortanzahl auf names.txt,
dies tatsächlich erzählte mir alles.
Dies ist eigentlich Druck - mal sehen, man wc - Zeilenumbrüche, Worten und Bytezahl.
Wenn ich über Linien nur kümmern, dann kann ich nur tun wc-l names.txt.
Damit ist Schritt 1.
Aber ich weiß nicht, wc-l names.txt wollen, weil names.txt enthält nur die Namen,
und ich herausfiltern möchten alle nicht Einzigen.
Also, wenn ich uniq names.txt tun, bedeutet das nicht ganz mir, was ich will
weil die duplizierten Namen sind noch da.
Warum ist, dass? Warum ist uniq nicht tun, was ich will?
[Schüler] Die Duplikate sind nicht [unverständlich] >> Ja.
Denken Sie an die Manpage für uniq sagt Filter angrenzenden übereinstimmenden Zeilen.
Sie sind nicht benachbart sind, so wird es nicht filtern sie.
Wenn ich sie zuerst zu sortieren, ist eine Art names.txt gehen, um alle doppelten Zeilen zusammen.
So, jetzt sort names.txt ist, dass.
Ich werde zu wollen, dass als Eingang für uniq, welches verwenden | uniq.
Das gibt mir Joseph, RJ, Rob, Tommy,
und ich möchte, dass als Eingang für wc-l verwenden,
das wird mir 4.
Wie es hier sagt, was könnte Pipeline verwenden Sie?
Sie können eine Menge von Dingen wie mit einer Reihe von Befehlen zu tun
, wo Sie die Ausgabe eines Befehls als Eingabe für den nächsten Befehl.
Sie können eine Menge Dinge, viel kluge Dinge.
>> Haben Sie Fragen?
Okay.
Das war es für Pipes und Umleitungen.
>> Jetzt gehen wir zum eigentlichen Sachen, die Codierung Zeug.
Innerhalb dieses PDF, sehen Sie diesen Befehl,
und Sie wollen diesen Befehl in Ihrem Gerät laufen.
wget ist der Befehl für nur immer etwas aus dem Internet, im Grunde,
so wget und diese URL.
Wenn Sie zu dieser URL ging in Ihrem Browser, wäre es downloaden Sie diese Datei.
Ich klickte auf sie, so dass es die Datei heruntergeladen haben für mich.
Aber schriftlich wget dieses Ding in der Klemme
wird nur gehen, um es in Ihrem Endgerät herunterladen.
Ich habe section5.zip und Sie wollen section5.zip entpacken,
das wird Ihnen ein Ordner namens Abschnitt5,
was wird alle Dateien wir verwenden heute innerhalb der IT sind zu haben.
Da diese Programme 'file Namen vermuten lassen, sind sie ein bisschen buggy,
so dass Ihre Mission ist es, herauszufinden, warum mit gdb.
Hat jeder haben sie heruntergeladen / wissen, wie man sie heruntergeladen
in ihre Appliance? Okay.
>> Laufen ./buggy1, wird sie sagen Segmentation fault (core dumped),
denen zu jeder Zeit erhalten Sie einen segfault, es ist eine schlechte Sache.
Unter welchen Umständen bekommt man einen segfault?
[Schüler] Dereferenzierung eines NULL-Zeiger. >> Ja. Also das ist ein Beispiel.
Dereferenzierung eines Null-Zeiger Sie vorhaben, ein segfault zu bekommen sind.
Was für ein segfault Mittel Sie berühren Speicher sollten Sie sich nicht berühren.
So Dereferenzierung eines Null-Zeiger berührt Adresse 0,
und im Grunde alle Computer heute sagen, dass die Adresse 0 Speicher, den Sie nicht zu berühren ist.
Also das ist, warum Dereferenzierung eines Null-Zeiger führt zu einem segfault.
Wenn Sie nicht einen Zeiger zu initialisieren passieren, dann hat es eine Garbage-Wert,
und so, wenn Sie zu dereferenzieren es versuchen, in aller Wahrscheinlichkeit Sie berühren Speicher
das ist in der Mitte von Nirgendwo.
Wenn Sie geschehen, mit etwas Glück und der Müll-Wert
passiert, um irgend etwas zu zeigen auf dem Stack oder so etwas,
dann, wenn Sie Dereferenzierung des Zeigers, die Sie noch nicht initialisiert ist,
nichts schief gehen.
Wenn es aber darauf ist, sagen wir, irgendwo zwischen dem Stapel und dem Haufen,
oder es ist darauf nur irgendwo, dass ist nicht von Ihrem Programm noch verwendet werden,
dann sind Sie berühren Speicher sollte man nicht berühren und Sie segfault.
Wenn Sie schreiben eine rekursive Funktion und es rekursiv zu oft
und Ihr Stack wächst zu groß und die Stapel kollidiert in Dinge
dass es nicht mit zu kollidieren, Sie berühren Speicher sollte man nicht berühren,
so dass Sie segfault.
Das ist, was ein segfault ist.
>> Es ist auch aus dem gleichen Grund, dass wenn Sie eine Zeichenfolge wie -
gehen wir zurück zum vorherigen Programm.
In hello.c--ich bin gerade dabei, etwas anderes zu machen.
char * s = "Hallo Welt!";
Wenn ich * s = etwas oder s [0] = 'X';
so stellen hallo,. / hallo, warum, dass segfault?
Warum ist das segfault?
Was würden Sie erwarten passieren?
Wenn ich printf tat ("% s \ n", s), was würden Sie erwarten, gedruckt werden?
[Schüler] X hallo. >> Ja.
Das Problem ist, dass, wenn Sie eine Zeichenfolge wie diese zu erklären,
s ist ein Zeiger, gehen auf den Stapel geht,
und was s wird zeigen, ist diese Zeichenfolge, die in Nur-Lese-Speicher enthalten ist.
Also nur durch den Namen, Nur-Lese-Speicher, sollten Sie auf die Idee
dass, wenn Sie versuchen zu ändern, was in Nur-Lese-Speicher,
Sie tun etwas, das Sie nicht mit dem Gedächtnis tun sollte und Sie segfault.
Dies ist tatsächlich ein großer Unterschied zwischen char * s und char s [].
So char s [], jetzt diese Saite wird auf den Stapel gelegt werden,
und der Stapel nicht nur gelesen werden, was bedeutet, dass dies funktionieren sollte völlig in Ordnung.
Und das tut sie.
Beachten Sie, dass, wenn ich char * s = "Hallo Welt!", Ist s selbst auf dem Stack
aber s Punkte woanders, und dass irgendwo zufällig nur gelesen werden.
Aber char s [] ist nur etwas auf den Stapel.
Damit ist ein weiteres Beispiel für ein segfault geschieht.
>> Wir sahen, dass ./buggy1 in einem segfault geführt.
In der Theorie sollten Sie nicht zu buggy1.c sofort suchen.
Stattdessen werden wir es durch gdb aussehen.
Beachten Sie, dass, wenn Sie Segmentation fault (core dumped) zu erhalten,
erhalten Sie diese Datei über hier als Kern.
Wenn wir ls-l, werden wir sehen, dass der Kern ist in der Regel eine ziemlich große Datei.
Dies ist die Anzahl der Bytes der Datei, so dass es aussieht wie es 250-etwas Kilobyte ist.
Der Grund dafür ist, dass, was die Kernspeicherauszug tatsächlich
ist, wenn Ihr Programm abstürzt, der Zustand des Speichers Ihres Programms
bekommt nur kopiert und in dieser Datei.
Es wird in dieser Datei geworfen.
Dieses Programm, während es läuft, passiert eine Speicherauslastung von rund 250 Kilobyte haben,
und so, dass ist es, was wurde in diese Datei geworfen.
Jetzt können Sie diese Datei aussehen, wenn wir gdb buggy1 Kern zu tun.
Wir können nur tun gdb buggy1, und das wird einfach starten Sie gdb regelmäßig,
Verwendung buggy1 als Eingabedatei.
Aber wenn Sie gdb buggy1 Kern zu tun, dann ist es speziell gehen zu starten gdb
Dazu suchen Sie in diesem System Datei.
Und Sie sagen buggy1 mittels gdb kennt, dass Core-Datei von der buggy1 Programm kommt.
So gdb buggy1 Kern wird sofort bringen uns
, wo das Programm passiert zu beenden.
Wir sehen hier Programm mit Signal 11, Segmentation fault beendet.
Wir passieren eine Reihe von Montage, das ist wahrscheinlich nicht sehr hilfreich zu sehen.
Aber wenn Sie bt oder backtrace geben, das geht auf die Funktion sein
das gibt uns die Liste unserer aktuellen Stack-Frames.
So backtrace. Es sieht aus wie wir haben nur zwei Stack-Frames.
Die erste ist unsere Stack-Frame,
und der zweite ist der Stapelrahmen für diese Funktion, die wir in sein passieren,
das sieht aus wie wir haben nur die Assembler-Code für.
So gehen wir zurück in unsere Hauptfunktion
und zu tun, dass wir Rahmen 1 zu tun, und ich denke, wir können auch nach unten,
aber ich fast nie nach unten - oder nach oben. Yeah.
Rauf und runter. Up bringt Sie ein Stack-Frame, unten bringt Sie unten einen Stack-Frame.
Ich neige dazu, niemals, dass.
Ich habe gerade ausdrücklich sagen Rahmen 1, die dem Bild mit der Bezeichnung 1 gehen wird.
Frame 1 wird uns bringen in Haupt-Stack-Frame,
und er sagt, hier die Linie der Code, den wir passieren, um zu sein.
Wenn wir noch ein paar Zeilen Code wollte, können wir sagen, Liste,
und dass geht um uns alle Zeilen Code um ihn herum.
Die Linie, die wir am segfaulted betrug 6:
if (strcmp ("CS50 rocks", argv [1]) == 0).
Wenn es nicht offensichtlich ist, haben, können Sie es gerade bekommen von hier nur durch das Denken, warum es segfaulted.
Aber wir können noch einen Schritt weiter gehen und sagen: "Warum sollte argv [1] segfault?"
Lassen Sie drucken argv [1], und es sieht aus wie die 0x0, die NULL-Zeiger ist.
Wir strcmping CS50 Felsen und null, und so, das wird segfault.
Und warum ist argv [1] null?
[Schüler] Weil wir nicht geben keine Kommandozeilen-Argumente.
Yeah. Wir haben es nicht geben keine Kommandozeilen-Argumente.
So ./buggy1 wird nur gehen zu müssen argv [0] ./buggy1 sein.
Es ist nicht zu haben eine argv [1], so, das wird segfault.
Aber wenn, anstatt, ich CS50 zu tun, es geht zu sagen, Sie erhalten eine D
weil das ist, was es tun soll.
Mit Blick auf buggy1.c, es soll print "Sie erhalten eine D" -
Wenn argv [1] ist nicht "CS50 rocks", "Du bist ein D bekommen" else "Sie erhalten eine A!"
Also, wenn wir eine A wollen, müssen wir dies als wahr zu vergleichen,
was bedeutet, dass es auf 0 vergleicht.
So argv [1] muss "CS50 rocks" sein.
Wenn Sie, dass auf der Kommandozeile tun wollen, müssen Sie \ verwenden, um den Raum zu entkommen.
So CS50 \ Felsen und Sie erhalten eine A!
Wenn Sie das nicht tun den Backslash, warum das nicht funktioniert?
[Schüler] Es gibt zwei unterschiedliche Argumente. >> Ja.
Argv [1] wird CS50, und argv [2] wird Felsen. Okay.
>> Jetzt ./buggy2 wird wieder segfault.
Statt der Eröffnung es mit seinem Core-Datei, wir öffnen Sie einfach buggy2 direkt
so gdb buggy2.
Nun, wenn wir laufen nur unser Programm, dann wird es zu sagen Programm empfangene Signal SIGSEGV,
welches das segfault Signal, und hier ist es geschehen passiert.
Mit Blick auf unsere backtrace, sehen wir, dass wir in der Funktion oh_no waren,
die durch die Funktion dinky, die durch die Funktion binky genannt wurde genannt,
Das war nach den wichtigsten genannt.
Wir können auch die Argumente für diese Funktionen.
Das Argument für dinky und binky 1 war.
Wenn wir die Funktion oh_no Liste, sehen wir, dass oh_no ist nur tun, char ** s = NULL;
* S = "BOOM";
Warum wäre das nicht?
[Schüler] Sie können nicht Dereferenzierung den Null-Zeiger? >> Ja.
Dies ist nur zu sagen s NULL ist, unabhängig davon, ob dies geschieht, um ein char ** sein,
die, je nachdem, wie Sie interpretieren, könnte es ein Zeiger auf einen Zeiger auf eine Zeichenfolge
oder ein Array von Strings.
Es ist s ist NULL, so * s ist Dereferenzierung eines Null-Zeiger,
und so, das wird abstürzen.
Dies ist eine der schnellsten Möglichkeiten, wie Sie möglicherweise segfault können.
Es ist einfach erklärt eine Null-Zeiger und sofort Speicherzugriffsfehler.
Das ist, was oh_no tut.
Wenn wir ein Bild gehen, dann werden wir in der Funktion, die oh_no genannt bekommen.
Ich muss, dass sich zu tun.
Wenn Sie keinen einen Befehl, und Sie drücken Sie einfach erneut die Eingabetaste,
es wird nur wiederholen Sie den vorherigen Befehl, den Sie lief.
Wir sind in Bild 1.
Auflisten diesem Rahmen sehen wir hier unsere Funktion.
Können Sie die Liste wieder zu schlagen, oder können Sie die Liste 20 zu tun und es wird mehr aufzulisten.
Die Funktion dinky sagt, wenn i 1 ist, dann ist der oh_no Funktion gehen,
sonst zum slinky Funktion zu gelangen.
Und wir wissen, i ist 1, weil wir sehen, hier passiert
dass dinky wurde mit dem Argument 1 aufgerufen.
Oder Sie können einfach gedruckt i und es wird sagen i = 1 ist.
Wir sind derzeit in dinky, und wenn wir gehen einen anderen Rahmen, wissen wir, wir landen in binky.
Up. Jetzt sind wir in binky.
Auflisten diese Funktion - die Liste von vor der Pause unterbrach mich -
es begann, als ob i 0 ist, dann werden wir es nennen oh_no, sonst dinky nennen.
Wir wissen, ich war 1, so heißt dinky.
Und jetzt sind wir wieder in Haupt-und wichtigsten ist gerade dabei, int i = rand ()% 3;
Das ist gerade dabei, Ihnen eine Zufallszahl, die entweder 0, 1 oder 2 ist.
Es wird binky mit dieser Nummer anrufen, und es wird 0 zurück.
Mit Blick auf diese,
nur zu Fuß durch das Programm manuell ohne läuft es sofort,
Sie würden einen Haltepunkt an Haupt gesetzt, was bedeutet, dass, wenn wir das Programm ausführen
Ihr Programm läuft, bis es einen Haltepunkt trifft.
So läuft das Programm, wird es laufen und dann wird es die Hauptfunktion getroffen und nicht mehr ausgeführt.
Jetzt sind wir im Inneren von Haupt-, und Schritt oder nächste wird uns in die nächste Zeile des Codes zu bringen.
Sie können Schritt oder nächsten.
Schlagen nächsten, jetzt i hat rand ()% 3, so können wir den Wert von i print eingestellt wurde,
und es wird sagen i = 1 ist.
Nun ist es nicht egal, ob wir nächste oder Schritt.
Ich denke, es zählte im Vorjahr ein, aber wir würden wollen nächstes nutzen.
Wenn wir Schritt verwenden wir in die Funktion treten, was bedeutet, Blick auf die eigentliche Sache
Das ist innerhalb binky passiert.
Wenn wir das nächste zu verwenden, dann bedeutet es, gehen über die Funktion
und nur in die nächste Zeile des Codes in unsere Funktion zu gelangen.
Genau hier auf dieser Linie war ich bei, wo es heißt rand ()% 3;
wenn ich Schritt täte, würde es in die Umsetzung der rand gehen
und was dort vor sich geht, und ich konnte durch die rand-Funktion fort.
Aber ich weiß nicht über die Funktion rand kümmern.
Ich will einfach nur in die nächste Zeile des Codes im Hauptspeicher zu gehen, so dass ich weiter.
Aber jetzt weiß ich kümmern uns um die binky Funktion, so möchte ich in diesen Schritt.
Jetzt bin ich in binky.
Die erste Zeile des Codes wird sagen, wenn (i == 0), ich einen Schritt,
sehen wir uns am Ende auf dinky.
Wenn wir Liste Dinge, sehen wir, dass geprüft wird, i = 0.
i ist nicht gleich 0, so ging es in die else-Bedingung,
was wird dinky (i) nennen.
Sie könnten verwirrt werden.
Wenn Sie diese Zeilen direkt zu sehen, könnte man denken, wenn (i == 0),
okay, dann nahm ich einen Schritt zurück und jetzt bin ich an dinky (i),
Man könnte meinen, muss bedeuten, i = 0 oder so etwas.
Nein, es bedeutet nur, dass sie weiß, es kann direkt kleben an der Linie dinky (i).
Weil ich nicht 0 ist, ist der nächste Schritt nicht auf der anderen enden.
Else ist nicht eine Zeile es geht um zu stoppen ist.
Ist es nur geht, um in die nächste Zeile tatsächlich ausführen können, was dinky (i) gehen.
Der Schritt in dinky (i), sehen wir, wenn (i == 1).
Wir wissen, i = 1, so dass, wenn wir Schritt, wir wissen, wir werden bis zum Ende in oh_no
weil i = 1 ruft die Funktion oh_no, die Sie in Schritt kann
was wird eingestellt char ** s = NULL und sofort "BOOM".
Und dann tatsächlich Blick auf die Umsetzung der buggy2,
Dabei wird i gerade erst eine Zufallszahl - 0, 1 oder 2 - Berufung binky,
die, wenn i 0 ist es oh_no nennt, sonst dinky nennt, kommt die hier oben.
Wenn i 1 ist, rufen oh_no, sonst rufen slinky, die kommen hier
wenn i 2 ist, rufen oh_no.
Ich glaube nicht einmal, es ist ein Weg -
Hat jemand finden einen Weg, dies ein Programm, das nicht segfault wird?
Denn wenn ich etwas fehlt bin, wenn i 0 ist, werden Sie sofort segfault,
was Sie auf eine Funktion, wenn i 1 Sie segfault gehen,
was Sie zu einer Funktion, wenn i 2 segfault Sie gehen.
Also egal, was du tust, segfault Sie.
>> Ich denke, ein Weg zur Festsetzung wäre es anstatt das zu tun char ** s = NULL sein,
Sie könnten Platz für diesen String malloc.
Wir könnten malloc (sizeof) - sizeof was?
[Schüler] (char) * 5? >> Scheint dies richtig?
Ich nehme an, das wird funktionieren, wenn ich lief es tatsächlich, aber es ist nicht das, was ich suche.
Schauen Sie sich die Art der s. Wir fügen int *, so int * x.
Ich tun würde, malloc (sizeof (int)).
Oder wenn ich ein Array von 5 wollte, würde ich es tun (sizeof (int) * 5);
Was passiert, wenn ich ein int ** haben?
Was würde ich malloc?
[Schüler] Größe des Zeigers. >> Ja. (Sizeof (int *));
Das Gleiche gilt hier unten.
Ich möchte (sizeof (char *));
Dies wird Platz für die Zeiger, die auf "BOOM", betont zuzuweisen.
Ich brauche nicht, um Platz für "BOOM" selbst zuweisen
denn dies ist im Grunde gleichwertig zu dem, was ich vorhin gesagt habe
der char * x = "BOOM".
"BOOM" existiert bereits. Es passiert existieren in der Nur-Lese-Bereich des Speichers.
Aber es existiert bereits, was bedeutet diese Codezeile, wenn s ein char ** ist,
dann * s ist ein char * und du bist Einstellung dieses char * auf "BOOM" zeigen.
Wenn ich auf "BOOM" in s kopieren wollte, dann würde ich brauchen, um Platz für s zuzuweisen.
Ich werde tun, * s = malloc (sizeof (char) * 5);
Warum 5?
Warum nicht 4? Es sieht aus wie "BOOM" ist 4 Zeichen. >> [Schüler] Die Null-Zeichen.
Yeah. Alle Ihre Saiten werden das Null-Zeichen benötigen.
Jetzt kann ich so etwas wie strcat tun - Was ist die Funktion zum Kopieren eines Strings?
[Schüler] cpy? >> Strcpy.
Mann strcpy.
So strcpy oder strncpy.
strncpy ist ein bisschen sicherer, da Sie angeben können, wie viele Zeichen,
aber hier ist es egal, weil wir wissen.
So strcpy und schauen Sie in den Argumenten.
Das erste Argument ist unser Ziel.
Das zweite Argument ist unsere Quelle.
Wir gehen in unserem Ziel * Kopie S der Zeiger "BOOM".
Warum sollten Sie dies mit einem strcpy statt nur, was wir hatten, bevor
von * s = "BOOM"?
Es ist ein Grund, warum Sie dies tun wollen könnte, aber was ist das Grund?
[Schüler] Wenn Sie etwas in "BOOM" ändern möchten. >> Ja.
Jetzt kann ich etwas tun, s [0] = 'X';
weil s verweist auf dem Heap und diesem Raum auf dem Heap, dass s wird darauf
ist ein Zeiger, um mehr Platz auf dem Heap, die Speicherung von "BOOM" genannt wird.
So diese Kopie von "BOOM" wird in dem Heap gespeichert.
Es sind technisch zwei Exemplare von "BOOM" in unserem Programm.
Es ist das erste, das gerade durch diese "BOOM" string constant ist gegeben,
und die zweite Kopie von "BOOM", erstellt strcpy die Kopie von "BOOM".
Aber die Kopie von "BOOM" wird auf dem Heap gespeichert, und der Haufen, du bist frei zu ändern.
Der Haufen ist nicht nur gelesen, bedeutet so, dass s [0]
wird gehen zu lassen, ändern Sie den Wert von "BOOM".
Es gehen zu lassen, ändern Sie diese Zeichen.
>> Haben Sie Fragen?
Okay.
>> Bewegen Sie sich auf buggy3, lasst gdb buggy3.
Wir führen Sie es einfach und wir sehen bekommen wir einen segfault.
Wenn wir backtrace, gibt es nur zwei Funktionen.
Wenn wir gehen in unsere Funktion, sehen wir, dass wir auf dieser Linie segfaulted.
So gerade auf der Suche in dieser Zeile, int line = 0 for (; fgets dieses Zeug nicht gleich NULL;
Linie + +).
Unsere vorherigen Frame genannt wurde _IO_fgets.
Du wirst sehen, dass eine Menge mit integriertem C-Funktionen,
, dass, wenn Sie die segfault bekommen, wird es wirklich kryptisch Funktionsnamen werden
RS _IO_fgets.
Aber das geht auf diese fgets Anruf beziehen.
Irgendwo hier drinnen sind wir Speicherzugriffsfehler.
Wenn wir uns die Argumente an fgets betrachten, können wir drucken Puffer.
Lassen Sie drucken, wie a - Oh, nein.
Print wird nicht genau so, wie ich es will arbeiten.
Lassen Sie uns das eigentliche Programm zu suchen.
Buffer ist ein Zeichen-Array. Es ist ein Zeichen-Array von 128 Zeichen.
Wenn ich also sage Druckpuffer, es geht um jene 128 Zeichen zu drucken,
die ich schätze, ist, was erwartet wird.
Was ich suche, ist Drucken Sie die Adresse des Puffers,
aber das bedeutet nicht wirklich sagen mir viel.
Also, wenn ich sagen hier x-Puffer geschieht, zeigt er mir 0xbffff090,
die, wenn man aus früheren oder irgendwann erinnern, Oxbffff ein Stapel-ish Region neigt.
Der Stapel neigt dazu, irgendwo anfangen knapp 0xc000.
Nur indem wir diese Adresse, ich weiß, dass Puffer auf dem Stack passiert.
Neustart mein Programm, laufen, bis, puffern wir sahen, war diese Folge von Zeichen
das sind so ziemlich bedeutungslos.
Dann Druckdatei, was bedeutet Datei aussehen?
[Schüler] Null. >> Ja.
Datei ist eine vom Typ FILE *, so ist es ein Zeiger,
und der Wert von diesem Zeiger ist null.
So fgets wird versuchen, aus diesem Zeiger auf indirekte Weise zu lesen,
aber um diesen Zeiger zuzugreifen, muss es dereferenzieren.
Oder, um zu übersetzen, was es sollte, es dereferences es zeigen.
Also ist es Dereferenzierung eines Null-Zeiger und es segfaults.
Ich konnte es gestartet hat es.
Wenn wir unsere wichtigste Punkt zu brechen und zu laufen,
die erste Zeile Code ist char * filename = "NonExistent.txt";
Das sollte ein ziemlich großes Hinweis darauf, warum dieses Programm nicht.
Typing nächsten bringt mich in die nächste Zeile, wo ich diese Datei öffnen,
und dann habe ich sofort in unserer Linie, wo ich einst getroffen nächsten zu kommen, es geht um segfault.
Möchte jemand zu werfen, ein Grund, warum wir werden Speicherzugriffsfehler könnte?
[Schüler] Die Datei existiert nicht. >> Ja.
Dies soll ein Hinweis sein
, dass, wenn Sie eine Datei öffnen, müssen Sie überprüfen, ob die Datei tatsächlich existiert.
Also hier, "NonExistent.txt";
Wenn wir fopen Dateiname zum Lesen, müssen wir dann sagen,
if (file == NULL) und sagen printf ("Die Datei existiert nicht!"
oder - noch besser - filename); return 1;
So, jetzt überprüfen wir, wenn es NULL ist
bevor sie tatsächlich weiter und versuchen, aus dieser Datei gelesen.
Wir können Remake es nur zu, dass diese Arbeiten zu sehen.
Ich wollte eine neue Zeile einzufügen.
So, jetzt NonExistent.txt existiert nicht.
Sie sollten immer für diese Art der Sache zu prüfen.
Sie sollten immer prüfen, ob fopen NULL zurück.
Sie sollten immer überprüfen, um sicherzustellen, dass malloc nicht NULL zurückgeben,
oder du segfault.
>> Jetzt buggy4.c.
Running. Ich vermute, dies ist für die Eingabe oder möglicherweise Endlosschleife wartet.
Ja, es ist Endlosschleife.
So buggy4. Es sieht aus wie wir Endlosschleife sind.
Wir können an Haupt zu brechen, führen unser Programm.
In gdb, solange die Abkürzung Sie ist eindeutig
oder spezielle Abkürzungen, die sie bieten für Sie,
dann können Sie n zum nächsten anstatt zu tippen nächsten ganzen Weg zu verwenden.
Und jetzt, wo ich getroffen habe n einmal, kann ich einfach Enter drücken, um weiterzumachen nächsten
anstatt zu schlagen n Geben, n Geben, n die Eingabetaste.
Es sieht aus wie ich in einer Art for-Schleife, die Einstellung Arrays [i] auf 0 bin.
Es sieht aus wie ich bin nie brechen aus dieser for-Schleife.
Wenn ich i, drucken, so i = 2 ist, dann werde ich weiter gehen.
Ich werde print i, i = 3, dann werde ich weiter gehen.
Ich werde print i und i 3. Weiter, drucken i, i 4.
Eigentlich ist Druck sizeof (array), so Feldgröße von 20.
Aber wie es aussieht, es gibt einige spezielle gdb-Befehl für den Gang, bis etwas passiert.
Es ist wie Einstellen eines Zustands von dem Wert der Variablen. Aber ich erinnere mich nicht, was es ist.
Also, wenn wir weitermachen -
Was hast du gesagt? Was hast du zu bringen?
[Schüler] Hat anzuzeigen füge ich - >> Ja. So zeigen kann ich helfen.
Wenn wir zeigen Sie nur i, wird es hier aufgestellt, was den Wert von i ist
so dass ich nicht haben, um es auszudrucken jeder Zeit.
Hält man gerade dabei neben sehen wir 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5.
Etwas wird furchtbar schief, und ich wird auf 0 zurückgesetzt.
Mit Blick auf buggy4.c, sehen wir alles, was geschieht, ist int array [5];
for (i = 0, i <= sizeof (Array); i + +)
array [i] = 0;
Was wir sehen, dass ist hier falsch?
Als Hinweis, wenn ich tat das gdb buggy4 - lasst break main, run -
Ich habe Druck sizeof (array) nur um zu sehen, was der Zustand, in dem ich endlich ausbrechen sollte ist.
Wo bin ich? Habe ich laufen?
Ich habe noch nicht erklären.
So drucken Sie sizeof (array) und das ist 20,
die voraussichtlich seit meinem Array der Größe 5 und es ist von 5 Zahlen,
so dass die ganze Sache sollte 5 * sizeof (int) Bytes, wobei sizeof (int) tendiert bis 4 betragen.
So sizeof (array) ist 20.
Was soll das sein?
[Student] von sizeof (int) unterteilt. >> Ja, / sizeof (int).
Es sieht so aus, als gäbe es noch ein Problem hier. Ich denke, dies sollte nur sein <
da es so ziemlich immer ist <und nie <=.
Lassen Sie uns nun darüber, warum dies tatsächlich gebrochen zu denken.
Hat jemand errät Warum war ich wieder auf 0 zurückgesetzt durch jede Iteration der Schleife?
Das einzige, was im Inneren von hier, die passiert ist, dass array [i] wird auf 0 gesetzt ist.
Also irgendwie ist diese Codezeile verursacht unseren int i auf 0 gesetzt werden.
[Schüler] Könnte es sein, weil es das Überschreiben ist die Erinnerung an diesen Teil der i
wenn es denkt, dass es das nächste Element des Arrays? >> [Bowden] Ja.
Wenn wir über das Ende der unser Angebot gehen,
irgendwie, dass der Raum, dass wir das Überschreiben wird das Überschreiben der Wert von i.
Und so, wenn wir in buggy4 schauen, break main, run,
wir drucken die Adresse des i.
Es sieht aus wie es bffff124 ist.
Nun wollen wir drucken die Adresse array [0]. 110.
Was ist [1]? 114.
[2] 118.
11c, 120. array [5] ist bfff124.
So array [5] hat die gleiche Adresse wie i, was bedeutet, dass array [5] ist i bedeutet.
Wenn sie die gleiche Adresse haben, sind sie ein und dasselbe.
Also, wenn wir array [5] auf 0 setzen, setzen wir i auf 0 gesetzt.
Und wenn Sie darüber nachdenken, dies im Hinblick auf den Stapel,
int i wird zunächst erklärt, was bedeutet, ich bekomme etwas Platz auf dem Stack.
Dann array [5] zugeordnet ist, so dass dann 20 Byte auf dem Stack zugeordnet sind.
So i wird zuerst zugeteilt werden diese 20 Bytes bekommen zugeordnet.
So i geschieht direkt vor dem Array
und wegen der Art, wie ich schon sagte letzte Woche, soweit technisch der Stapel nach unten wächst,
wenn man in einem Array-Index, sind wir sichergestellt, dass die 0. Position in der Anordnung
geschieht immer vor dem ersten Position im Feld.
Dies ist eine Art, wie ich zog es letzte Woche.
Beachten Sie, dass an der Unterseite haben wir die Adresse 0 haben und an der Spitze haben wir Adresse Max.
Der Stack wächst ständig nach unten.
Sagen wir, wir reservieren i.
Wir verteilen integer i, das heißt, sagen wir einfach, hier integer i zugeordnet wird.
Dann ordnen wir unser Angebot von 5 Zahlen, was bedeutet, dass unter, dass
Da der Stack wächst nach unten, bekommen die 5 Zahlen zugeordnet.
Aber weil, wie Arrays arbeiten, wir sichergestellt, dass die erste Position im Array
hat immer eine Adresse kleiner als der zweite, was in dem Array.
So Arrayposition 0 muss immer zuerst geschehen im Speicher
während Arrayposition 1 muss danach passieren
und Array-Position 2 muss danach passieren,
was bedeutet, dass Arrayposition 0 würde irgendwo hier unten passieren,
Arrayposition 1 würde über das passieren
da bewegt sich bedeutet höhere Adressen, da die maximale Adresse ist hier oben.
So array [0] hier unten, array [1] hier oben, array [2] hier oben, array [3] hier oben.
Beachten Sie, wie, bevor wir integer zugeordnet i den ganzen Weg bis hier
wie wir weiter in unser Angebot zu bewegen, sind wir näher und näher an unsere integer i.
Es passiert einfach so, dass array [5], das ist eine Position jenseits unserer Array
Genau hier integer i zugeordnet werden passiert.
Also das ist der Punkt, wo wir gerade sind Schlagen der Platz auf dem Stack
Das war für integer i zugeordnet, und wir, daß auf 0 setzen.
>> Das ist, wie das funktioniert. Haben Sie Fragen? Yeah.
[Schüler] Never mind. Okay.
[Schüler] Wie vermeiden Sie diese Art von Fehlern?
Diese Art von Fehler? Verwenden Sie keine C als Programmiersprache.
Verwenden Sie eine Sprache, die Feldgrenzen überprüft hat.
Solange du vorsichtig bist, brauchen Sie nur zu vermeiden, gehen vorbei an den Grenzen des Arrays.
[Schüler] Also hier, wenn wir an die Grenzen des Arrays ging -
[Bowden] Das ist, wo die Dinge schief gehen beginnen. >> [Schüler] Oh, okay.
Solange Sie im Speicher für das Array zugeordnet bleiben, bist du in Ordnung.
Aber C führt keine Fehlerprüfung. Wenn ich array zu tun [1000], wird es gerne nur ändern, was passiert -
Es geht zum Anfang des Arrays, dann geht 1000 Positionen nach und setzt es auf 0 gesetzt.
Es macht keinen Überprüfung, dass oh, das eigentlich nicht haben 1000 Dinge in ihm.
1000 ist weit über das, was ich sollte sich ändern,
während Java oder etwas, das Sie bekommen array out of bounds index
oder Index out of bounds Ausnahme.
Das ist, warum viele Hochsprachen diese Dinge haben
wo, wenn Sie über die Grenzen des Arrays zu gehen, scheitern Sie
so dass Sie nicht ändern können, Dinge aus unter Ihnen
Und dann wird es viel schlimmer, als nur immer eine Ausnahme
sagen, dass Sie über das Ende des Arrays ging.
[Schüler] Und so sollten wir gerade änderte sich die <= nur <? >> [Bowden] Yeah.
Es sollte <sizeof (array) / sizeof (int) sein;
Seit sizeof (array) ist 20, aber wir wollen nur 5. >> [Schüler] Right.
Noch Fragen? Okay.
>> [Schüler] Ich habe eine Frage. >> Ja.
[Schüler] Was ist der eigentliche Array-Variable?
[Bowden] wie, was ist Array?
Array selbst ist ein Symbol.
Es ist nur die Adresse des Anfangs der 20 Bytes, die wir verweisen.
Sie können es als Zeiger denken, aber es ist ein konstanter Zeiger.
Sobald alles kompiliert, wird der Variablen-Array nicht mehr existieren.
[Schüler] Also, wie findet er die Größe des Array?
Größe des Feldes bezieht sich auf die Größe dieses Blocks, dass Symbol bezeichnet.
Wenn ich etwas tun, wie printf ("% p \ n", array);
lasst uns laufen lassen.
Was habe ich gerade falsch gemacht?
Array 'array' hier deklariert.
Oh, hier oben.
Clang ist klug, und es geschieht zu bemerken, dass ich das Array als 5 Elemente deklariert
aber ich bin in die Position 1000 der Indizierung.
Es kann das tun, weil diese nur Konstanten sind.
Es kann nur so weit gehen, zu bemerken, dass ich über die Grenzen des Arrays gehen.
Aber bevor, wenn wir i nicht korrekt bemerken,
es kann unmöglich festzustellen, wie viele Werte konnte ich übernehmen,
so kann es nicht bestimmen, dass ich über das Ende des Arrays gehen.
Das ist nur Clang ist clever.
>> Aber jetzt machen buggy4. So was mache ich falsch?
Implizit erklärt Library-Funktion 'printf'.
Ich werde zu wollen # include.
Okay. Jetzt läuft buggy4.
Drucken Sie den Wert des Feldes wie ich hier, ihn zu drucken als Zeiger
Drucke etwas, das wie folgt aussieht - bfb8805c - die einige Adresse ist
das ist im Stapel-ish Region.
Array selbst ist wie ein Zeiger, aber es ist nicht ein tatsächliches Zeiger,
Seit einem regulären Zeiger können wir ändern.
Array ist nur eine Konstante ist. Die 20 Blöcke des Speichers an der Adresse 0xbfb8805c starten.
So bfb8805c über diese Adresse +20- oder ich denke, -20 -
ist der gesamte Speicher für dieses Array zugeordnet.
Array, wird die Variable selbst nicht irgendwo gespeichert.
Wenn Sie die Erstellung der Compiler - Hand winken sie -
aber der Compiler wird nur einzusetzen, wo sie array zu sein weiß.
Es weiß, wo das Array beginnt,
und so kann es immer nur Dinge tun, in Bezug auf die Offsets von diesem Anfang.
Es braucht nicht eine variable sich Array repräsentieren.
Aber wenn ich so etwas wie int * p = array zu tun, jetzt p ist ein Zeiger, der auf diesem Array verweist,
und nun p eigentlich gar auf dem Stack vorhanden.
Ich bin frei, p ändern. Ich kann p = malloc.
So es ursprünglich wies auf Array, jetzt ist es verweist auf etwas Platz auf dem Heap.
Ich kann das nicht array = malloc.
Wenn Clang ist clever, wird es bei mir auf Anhieb schreien.
Eigentlich bin ich ziemlich sicher, gcc würde dies auch tun.
So Array-Typ 'int [5] "ist nicht übertragbar.
Sie können nicht zuordnen etwas zu einem Array-Typ
weil Array ist nur eine Konstante.
Es ist ein Symbol, das Verweise diese 20 Byte. Ich kann es nicht ändern.
>> [Schüler] Und wo ist die Größe des Arrays gespeichert?
[Bowden] Es ist nicht irgendwo gespeichert. Es ist, wenn es kompiliert ist.
Also, wo ist die Größe des Array gespeichert?
Sie können nur sizeof (Array) innerhalb der Funktion, dass das Array selbst erklärt.
Also, wenn ich eine Funktion, foo, und kann ich tun (int array [])
printf ("% d \ n", sizeof (array));
und dann hier unten Ich nenne foo (array);
Innere dieser Funktion - wir führen Sie es.
Dies ist Clang ist kluge wieder.
Es sagt mir, dass sizeof auf Array Funktionsparameter
wird Größe 'int *' zurückzukehren.
Dies wäre ein Fehler, wenn es nicht ist, was ich zu geschehen wollte.
Lasst uns tatsächlich auszuschalten Werror.
Warnung. Warnungen sind in Ordnung.
Es wird noch kompilieren, solange es eine Warnung aufweist.
. / A.out wird 4 zu drucken.
Die Warnung generiert wurde ist ein klarer Indikator, was falsch gelaufen ist.
Das int-Array wird nur gehen, um sizeof (int *) zu drucken.
Selbst wenn ich array [5] legte hier, es ist immer noch gerade dabei, sizeof (int *) zu drucken.
So, sobald Sie geben es in eine Funktion, die Unterscheidung zwischen Arrays und Zeiger
ist nicht existent.
Dies geschieht, um ein Array, das auf den Stapel erklärt wurde sein,
aber sobald wir an den Wert, dass 0xbf blah, blah, blah in dieser Funktion
dann Zeiger auf dieses Array auf dem Stack.
Das heißt also, dass sizeof gilt nur in der Funktion, die das Array deklariert wurde,
was bedeutet, dass, wenn Sie kompilieren diese Funktion,
wenn Clang durch diese Funktion geht, sieht es Array ist ein int-Array der Größe 5.
Also es sieht sizeof (array). Nun, das ist 20.
Das ist tatsächlich, wie sizeof arbeitet grundsätzlich für fast alle Fälle.
Sizeof ist keine Funktion, es ist ein Operator.
Sie rufen Sie nicht die sizeof Funktion.
Sizeof (int), wird der Compiler nur, dass bis 4 zu übersetzen.
Verstanden? Okay.
>> [Schüler] Also, was ist der Unterschied zwischen sizeof (array) in Haupt-und in foo?
Dies ist, weil wir sagen, sizeof (array), die vom Typ int * ist bist,
während das Array hier unten ist nicht vom Typ int *, es ist ein int-Array.
>> [Schüler] Also, wenn Sie den Parameter hatte array [] anstelle von int * array,
würde das bedeuten, dass man sich noch ändern array, weil es jetzt ein Zeiger ist?
[Bowden] Wie das? >> [Schüler] Yeah. Können Sie Array innerhalb der Funktion jetzt?
[Bowden] Man könnte Array in beiden Fällen ändern.
In beiden Fällen sind Sie frei zu sagen, array [4] = 0 ist.
[Schüler] Aber können Sie Arrays, auf etwas anderes?
[Bowden] Oh. Yeah. In jedem Fall - >> [Schüler] Yeah.
[Bowden] Die Unterscheidung zwischen array [] und ein int * array, gibt es keine.
Sie können auch einige mehrdimensionales Array hier
für einige praktische Syntax, aber es ist immer noch nur ein Zeiger.
Das bedeutet, dass ich frei array tun habe = malloc (sizeof (int)), und nun woanders zeigen.
Aber wie, wie dies immer und immer funktioniert,
Änderung dieses Array, indem sie verweisen auf etwas anderes
ändert nichts an dieser array hier unten, weil es eine Kopie des Arguments ist,
es ist nicht ein Zeiger auf dieses Argument.
Und tatsächlich, so wie weitere Anzeichen dafür, dass es genau das gleiche -
wir bereits gesehen, was Druck array Drucke -
was ist, wenn wir drucken die Adresse des Arrays oder die Adresse der Adresse des Arrays
, von denen entweder?
Lassen Sie ignorieren diese ein.
Okay. Das ist in Ordnung. Es läuft jetzt. / A.out.
Printing-Array, dann drucken Sie die Adresse des Arrays sind die gleiche Sache.
Array gerade nicht vorhanden ist.
Er weiß, wann Sie drucken Array, Sie drucken das Symbol, das den 20 Byte bezieht.
Drucken Sie die Adresse des Arrays, na ja, nicht Array nicht existieren.
Es muss nicht eine Adresse, so dass es nur druckt die Adresse jener 20 Byte.
Sobald Sie sich kompilieren, in der kompilierten buggy4 mögen. / A.out,
Array ist nicht existent.
Pointers existieren. Arrays nicht.
Die Blöcke des Speichers repräsentiert das Array noch existieren,
aber die variable Arrays und Variablen dieses Typs gibt es nicht.
Das sind, wie die wichtigsten Unterschiede zwischen Arrays und Zeiger
werden, sobald Sie Funktionsaufrufe zu machen, gibt es keinen Unterschied.
Aber innerhalb der Funktion, die das Array selbst erklärt wird, arbeitet sizeof anders
da Sie das Drucken der Größe der Blöcke statt der Größe des Typs,
und man kann es nicht ändern, weil es ein Symbol ist.
Drucken der Sache und die Adresse der Sache druckt die gleiche Sache.
Und das ist ziemlich viel es.
[Schüler] Könnte man sagen, dass man mehr Zeit?
Ich könnte etwas verpasst haben.
Printing-Array und Adresse des Arrays druckt die gleiche Sache,
während, wenn Sie drucken einen Zeiger gegen die Adresse des Zeigers,
die eine Sache, druckt die Adresse von dem, was Sie auf den Hinweis,
der andere gibt die Adresse des Zeigers auf dem Stack.
Sie können einen Zeiger, man kann es nicht ändern ein Array-Symbol.
Und sizeof Zeiger wird die Größe dieses Zeigers drucken.
So int * p sizeof (p) wird 4 zu drucken,
aber int array [5] print sizeof (array) wird auf 20 drucken.
[Schüler] So int array [5] druckt 20? >> Ja.
Das ist, warum innerhalb buggy4, wenn es um sizeof (array) werden verwendet
Diese tat i <20, ist das nicht das, was wir wollten.
Wir wollen i <5. >> [Schüler] Okay.
[Bowden] Und dann, sobald Sie vorbei in den Funktionen zu starten,
wenn wir das täten int * p = array;
Innere dieser Funktion können wir im Grunde mit p-und Array in genau der gleichen Weise,
mit Ausnahme der sizeof Problem und die sich verändernde Problem.
Aber p [0] = 1; ist die gleiche wie zu sagen array [0] = 1;
Und sobald wir foo (array) sagen, oder foo (p);
Innenseite des foo-Funktion, das ist das gleiche Gespräch zweimal.
Es gibt keinen Unterschied zwischen diesen zwei Anrufe.
>> Jeder gut auf, dass? Okay.
Wir haben 10 Minuten.
>> Wir werden versuchen, durch diesen Hacker Typer Programm zu erhalten,
Diese Website, die kam im letzten Jahr oder so etwas.
Es ist einfach sein soll wie du zufällig eingeben und er druckt -
Was auch immer Datei geschieht es geladen haben, ist, wie es du schreibst aussieht.
Es sieht aus wie eine Art von Betriebssystem-Code.
Das ist, was wir umsetzen wollen.
Sie sollten eine binäre ausführbare Datei namens hacker_typer
das braucht in einem einzigen Argument, die Datei "Hacker-Typ."
Starten der ausführbaren Datei sollte den Bildschirm
und dann ausdrucken ein Charakter aus der übergebenen Datei jedes Mal der Benutzer eine Taste drückt.
So beliebigen Tonart drücken, sollte es entfernt und stattdessen Drucken ein Zeichen aus der Datei
das ist das Argument.
Ich werde ziemlich viel sagen, was die Dinge, die wir gehen zu müssen, zu wissen, sind sind.
Aber wir wollen Sie bitte zuerst die termios Bibliothek.
Ich habe noch nie diese Bibliothek in meinem ganzen Leben verwendet, so hat es sehr minimal Zwecke.
Aber das wird die Bibliothek nutzen wir wegwerfen, das Zeichen, das Sie treffen können
wenn Sie in Standard in. eingeben
So hacker_typer.c, und wir gehen zu wollen, # include.
Mit Blick auf die Manpage für termios - ich vermute, dass es das Terminal OS oder so etwas -
Ich weiß nicht, wie es zu lesen.
Mit Blick auf diese, sagt er, um diese 2 Dateien enthalten, so werden wir das tun.
>> Das allererste, wollen wir in einem einzigen Argument, das die Datei sollten wir öffnen wird.
So was will ich tun? Wie kann ich überprüfen, ich habe ein einziges Argument?
[Schüler] Wenn argc es gleich. >> [Bowden] Yeah.
So if (argc = 2!) Printf ("usage:% s [Datei öffnen]").
So jetzt, wenn ich das ohne eine zweite Argument ausgeführt - oh, ich brauche die neue Linie -
Sie werden sehen, es sagt Nutzung:. / hacker_typer,
und dann das zweite Argument sollte die Datei Ich möchte zu öffnen sein.
Nun, was soll ich tun?
Ich möchte aus dieser Datei gelesen. Wie kann ich aus einer Datei lesen?
[Schüler] öffnen Sie es zuerst. >> Ja.
So fopen. Was bedeutet fopen aussehen?
[Schüler] Dateiname. >> [Bowden] Dateiname wird argv [1] sein.
[Schüler] Und dann, was Sie wollen damit zu tun, so dass die - >> [Bowden] Yeah.
Also, wenn Sie sich nicht erinnern, könnten Sie einfach tun, man fopen,
wohin es geht, ein const char * path, wobei Pfad Dateiname sein,
const char * mode.
Wenn Sie sich nicht erinnern, was Modus passieren, dann können Sie für den Modus zu suchen.
Innerhalb von Manpages, ist der Schrägstrich, was Sie verwenden können, um für Dinge zu suchen.
So tippe ich / Modus für den Suchmodus.
n und N sind, was Sie können, um durch die Suche nach Übereinstimmungen zu verwenden.
Hier heißt es das Argument mode zeigt auf einen String
beginnend mit einer der folgenden Sequenzen.
So r, Open Text-Datei zum Lesen. Das ist, was wir tun wollen.
Zum Lesen, und ich möchte zu speichern, dass.
Die Sache wird ein FILE * sein. Nun, was kann ich tun?
Gib mir eine Sekunde.
Okay. Nun, was kann ich tun?
[Schüler] Prüfen Sie, ob es NULL ist. >> [Bowden] Yeah.
Jedes Mal, wenn Sie eine Datei öffnen, stellen Sie sicher, dass Sie erfolgreich sind in der Lage, es zu öffnen.
>> Jetzt möchte ich, dass termios Dinge zu tun, wo ich zum ersten Mal las meine aktuellen Einstellungen möchten
und speichern Sie diese in etwas, dann möchte ich meine Einstellungen ändern
wegzuwerfen jedes Zeichen, dass ich geben,
und dann möchte ich, um diese Einstellungen zu aktualisieren.
Und dann am Ende des Programms, möchte ich ändern zurück zu meiner ursprünglichen Einstellungen.
So ist die Struktur wird vom Typ termios sein, und ich werde zwei von denen wollen.
Die erste wird mein current_settings sein,
und dann wirst meine hacker_settings sein.
Zuerst werde ich möchte meine aktuellen Einstellungen zu speichern,
dann werde ich zu wollen hacker_settings aktualisieren,
und dann so am Ende meines Programms, ich möchte um die aktuellen Einstellungen zurück.
So sparen aktuellen Einstellungen, die Art und Weise, die funktioniert haben wir Menschen termios.
Wir sehen, dass wir diese int tcsetattr, int tcgetattr haben.
Ich gehe in einem termios struct durch ihre Zeiger.
Die Art und Weise dies aussehen wird - ich habe schon vergessen, was die Funktion aufgerufen wurde.
Kopieren und einfügen.
So tcgetattr, dann will ich in der Struktur passieren, dass ich die Angaben speichern in,
was wird current_settings sein,
und das erste Argument ist der Deskriptor für das, was ich will, um die Attribute zu speichern.
Was die Dateideskriptor ist wie jedes Mal, wenn Sie eine Datei öffnen, wird es einen Dateideskriptor.
Wenn ich fopen argv [1], wird es einen Dateideskriptor, die Sie verweisen
wenn Sie zu lesen oder zu schreiben.
Das ist nicht der Dateideskriptor Ich möchte hier verwenden.
Es gibt drei Dateideskriptoren haben standardmäßig
das sind Standard in, Standardausgabe und Standardfehler.
Standardmäßig ich denke es ist Standard in 0 ist, Standardausgabe 1 ist und Standardfehler 2 ist.
So was will ich, um die Einstellungen zu ändern?
Ich möchte die Einstellungen, wenn ich traf ein Zeichen zu ändern,
Ich möchte, dass dieses Zeichen entfernt, anstatt ihn zu drucken auf dem Bildschirm.
Was stream - Standard, Standard out, oder Standard-Fehler -
reagiert auf Dinge, wenn ich auf der Tastatur eingeben? >> [Student] Standard in. >> Ja.
So kann ich entweder 0 oder ich kann stdin tun.
Ich erhalte die current_settings von Standard in.
>> Jetzt möchte ich diese Einstellungen zu aktualisieren,
so erste Ich werde in hacker_settings was meine current_settings sind kopieren.
Und wie structs Arbeit ist, wird es nur zu kopieren.
Diese kopiert alle Felder, wie man es erwarten würde.
>> Jetzt möchte ich einige der Felder zu aktualisieren.
Mit Blick auf termios, müssten Sie durch eine Menge von diesen gelesen
nur um zu sehen, was Sie suchen möchten,
aber die Flags, die Sie gehen zu wollen, zu suchen sind sind Echo,
so ECHO Echo Zeichen einzugeben.
Zuerst möchte ich eingestellt - ich habe schon vergessen, was die Felder.
Dies ist, was die Struktur aussieht.
So Eingabemodi Ich denke, wir ändern wollen.
Wir werden am Lösung suchen, um sicherzustellen, dass das, was wir ändern wollen.
Wir wollen lflag ändern, um zu verhindern, die im Wege alle diese aussehen.
Wir wollen die lokalen Modus zu ändern.
Sie müssten durch diese ganze Sache zu lesen, um zu verstehen, wo alles gehört
dass wir ändern möchten.
Aber es ist im Inneren des lokalen Modi, wo wir gehen zu wollen, um das zu ändern sind.
So hacker_settings.cc_lmode ist, was es heißt.
c_lflag.
Dies ist, wo wir in Bitoperatoren bekommen.
Wir sind irgendwie aus der Zeit, aber wir werden es ganz schnell gehen.
Dies ist, wo wir in bitweisen Operatoren zu erhalten,
wo ich glaube, ich sagte einmal vor langer Zeit, dass, wenn Sie sich mit Fahnen zu starten,
du gehst zu sein mit bitweisen Operator eine Menge.
Jedes Bit in der Flagge entspricht einer Art von Verhalten.
Also hier hat dieses Flag eine Reihe von verschiedenen Dingen, wo sie sich alle etwas anderes bedeuten.
Aber was ich tun will ist einfach abschalten Bit, das ECHO entspricht.
So drehen, dass der I do & = ¬ ECHO.
Eigentlich, denke ich, es ist wie Techo oder so etwas. Ich werde einfach noch einmal zu überprüfen.
Ich kann termios es. Es ist einfach ECHO.
ECHO wird ein einzelnes Bit sein.
¬ ECHO wird bedeuten, alle Bits auf 1 gesetzt sind, was bedeutet, alle Flags auf true gesetzt
mit Ausnahme der ECHO-Bit.
Mit Beendigung meiner lokalen Merker mit dieser, bedeutet dies, alle Flaggen, die derzeit auf true gesetzt
noch auf true gesetzt werden.
Wenn meine ECHO-Flag auf true gesetzt wird, dann wird dies zwangsläufig auf der ECHO-Flag auf false.
So diese Codezeile einfach schaltet die ECHO-Flagge.
Die anderen Zeilen Code, werde ich sie einfach kopieren Sie sie im Interesse der Zeit, und dann erklären sie.
In der Lösung, sagte er 0.
Es ist wahrscheinlich besser, explizit sagen stdin.
>> Beachten Sie, dass ich auch tun ECHO | ICANON hier.
ICANON bezieht sich auf etwas getrennt, die kanonische Modus bedeutet.
Was kanonischen Modus bedeutet in der Regel, wenn Sie mit der Eingabe out sind die Befehlszeile
Standard in nicht verarbeitet nichts, bis Sie newline getroffen.
Also, wenn Sie GetString, geben Sie ein paar Dinge, dann drückst du Zeilenumbruch.
Das ist, wenn es auf Standard eingeschickt
Das ist die Standardeinstellung.
Wenn ich abschalten kanonischen-Modus, jetzt jedes einzelne Zeichen drücken Sie
ist, was wird verarbeitet, was normalerweise etwas schlecht, weil es langsam, diese Dinge zu verarbeiten ist,
weshalb es gut ist, um es in ganze Zeilen zu puffern.
Aber ich will jedes Zeichen verarbeitet werden
da ich nicht wollen, dass es auf mich warten newline zu schlagen
bevor es alle Zeichen verarbeitet Ich habe tippen.
Dies schaltet kanonischen Modus.
Dieses Zeug bedeutet nur, wenn es verarbeitet tatsächlich Zeichen.
Dies bedeutet, verarbeiten sie sofort; sobald ich tippe sie zu verarbeiten.
Und dies ist die Funktion, die Aktualisierung meines Einstellungen für Standard-in,
und TCSA Mitteln tun es jetzt.
Die anderen Optionen werden warten, bis alles, was derzeit auf dem Strom verarbeitet wird.
Das spielt eigentlich keine Rolle.
Gerade jetzt meine Einstellungen ändern zu sein, was derzeit in hacker_typer_settings.
Ich glaube, ich nannte es hacker_settings, also lasst uns das ändern.
Ändern Sie alles hacker_settings.
>> Jetzt, am Ende unseres Programms werden wir zurückkehren möchten
zu dem, was derzeit innerhalb normal_settings,
was wird wie und normal_settings aussehen.
Beachten Sie, ich habe nicht alle meine normal_settings da ursprünglich bekommen es geändert.
Dann ändern Sie einfach sie zurück, gehe ich sie wieder am Ende.
Dies war das Update. Okay.
>> Nun innerhalb von hier werde ich nur erklären, den Code im Interesse der Zeit.
Es ist nicht so viel Code.
Wir sehen lesen wir ein Zeichen aus der Datei. Wir nannten es f.
Jetzt können Menschen fgetc, aber wie fgetc funktionieren wird
ist nur, es wird das Zeichen, das Sie gerade lesen oder EOF zurück,
das entspricht dem Ende der Datei oder des Fehlers geschieht.
Wir sind Looping, weiterhin ein einzelnes Zeichen aus der Datei gelesen,
bis wir aus Zeichen ausführen, um zu lesen.
Und während wir tun wollen, warten wir auf einen einzelnen Charakter von Standard in.
Jedes einzelne Mal, wenn Sie etwas eingeben in der Befehlszeile,
das ist in einem Charakter Lesen von Standard in.
Dann putchar ist eben das char lesen wir hier von der Datei in Standard-Out setzen.
Sie können Menschen putchar, aber es ist gerade dabei, in die Standardausgabe, es ist Ausdruck dieser Charakter.
Man könnte auch einfach printf tun ("% c", c); gleiche Idee.
Das wird den größten Teil unserer Arbeit zu tun.
>> Das letzte, was wir wollen, zu tun, ist nur fclose unserer Datei.
Wenn Sie nicht fclose, das ist ein Speicherverlust.
Wir wollen die Datei, die wir ursprünglich eröffnet fclose, und ich denke, das ist es.
Wenn wir das machen, hatte ich schon Probleme.
Mal sehen.
Was hat es beschweren?
Erwartete 'int', sondern Argument ist vom Typ 'struct _IO_FILE *'.
Wir werden sehen, ob das funktioniert.
Nur in C99 erlaubt. Augh. Okay, machen hacker_typer.
Jetzt bekommen wir weitere nützliche Beschreibungen.
So Schwarzarbeit Kennung 'normal_settings "zu verwenden.
Ich habe es nicht nennen normal_settings. Ich nannte es current_settings.
So ändern wir das alles.
Jetzt Übergabe des Arguments.
Ich werde diese 0 für jetzt machen.
Okay. . / Hacker_typer cp.c.
Ich habe auch nicht den Bildschirm am Anfang.
Aber man blickt auf die letzte Problem Satz zu sehen, wie Sie den Bildschirm zu löschen.
Es ist nur Ausdruck einige Zeichen
während dies zu tun, was ich tun will.
Okay.
Und darüber nachzudenken, warum dies notwendig, um 0 statt stdin sein,
die sollten # definieren 0,
dies wird beklagt, dass -
Vor wenn ich sagte, dass es Dateideskriptoren, aber dann haben Sie auch Ihren FILE *,
ein Datei-Deskriptor nur eine einzige Zahl,
während ein FILE * hat eine ganze Reihe von Sachen mit ihm verbunden.
Der Grund müssen wir auf 0 statt stdin sagen,
ist, dass die Standardeingabe ist ein FILE *, die zur Sache, die Referenzierung Dateideskriptor 0 wird betont.
Also auch hier, wenn ich fopen tun (argv [1], ich bin immer ein FILE * zurück.
Aber irgendwo in diesem FILE * ist eine Sache, die der Datei-Deskriptor für diese Datei.
Wenn Sie auf der man-Seite für offene aussehen, so dass ich glaube, du wirst zu tun haben, man 3 offen - nein -
Mann 2 offen - yeah.
Wenn Sie auf der Seite für offene betrachten, ist offen wie ein niedrigerer Ebene fopen,
und es ist wieder die eigentliche Datei-Deskriptor.
fopen macht ein paar Sachen auf der Oberseite offen,
die anstelle der Rücksendung nur, dass Dateideskriptor eine ganze Datei zurück * Zeiger
innerhalb dessen ist unser kleiner Dateideskriptor.
So Norm bezieht sich auf die FILE * Sache,
wobei 0 bezieht sich nur auf die Dateideskriptor Standard in sich.
>> Haben Sie Fragen?
[Lacht] blies durch, dass.
Gut. Wir sind fertig. [Lacht]
>> [CS50.TV]