Einführung

Einführung

Wir sind in unserer Reihe von Artikeln zur C -Entwicklung zu einem entscheidenden Punkt gekommen. Es ist auch nicht zufällig der Teil von C, der Anfängern viele Kopfschmerzen gibt. Hier kommen wir ins Spiel, und der Zweck dieses Artikels (sowieso einer von ihnen) besteht darin, die Mythen über Zeiger und C als eine Sprache zu entlarven, die schwer zu lernen und zu lesen ist. Trotzdem empfehlen wir mehr Aufmerksamkeit und ein bisschen Geduld und Sie werden sehen, dass Zeiger nicht so umwerfend sind, wie die Legenden sagen.

Definitionen und Warnungen

Es scheint natürlich und gesunder Menschenverstand zu sein, dass wir mit den Warnungen beginnen sollten, und wir empfehlen Ihnen von Herzen, sich an sie zu erinnern: Während Zeiger Ihr Leben als C -Entwickler erleichtern, werden sie auch erleichtert, aber sie auch dürfen Stellen Sie schwer zu findende Fehler und unverständliche Code ein. Sie werden sehen, wenn Sie weiter lesen, worüber wir sprechen und die Ernsthaftigkeit dieser Bugs, aber das Endergebnis ist, wie bereits gesagt, besonders vorsichtig sein.

Eine einfache Definition eines Zeigers wäre „eine Variable, deren Wert die Adresse einer anderen Variablen ist“. Sie wissen wahrscheinlich, dass Betriebssysteme beim Speichern von Werten mit Adressen umgehen, so wie Sie Dinge in einem Lagerhaus kennzeichnen würden, damit Sie eine einfache Möglichkeit haben, sie bei Bedarf zu finden. Andererseits kann ein Array als eine Sammlung von Elementen definiert werden, die nach Indizes identifiziert wurden. Sie werden später sehen, warum Zeiger und Arrays normalerweise zusammen präsentiert werden und wie Sie in C mit ihnen effizient werden können. Wenn Sie einen Hintergrund in anderen Sprachen auf höherer Ebene haben, sind Sie mit dem String-Datentyp vertraut. In C sind Arrays das Äquivalent von Variablen mit String-Typen, und es wird argumentiert, dass dieser Ansatz effizienter ist.



Zeiger

Sie haben die Definition eines Zeigers gesehen, jetzt beginnen wir mit eingehenden Erklärungen und natürlich Beispielen. Eine erste Frage, die Sie sich stellen können, lautet: „Warum sollte ich Zeiger verwenden?”. Obwohl ich über diesen Vergleich zugeflammt werde, nehme ich meine Risiko ein: Verwenden Sie Symlinks in Ihrem Linux -System? Auch wenn Sie selbst keine selbst erstellt haben, fasst Ihr System sie auf und macht die Arbeit effizienter. Ich habe einige Horrorgeschichten über hochrangige C -Entwickler gehört, die schwören, dass sie keine Zeiger benutzt haben, weil sie „schwierig“ sind, aber das bedeutet nur, dass der Entwickler inkompetent ist, nichts mehr. Außerdem gibt es Situationen, in denen Sie Zeiger verwenden müssen, damit sie nicht als optional behandelt werden dürfen, weil sie es nicht sind. Nach wie vor glaube ich daran, mit gutem Beispiel zu lernen, also hier geht es: hier:

int x, y, z; x = 1; y = 2; int *ptoi; /* ptoi ist und steht für Zeiger auf Ganzzahl*/ ptoi = & x; / * ptoi zeigt auf x */ z = *ptoi; / * z ist jetzt 1, xs Wert, zu dem ptoi zeigt */ ptoi = & y; / *ptoi zeigt jetzt auf y */

Wenn Sie verwirrt am Kopf kratzen, rennen Sie nicht weg: Es tut nur beim ersten Mal weh, wissen Sie. Gehen wir nach Linie und sehen, was wir hier getan haben. Wir haben zuerst drei ganze Zahlen deklariert, das sind X, Y und Z und gaben x- und y -Werte 1 bzw. 2. Dies ist der einfache Teil. Das neue Element kommt mit der Erklärung des variablen ptoi ein, nämlich a Zeiger auf eine Ganzzahl, so dass es Punkte auf eine Ganzzahl. Dies wird durch die Verwendung des Sterners vor dem Namen der Variablen erreicht und soll ein Umleitungsbetreiber sein. Die Zeile 'ptoi = & x;' bedeutet: "Ptoi zeigt jetzt auf X, was laut Ptois Erklärung oben eine ganze Zahl sein muss.". Sie können jetzt mit Ptoi arbeiten, wie Sie es mit x tun würden (na ja, fast). Wenn Sie dies wissen, ist die nächste Zeile das Äquivalent von 'z = x;'. Nächsten wir Dereferenz ptoi, was bedeutet, dass wir sagen: "Hör auf, auf X zu zeigen, und fangen Sie an, auf Y zu zeigen.". Eine wichtige Beobachtung ist hier.

[1] Variablen vom Typ Register sind eines der Elemente von C, die existieren, aber die Mehrheit der Programmierer meidet sie. Eine Variable mit diesem beigefügten Schlüsselwort deutet dem Compiler vor, dass sie häufig verwendet wird und in einem Prozessorregister für einen schnelleren Zugriff gespeichert werden sollte. Die meisten modernen Compiler ignorieren diesen Hinweis und entscheiden trotzdem selbst. Wenn Sie also nicht sicher sind, ob Sie sich registrieren müssen, tun Sie dies nicht.

Wir sagten, dass PTOI auf eine Ganzzahl verweisen muss. Wie sollten wir vorgehen, wenn wir einen generischen Zeiger wollten, damit wir uns keine Sorgen um Datentypen machen müssen? Geben Sie den Zeiger ein, um ungültig zu werden. Dies ist alles, was wir Ihnen sagen werden, und die erste Aufgabe besteht.



Arrays

Sie werden in diesem Unterkapitel sehen, warum wir darauf bestanden haben, Hinweise und Arrays in einem Artikel vorzustellen, obwohl das Risiko des Gehirns des Lesers überlastet wurde. Es ist gut zu wissen, dass Sie bei der Arbeit mit Arrays keine Zeiger verwenden müssen, aber es ist schön, dies zu tun, da die Operationen mit dem Nachteil von weniger verständlichem Code schneller sein werden. Eine Array -Erklärung ist das Ergebnis der Erklärung einer Reihe aufeinanderfolgender Elemente, die über Indizes wie SO verfügbar sind:

int a [5]; int x; a [2] = 2; x = a [2];

A ist ein 5-Element-Array, wobei das dritte Element 2 ist (die Indexnummerierung beginnt mit Null!), und x ist definiert als auch 2 ist 2. Viele Fehler und Fehler beim ersten Umgang mit Arrays sind, dass man das 0-Index-Problem vergisst. Als wir „aufeinanderfolgende Elemente“ sagten, meinten wir, dass es garantiert ist. Es gibt eine Datenstruktur in C, die als Enum bezeichnet wird, die das tut, aber wir werden uns noch nicht damit befassen. Ich habe ein altes Programm gefunden, das ich beim Lernen C mit Hilfe meines Freundes Google geschrieben habe, das die Charaktere in einer Zeichenfolge umkehrt. Hier ist es:

#include #include int main () char Stringy [30]; int i; Char C; printf ("Geben Sie eine Zeichenfolge ein .\ n "); fGets (Stringy, 30, stdin); printf (" \ n "); für(i = 0; i < strlen(stringy); i++) printf("%c", stringy[i]); printf("\n"); für(i = strlen (Stringy); i> = 0; i--) printf ("%c", Stringy [i]); printf ("\ n"); zurückkehren 0;  

Dies ist eine Möglichkeit, dies zu tun, ohne Zeiger zu verwenden. Es hat in vielerlei Hinsicht Fehler, aber es zeigt die Beziehung zwischen Strings und Arrays. Stringy ist ein 30-Charakter-Array, mit dem die Benutzereingabe geführt wird. Wir fragen also nach einer Zeichenfolge, speichern wir sie mit FGets im Array, druckt die Originalzeichenfolge, indem wir von der Stringy [0] beginnen und inkrementell mit einer Schleife fortfahren, bis die Zeichenfolge endet. Die umgekehrte Operation gibt das gewünschte Ergebnis: Wir erhalten erneut die Länge der Zeichenfolge mit strlen () und starten einen Countdown 'bis Null, dann drucken Sie das Zeichenfolgenzeichen mit dem Zeichen für Zeichen. Ein weiterer wichtiger Aspekt ist, dass jedes Zeichenarray in C mit dem Nullzeichen endet, das grafisch durch '\ 0' dargestellt wird.

Wie würden wir das alles mit Zeigern machen?? Seien Sie nicht versucht, das Array durch einen Zeiger auf Char zu ersetzen, das wird nicht funktionieren. Verwenden Sie stattdessen das richtige Tool für den Job. Verwenden Sie für interaktive Programme wie die oben genannten Zeichen von Zeichen mit fester Länge, kombiniert mit sicheren Funktionen wie FGets (), sodass Sie nicht von Pufferüberläufen gebissen werden. Für Stringkonstanten können Sie jedoch verwenden

char * myname = "David";

und dann die Funktionen, die Sie in der String zur Verfügung gestellt haben.H, manipulieren Sie Daten, wie Sie es für richtig halten. Apropos, welche Funktion würden Sie für Strings, die den Benutzer ansprechen, MyName hinzufügen möchten? Anstelle von "Bitte geben Sie eine Nummer ein", sollten Sie "David, bitte geben Sie eine Nummer ein".



Zeiger und Arrays

Sie können und werden ermutigt, Arrays in Verbindung mit Zeigern zu verwenden, obwohl Sie zunächst wegen der Syntax erschrocken sind. Im Allgemeinen können Sie alles mit Zeigern mit dem Vorteil der Geschwindigkeit auf Ihrer Seite ausführen. Sie denken vielleicht, dass es sich bei der heutigen Hardware nicht lohnt, Zeiger mit Arrays zu verwenden, nur um etwas Geschwindigkeit zu gewinnen. Wenn Ihre Programme jedoch an Größe und Komplexität wachsen, wird der Unterschied offensichtlicher. Wenn Sie jemals daran denken, Ihre Bewerbung auf eine eingebettete Plattform zu portieren, werden Sie sich selbst gratulieren. Wenn Sie verstanden haben, was bis zu diesem Zeitpunkt gesagt wurde, haben Sie keine Gründe, erschrocken zu werden. Nehmen wir an, wir haben eine Reihe von Ganzzahlen und wir möchten einen Zeiger auf eines der Elemente des Arrays erklären. Der Code würde so aussehen:

int myarray [10]; int *myptr; int x; myptr = & myarray [0]; x = *myptr;

Wir haben also ein Array namens Myarray, bestehend aus zehn Ganzzahlen, einem Zeiger auf eine Ganzzahl, die die Adresse des ersten Elements des Arrays erhält, und X, das den Wert des ersten Elements erhält über Ein Zeiger. Jetzt können Sie alle möglichen raffinierten Tricks machen, um sich durch das Array zu bewegen, wie

*(myptr + 1);

Das wird auf das nächste Element von MyArray hinweisen, nämlich Myarray [1].

Eine wichtige Sache, die zu wissen ist, und gleichzeitig eine, die die Beziehung zwischen Zeigern und Arrays perfekt veranschaulicht, ist, dass der Wert eines Array-Typ-Objekts die Adresse seines ersten (Null-) Elements ist. 0], dann myptr = myarray. Als eine Art Übung laden wir Sie ein, diese Beziehung ein wenig zu studieren und einige Situationen zu codieren, in denen Sie glauben, dass sie nützlich sein wird/könnte. Dies ist, was Sie als Zeigerarithmetik begegnen werden.

Überlegungen zu Saiten in C und Anrufen

Bevor wir gesehen haben, dass Sie entweder tun können

char *mystring; mystring = "Dies ist eine Zeichenfolge."

oder Sie können dasselbe tun, indem Sie verwenden

char mystring [] = "Dies ist eine Zeichenfolge.";

Im zweiten Fall ist MyString, wie Sie vielleicht geschlossen haben, ein Array, das groß genug ist, um die ihm zugeschriebenen Daten zu halten. Der Unterschied besteht darin, dass Sie durch die Verwendung von Arrays auf einzelnen Zeichen innerhalb der Zeichenfolge arbeiten können, während Sie den Zeigeransatz verwenden können. Es ist ein sehr wichtiges Thema, an das Sie sich daran erinnern können, dass Sie vor dem Compiler retten, wenn große Männer zu Ihnen nach Hause kommen und Ihrer Oma schreckliche Dinge tun. Ein wenig weiter, ein weiteres Problem, das Sie sich bewusst sein sollten, ist, dass, wenn Sie Zeiger vergessen, Anrufe in C getätigt werden nach Wert. Wenn also eine Funktion etwas aus einer Variablen benötigt, wird eine lokale Kopie durchgeführt und darauf werden Arbeiten erledigt. Wenn die Funktion jedoch die Variable verändert, werden Änderungen nicht reflektiert, da das Original intakt bleibt. Durch die Verwendung von Zeigern können Sie Anrufe verwenden durch Bezugnahme, Wie Sie in unserem Beispiel unten sehen werden. Das Aufrufen von Wert nach Wert kann auch ressourcenintensiv werden, wenn die bearbeiteten Objekte groß sind. Technisch gesehen gibt es auch einen Anruf von Zeiger, aber lassen Sie ihn für den Moment einfach aufbewahren.

Nehmen wir an, wir möchten eine Funktion schreiben, die eine Ganzzahl als Argument nimmt und sie mit einem gewissen Wert erhöht. Sie werden wahrscheinlich versucht sein, so etwas zu schreiben:

void incin (int a) a+= 20; 

Wenn Sie dies versuchen, werden Sie feststellen, dass die Ganzzahl nicht inkrementiert wird, da nur die lokale Kopie sein wird. Wenn Sie geschrieben hätten

void incin (int & a) a+= 20; 

Ihr ganzzahliges Argument wird mit zwanzig erhöht, was Sie wollen. Wenn Sie also noch einige Zweifel an der Nützlichkeit von Zeigern hatten, finden Sie hier ein einfaches, aber bedeutendes Beispiel.



Etwas fortgeschrittene Themen

Wir haben darüber nachgedacht, diese Themen in einen speziellen Abschnitt zu bringen. So…

Zeiger auf Zeiger

Ja, Zeiger sind Variablen wie jeder andere, sodass sie andere Variablen auf sie hinweisen können. Während einfache Zeiger, wie oben gesehen, eine Ebene „Zeigen“ haben, haben Zeiger auf Zeiger zwei, so dass eine solche Variable auf eine andere zeigt, die auf eine andere zeigt. Sie denken, das ist verrückt? Sie können Hinweise auf Hinweise auf Hinweise auf Hinweise auf… .ad infinitum, aber Sie haben bereits die Schwelle von geistiger Gesundheit und Nützlichkeit überschritten, wenn Sie solche Erklärungen erhalten haben. Wir empfehlen die Verwendung von CDECL, ein kleines Programm, das normalerweise in den meisten Linux -Distributen verfügbar ist, die zwischen C und C ++ und Englisch und umgekehrt „übersetzt“ werden. Ein Zeiger auf einen Zeiger kann also als als deklariert werden

int ** ptrtoptr;

Nach der Art und Weise, wie mehrere Zeiger nützlich sind, gibt es Situationen, in denen Sie Funktionen wie den obigen Vergleich haben, und Sie möchten einen Zeiger als Rückgabewert von ihnen erhalten. Möglicherweise möchten Sie auch eine Reihe von Strings, was eine sehr nützliche Funktion ist, wie Sie in einer Laune heraus sehen werden.

Mehrdimensionale Arrays

Die Arrays, die Sie bisher gesehen haben, sind eindimensional, aber das bedeutet nicht, dass Sie darauf beschränkt sind. Zum Beispiel kann ein bi-dimensionales Array in Ihrem Kopf als Array von Arrays vorgestellt werden. Mein Rat wäre, mehrdimensionale Arrays zu verwenden, wenn Sie das Bedürfnis haben. Wenn Sie jedoch gut mit einem einfachen, guten alten „eindimensionalen“ sind, verwenden Sie dies, damit Ihr Leben als Coder einfacher ist. Um ein bi-dimensionales Array zu deklarieren (wir verwenden hier zwei Dimensionen, aber Sie sind nicht auf diese Zahl beschränkt), werden Sie dies tun

 int bidimarray [4] [2];

Dies wird die Auswirkung haben, ein 4-mal-2-Ganzzahl-Array zu erklären. Um vertikal auf das zweite Element zugreifen (denken Sie an ein Kreuzworträtsel, wenn das hilft!) und das erste horizontal können Sie tun

Bidimarray [2] [1];

Denken Sie daran, dass diese Dimensionen nur für unsere Augen sind: Der Compiler verteilt Erinnerung und arbeitet mit dem Array auf die gleiche Weise. Wenn Sie also nicht die Nützlichkeit davon sehen, verwenden Sie es nicht. Ergo kann unser Array oben als als deklariert werden

int bidimarray [8]; / * 4 von 2, wie gesagt */


Kommandozeilenargumente

In unserer vorherigen Ausgabe der Serie haben wir über Main gesprochen und wie sie mit oder ohne Argumente verwendet werden kann. Wenn Ihr Programm es braucht und Sie Argumente haben, sind es char argc und char argv []. Jetzt, da Sie wissen, was Arrays und Zeiger sind, machen die Dinge viel sinnvoller. Wir haben jedoch darüber nachgedacht, hier ein bisschen detailliert zu werden. char *argv [] kann auch als char ** argv geschrieben werden. Warum denkst du, wie etwas Essen zum Nachdenken ist möglich, dass das möglich ist?? Bitte denken Sie daran, dass Argv für „Argument Vector“ steht und eine Reihe von Strings ist. Immer können Sie sich darauf verlassen, dass Argv [0] der Name des Programms selbst ist, während Argv [1] das erste Argument ist und so weiter. Ein kurzes Programm, um den Namen und die Argumente so zu sehen, würden so aussehen:

#include #include int main (int argc, char ** argv)  während(argc--) printf ("%s \ n", *argv ++); zurückkehren 0; 

Abschluss

Wir haben die Teile ausgewählt, die für das Verständnis von Zeigern und Arrays am wichtigsten aussahen, und haben absichtlich einige Themen wie Zeiger für Funktionen ausgelassen. Wenn Sie jedoch mit den hier vorgestellten Informationen zusammenarbeiten und die Übungen lösen, haben Sie jedoch einen ziemlich guten Start in diesem Teil von C, der als Hauptquelle für komplizierte und unverständliche Code angesehen wird.

Hier ist eine hervorragende Referenz zu C ++ - Zeigern. Obwohl es sich nicht um C handelt, sind die Sprachen verwandt, sodass der Artikel Ihnen dabei hilft, Zeiger besser zu verstehen.

Hier ist, was Sie als nächstes erwarten können:

  • ICH. C Entwicklung unter Linux - Einführung
  • Ii. Vergleich zwischen C und anderen Programmiersprachen
  • III. Typen, Operatoren, Variablen
  • Iv. Ablaufsteuerung
  • V. Funktionen
  • Vi. Zeiger und Arrays
  • Vii. Strukturen
  • Viii. Grundlegende I/O
  • Ix. Codierungsstil und Empfehlungen
  • X. Ein Programm erstellen
  • Xi. Verpackung für Debian und Fedora
  • Xii. Ein Paket in den offiziellen Debian -Repositories erhalten

Verwandte Linux -Tutorials:

  • Eine Einführung in Linux -Automatisierung, Tools und Techniken
  • Dinge zu installieren auf Ubuntu 20.04
  • Mastering -Bash -Skriptschleifen beherrschen
  • Verschachtelte Schleifen in Bash -Skripten
  • Mint 20: Besser als Ubuntu und Microsoft Windows?
  • Big Data Manipulation zum Spaß und Gewinn Teil 1
  • Dinge zu tun nach der Installation Ubuntu 20.04 fokale Fossa Linux
  • GDB -Debugging -Tutorial für Anfänger
  • Erweiterte Protokollierung und Prüfung unter Linux
  • Wie oft müssen Sie Ihren Linux -Server neu starten??