Frage

versuchen nur zu verstehen, wie ein einzelnes Zeichen in einem Array von Strings zu adressieren. Auch wird dies natürlich erlauben Sie mir Zeiger auf Zeiger zu verstehen, im allgemeinen Indizierung. Wenn ich char **a haben und ich möchte das 3. Zeichen der 2. Saite erreichen, funktionierts: **((a+1)+2)? Scheint, wie es sein sollte ...

War es hilfreich?

Lösung

Fast, aber nicht ganz. Die richtige Antwort lautet:

*((*(a+1))+2)

, weil Sie müssen zuerst de-Verweis auf eine der tatsächlichen Zeichenfolge Zeiger und dann an Sie de-Referenz, die Zeichenfolge auf die gewünschte Zeichenzeiger ausgewählt. (Beachten Sie, dass ich zusätzliche Klammer für Klarheit in der Reihenfolge der Operationen dort hinzugefügt).

Alternativ kann dieser Ausdruck:

a[1][2]

funktioniert auch! .... und vielleicht wäre bevorzugt, weil es die Absicht von dem, was Sie versuchen, mehr selbstverständlich zu tun ist, und die Notation selbst ist prägnanter. Dieses Formular kann nicht sofort offensichtlich, um Menschen in die Sprache neu sein, aber versteht, dass der Grund, warum die Notation Array funktioniert, weil in C, ein Array Indexierungsvorgang wirklich nur eine Abkürzung für den äquivalenten Zeiger Betrieb ist. das heißt: * (a + x) ist das gleiche wie ein [x]. Also, indem diese Logik auf die ursprüngliche Frage erstreckt, gibt es zwei getrennte Zeiger de verweis Operationen zusammen kaskadiert wobei der Ausdruck a [x] [y] ist äquivalent zu der allgemeinen Form * ((* (a + x)) + y).

Andere Tipps

Sie müssen keine Zeiger verwenden.

  

int main (int argc, char ** argv) {

     

printf ( "Das dritte Zeichen von   argv [1] [% C] \ n“, argv [1] [2]);.

     

}

Dann:

  

$ ./main hallo Das dritte Zeichen von   argv [1] [l].

Das ist eine Eins und eine l.

Sie können Zeiger verwenden, wenn Sie wollen ...

  

* (argv [1] 2)

oder auch

  

* ((* (a + 1)) + 2)

Als jemand oben erwähnt.

Das ist, weil Array Namen sind Zeiger.

IIRC, ein String ist eigentlich ein Array von Zeichen, so sollte diese Arbeit:

a[1][2]

Theres eine brillante C-Programmierung Erklärung im Buch Hacking die Kunst der Ausbeutung 2nd Edition von Jon Erickson, die allein Zeiger, Strings, eine Erwähnung wert für die Programmierung Erklärung Abschnitt wird https://leaksource.files.wordpress.com/2014 /08/hacking-the-art-of-exploitation.pdf.

Auch wenn die Frage bereits beantwortet wurde, jemand anderes wollen mehr wissen können folgende Highlights finden von Ericksons nützlich Buch einen Teil der Struktur hinter der Frage zu verstehen.

Header

Beispiele für Header-Dateien für variable Manipulation Sie wahrscheinlich verwenden werden.

stdio.h - http://www.cplusplus.com/reference/cstdio/

stdlib.h - http://www.cplusplus.com/reference/cstdlib/

string.h - http://www.cplusplus.com/reference/cstring/

limits.h - http://www.cplusplus.com/reference/climits/

Funktionen

Beispiele für allgemeine Funktionen werden Sie wahrscheinlich verwenden.

malloc () - http://www.cplusplus.com/reference/cstdlib/malloc/

calloc () - http://www.cplusplus.com/reference/cstdlib/calloc/

strcpy () - http://www.cplusplus.com/reference/cstring/strcpy/

Speicher

" ein kompilierten Programms Speicher in fünf Segmente unterteilt:.. Text, Daten, bss, Heap und Stack Jedes Segment stellt einen besonderen Teil des Speichers, der zur Seite für einen bestimmten Zweck gesetzt, um das Textsegment ist auch manchmal genannt das Code-Segment. Hier werden die montierten Maschinensprache Anweisungen des Programms befinden “.

" Die Ausführung von Befehlen in diesem Segment ist nichtlinear, dank der oben genannten High-Level-Kontrollstrukturen und Funktionen, die kompilieren in dem Zweig, springt und Anweisungen in Assemblersprache nennen. Als Programm ausführt, wird der EIP auf den ersten Befehl im Text-Segment ein. Das Prozessor dann folgt eine Ausführungsschleife, führt Folgendes aus: "

" 1. Liest die Anweisung, die EIP zeigt auf "

" 2. Fügt die Bytelänge des Befehls zu EIP "

" 3. Führt die Anweisung, die in Schritt gelesen wurde 1 "

" 4. Geh zurück zu Schritt 1 "

" Manchmal ist der Befehl wird ein Sprung oder ein Call-Befehl sein, die ändert die EIP an eine andere Adresse des Speichers. Der Prozessor nicht über die Änderung kümmern, weil sie die Ausführung der erwartete nicht-linear zu sein sowieso. Wenn EIP in Schritt 3 geändert wird, wird der Prozessor nur gehen zurück zu Schritt 1 und die Anweisung an der Adresse von was auch immer EIP wurde geändert “.

gefunden lesen .

" Schreibberechtigung wird im Textsegment deaktiviert, da es nicht verwendet wird, Variablen zu speichern, nur Code Dies verhindert, dass Menschen aus tatsächlich den Programmcode zu modifizieren; jeder Versuch, dieses Segment des Speichers zu schreiben, wird das dazu führen, Programm zu warnen den Benutzer, dass etwas Schlimmes passiert ist, und das Programm wird getötet. Ein weiterer Vorteil dieses Segment schreibgeschützt ist, ist, dass es kann zwischen verschiedenen Kopien des Programms geteilt werden, so dass mehrere Ausführungen des Programms zur gleichen Zeit ohne Probleme. Es sollte auch darauf hingewiesen, dass dieses Speichersegment eine feste Größe hat, da nichts jemals darin Änderungen “.

" Die Daten und bss Segmente werden verwendet, Programm zum Speichern von globalen und statischen Variablen. Das Datensegment wird mit den initialisierte globalen und statischen Variablen gefüllt, während das bss Segment mit ihren Pendants uninitialized gefüllt ist. Obwohl diese Segmente beschreibbar sind, haben sie auch eine feste Größe. Denken Sie daran, dass die globalen Variablen bestehen bleiben, trotz des funktionalen Zusammenhangs (wie die Variable j in den vorherigen Beispielen). Sowohl globale und statische Variablen sind in der Lage zu beharren, weil sie in ihrem eigenen Speichersegment gespeichert ist, “.

" Das Heap-Segment ist ein Segment des Speichers kann einen Programmierer direkt Steuerung. Blöcke des Speichers in diesem Segment zugewiesen werden könnenund für was auch immer der Programmierer brauchen könnte. Ein bemerkenswerter Punkt über den Haufen Segment ist, dass es nicht eine feste Größe ist, so kann es größer oder kleiner wachsen nach Bedarf “.

" die gesamte Speicher im Heap von allocator und deallocator Algorithmen verwaltet wird, das jeweils einen Bereich des Speichers in dem Heap für die Verwendung reservieren und entfernen Vorbehalte, der Teil des Speichers zu ermöglichen, für die späteren Reservierungen wiederverwendet werden. der Haufen wird wachsen und schrumpfen, je nachdem wie viel Speicher ist für den Gebrauch vorbehalten. Das bedeutet, einen Programmierer der Haufen mit Zuordnungsfunktionen können im laufenden Betrieb reservieren und die freie Speicher. Das Wachstum der der Haufen bewegt sich nach unten in Richtung auf höhere Speicheradressen “.

" Das Stack-Segment hat auch variabler Größe und wird als temporärer Scratch Pad dient zum Speichern lokale Funktionsvariablen und Kontextes während Funktion aufruft. Dies ist, was GDB Backtrace Befehl betrachtet. Wenn ein Programm eine Funktion aufruft, dass Funktion wird über einen eigenen Satz von übergebenen Variablen haben, und der Code der Funktion wird im Text (oder Code) Segment. Da der Rahmen an einem anderen Speicherort und die EIP muss sich ändern, wenn eine Funktion aufgerufen wird, wird der Stapel verwendet zu erinnern alle der übergebenen Variablen, die Lage der EIP nach der Funktion zurückkehren sollte ist abgeschlossen, und alle lokalen Variablen in von dieser Funktion. all diese Informationen gespeichert zusammen auf dem Stapel verwendet wird, was zusammen ein Stapelrahmen. der Stapel genannt wird enthält viele Stapelrahmen “.

" Im Allgemeinen Informatik gesehen ist ein Stapel eine abstrakte Datenstruktur, die häufig verwendet wird. Es first-in, liest-out (FILO) Bestellung hat , Das heißt, das erste Element, das in einen Stapel gelegt wird, ist das letzte Element aus ihm heraus zu kommen. Betrachten Sie es als Perlen auf einer Schnur setzen, die einen Knoten an einem Ende hat: Sie können nicht die erste Perle erhalten, bis Sie haben alle anderen Perlen entfernt. Wenn ein Element in einen Stapel gelegt wird, ist es als Schiebe bekannt, und wenn ein Element aus einem Stapel entfernt wird, nannte man das Knallen “.

" Wie der Name das Stapelspeichersegment impliziert wird, in der Tat, eine Stapel-Datenstruktur, die Stack-Frames enthält. Das ESP-Register verwendet wird, den Überblick über die Adresse des Endes des Stapels zu halten, die sich ständig verändert, wie Elemente in gedrückt werden und tauchte aus der IT. da diese sehr dynamische Verhalten ist, macht es Sinn, dass der Stapel ist auch nicht von einer festen Größe. im Gegensatz zu dem dynamischen Wachstum des Haufens, wie der Stapelwechsel s in der Größe, es wächst nach oben in einer visuellen Anzeige des Gedächtnisses, zu niedrigeren Speicheradressen “.

" Die FILO Natur eines Stapels könnte seltsam erscheinen, aber da der Stapel verwendet zum Speichern von Kontext ist, ist es sehr nützlich. Wenn eine Funktion aufgerufen wird, werden mehrere Dinge auf den Stapel zusammen in einem Stapelrahmen geschoben. Das EBP-Register manchmal genannt den Rahmenzeiger (FP) oder lokale Basis (LB) Zeiger -ist verwendete lokale Funktionsvariablen im aktuellen Stapelrahmen Bezug zu nehmen. Jeder Stack-Frame enthält die Parameter an die Funktion, die lokalen Variablen und zwei Zeiger, die notwendig sind Dinge so, wie sie waren zurück zu setzen: die gespeicherte Rahmenzeiger (SFP) und die Absenderadresse. Das SFP verwendet EBP auf den vorherigen Wert wiederherzustellen und die Absenderadresse EIP auf die nächste Anweisung wird verwendet, nach dem Funktionsaufruf gefunden wiederherzustellen. Dies stellt den funktionalen Kontext des vorherigen Stapels Rahmen “.

Strings

" In C wird eine Anordnung einfach eine Liste von n Elementen eines bestimmten Datentypen. Ein 20-Zeichen-Array ist einfach 20 benachbarte Zeichen im Speicher befanden. Arrays wird auch als Puffer bezeichnet “.

#include <stdio.h>

int main()
{
    char str_a[20];
    str_a[0] = 'H';
    str_a[1] = 'e';
    str_a[2] = 'l';
    str_a[3] = 'l';
    str_a[4] = 'o';
    str_a[5] = ',';
    str_a[6] = ' ';
    str_a[7] = 'w';
    str_a[8] = 'o';
    str_a[9] = 'r';
    str_a[10] = 'l';
    str_a[11] = 'd';
    str_a[12] = '!';
    str_a[13] = '\n';
    str_a[14] = 0;
    printf(str_a);
}

" In dem vorhergehenden Programm ein 20-Element-Zeichenfeld definiert ist als str_a, und jedes Element des Arrays geschrieben, eins nach dem anderen. Beachten Sie, dass die Zahl bei 0 beginnt, im Gegensatz zu 1. Beachten Sie auch, dass das letzte Zeichen ein 0 “.

" Der Charakter arra (Dies ist auch ein Null-Byte bezeichnet.)y definiert wurde, so werden 20 Bytes für die ihr zugeordneten, aber nur 12 dieser Bytes tatsächlich verwendet werden. Die Null-Byte-Programmierung am Ende wird als Trennzeichen verwendet, um jede Funktion zu sagen, dass mit der Zeichenfolge zu tun hat Recht, es zu stoppen Operationen. Die verbleibenden zusätzlichen Bytes sind nur Müll und werden ignoriert. Wenn ein Null-Byte in dem fünften Elemente des Zeichenfeldes eingeführt wird, werden nur die Zeichen von der Hallo printf () Funktion gedruckt werden würde .“

" Da jedes Zeichens in einem Zeichenfeld Einstellung ist mühsamer und Strings werden ziemlich oft, eine Reihe von Standardfunktionen verwendet wurde, für String-Manipulation geschaffen. Zum Beispiel kann die Funktion strcpy () wird eine Zeichenfolge aus einer Quelle kopieren zu einem Ziel, durch den Source-String iteriert und jedes Byte an das Ziel kopiert (und, nachdem es kopiert die null-Terminierung Byte Stoppen) “.

" Die Reihenfolge der Funktionen Argumente ist ähnlich wie Intel Baugruppe Syntax Ziel zuerst und dann Quelle. Das char_array.c Programm umgeschrieben werden kann strcpy () mit der gleichen Sache mit der String-Bibliothek zu erreichen. Die nächste Version das char_array Programms unten gezeigt enthält string.h, da es eine String-Funktion “.

verwendet
#include <stdio.h>
#include <string.h>

int main() 
{
    char str_a[20];
    strcpy(str_a, "Hello, world!\n");
    printf(str_a);
}

Weitere Informationen über die C-Strings

http://www.cs.uic.edu/~jbell/CourseNotes/C_Programming/CharacterStrings.html

http://www.tutorialspoint.com/cprogramming/c_strings.htm

Pointers

" Das EIP-Register ist ein Zeiger, der‚Punkte‘auf den aktuellen Befehl während eines Ausführungsprogrammes durch seine Speicheradresse enthält. Die Idee von Zeigern in C verwendet wird, auch. Da der physikalischen Speicher nicht tatsächlich bewegt werden müssen die Informationen in sie kopiert werden. es ist sehr rechenintensiv sein kann, große Teile des Speichers zu kopieren, indem verschiedene Funktionen oder an verschiedenen Orten eingesetzt werden. Dies ist auch teuer aus einem Speicher Standpunkt, da der Platz für die neue Ziel Kopie sein muss gespeichert oder zugewiesen, bevor die Quelle kopiert werden. Pointers eine Lösung für dieses Problem ist. Anstatt ein großen Speicherblock zu kopieren, ist es viel einfacher, um die Adresse zu übergeben von Anfang dieses Speicherblock “.

" Pointers in C definiert und wie jeder anderen Variable-Typ verwendet werden kann. Da der Speicher auf der x86-Architektur verwendet 32-Bit-Adressierung, Zeiger sind ebenfalls 32 Bits groß (4 Bytes). Pointers ist definiert durch Voranstellen ein Sternchen (*) an den Variablennamen. Anstatt eine Variable dieses Typs definieren, wird ein Zeiger als etwas definiert, das auf die Daten dieses Typs zeigt. Das pointer.c Programm ist ein Beispiel eines Zeigers mit dem char Daten verwendet wird Typ, der nur 1 Byte groß ist “.

#include <stdio.h>
#include <string.h>

int main() 
{
    char str_a[20]; // A 20-element character array
    char *pointer; // A pointer, meant for a character array
    char *pointer2; // And yet another one
    strcpy(str_a, "Hello, world!\n");
    pointer = str_a; // Set the first pointer to the start of the array.
    printf(pointer);
    pointer2 = pointer + 2; // Set the second one 2 bytes further in.
    printf(pointer2); // Print it.
    strcpy(pointer2, "y you guys!\n"); // Copy into that spot.
    printf(pointer); // Print again.
}

" Da die Kommentare im Code angeben, der erste Zeiger am Anfang des Zeichenfeldes gesetzt. Wenn das Zeichen Array wie folgt Bezug genommen wird, es ist eigentlich ein Zeiger selbst. Dies ist, wie dieser Puffer war vergangen als Zeiger auf die printf () und strcpy () -Funktionen zuvor. der zweite Zeiger mit der ersten Zeiger-Adresse festgelegt ist und zwei, und dann werden einige Dinge gedruckt (in der Ausgabe unten) .“

reader@hacking:~/booksrc $ gcc -o pointer pointer.c
reader@hacking:~/booksrc $ ./pointer
Hello, world!
llo, world!
Hey you guys!
reader@hacking:~/booksrc $

" Der Adressoperator oft in Verbindung mit Zeigern verwendet wird, da Zeiger Speicheradressen enthalten. Das Programm zeigt addressof.c der Adressoperator verwendet wird, um die Adresse eines Integer-Variable zu setzen in einen Zeiger. Diese Zeile ist fett dargestellt unter “.

#include <stdio.h>

int main() 
{
    int int_var = 5;
    int *int_ptr;
    int_ptr = &int_var; // put the address of int_var into int_ptr
}

" Ein zusätzlicher unärer Operator genannt Dereferenzierungsoperator mit Zeigern zur Verwendung existiert. In der Adresse Dieser wird von einem Operator der Daten zurück, der Zeiger zeigt auf, statt die Adresse selbst. Es hat die Form eines Sterns gefunden vor dem Variablennamen, ähnlich wie bei der Deklaration eines Zeigers. wieder einmal besteht der Dereferenzierungsoperator sowohl in GDB und in C “.

" Ein paar Ergänzungen der addressof.c code (in addressof2.c gezeigt) all diese Konzepte demonstrieren. Die hinzugefügte printf () Funktionen Format verwenden Parameter, die ich im nächsten Abschnitt erläutern würde. Vorerst konzentrieren sich nur auf die Programme Ausgabe “.

#include <stdio.h>

int main() 
{
    int int_var = 5;
    int *int_ptr;
    int_ptr = &int_var; // Put the address of int_var into int_ptr.
    printf("int_ptr = 0x%08x\n", int_ptr);
    printf("&int_ptr = 0x%08x\n", &int_ptr);
    printf("*int_ptr = 0x%08x\n\n", *int_ptr);
    printf("int_var is located at 0x%08x and contains %d\n", &int_var, int_var);
    printf("int_ptr is located at 0x%08x, contains 0x%08x, and points to %d\n\n", &int_ptr, int_ptr, *int_ptr);
}

Wenn die unäre Operatoren mit Zeigern verwendet werden, kann die Adressoperator gedacht werden nach hinten zu verschieben, zu, während der Dereferenzierungsoperator nach vorne in Richtung bewegt sich der Zeiger zeigt “.

Erfahren Sie mehr über Pointers & Speicherzuweisung

Professor Dan Hirschberg, Institut für Informatik, Universität von Kalifornien auf Computerspeicher https://www.ics.uci.edu/~dan/class/165/notes/memory.html

http://cslibrary.stanford.edu/106/

http://www.programiz.com/c-programming/c-dynamic-memory-allocation

Arrays

Theres ein einfaches Tutorial auf multidimensionalen Arrays von einem Kerl namens Alex Allain verfügbar hier http://www.cprogramming.com/tutorial/c/lesson8.html

Theres Informationen über Arrays von einem Kerl namens Todd A Gibson verfügbar hier http://www.augustcouncil.com/~tgibson/tutorial/arr.html

Iterate ein Array

#include <stdio.h>

int main() 
{

    int i;
    char char_array[5] = {'a', 'b', 'c', 'd', 'e'};
    int int_array[5] = {1, 2, 3, 4, 5};
    char *char_pointer;
    int *int_pointer;
    char_pointer = char_array;
    int_pointer = int_array;

    for(i=0; i < 5; i++) { // Iterate through the int array with the int_pointer.
        printf("[integer pointer] points to %p, which contains the integer %d\n", int_pointer, *int_pointer);
        int_pointer = int_pointer + 1;
    }

    for(i=0; i < 5; i++) { // Iterate through the char array with the char_pointer.
        printf("[char pointer] points to %p, which contains the char '%c'\n", char_pointer, *char_pointer);
        char_pointer = char_pointer + 1;
    }

}

verketteten Listen vs Arrays

Arrays sind nicht die einzige Option zur Verfügung, Informationen über verlinkte Liste.

http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_linklist.aspx

Fazit

Diese Information wurde geschrieben einfach auf einige weitergeben, was ich während meiner Forschung über das Thema gelesen haben, die anderen helfen könnten.

Zitat aus der Wikipedia Artikel auf C-Pointer -

C, array Indexierungs wird formal in Bezug auf die Zeigerarithmetik definiert sind; das ist, die Sprachspezifikation erfordert, dass array [i] * zu entsprechen (array + i). So ist in C, können Arrays auf aufeinanderfolgende Speicherbereiche gedacht als Zeiger werden (ohne Lücken), und die Syntax für Arrays Zugriff ist identisch für das, was zu dereferenzieren verwendet werden kann, Zeiger. Zum Beispiel kann ein Array deklariert und auf die folgende Weise verwendet werden:

int array[5];      /* Declares 5 contiguous (per Plauger Standard C 1992) integers */
int *ptr = array;  /* Arrays can be used as pointers */
ptr[0] = 1;        /* Pointers can be indexed with array syntax */
*(array + 1) = 2;  /* Arrays can be dereferenced with pointer syntax */

So, als Antwort auf Ihre Frage! - Ja , Zeiger auf Zeiger überhaupt ohne jede Art von anderer Erklärung als Array verwendet wird

Versuchen a[1][2]. Oder *(*(a+1)+2).

Grundsätzlich Array Referenzen sind syntaktischer Zucker für Zeiger dereferenzierenden. a [2] ist das gleiche wie ein + 2, und auch die gleichen wie 2 [a] (wenn Sie wirklich nicht lesbaren Code wollen). Ein Array von Zeichenketten ist das gleiche wie ein Doppelzeiger. So können Sie die zweite Zeichenfolge extrahieren entweder mit einem [1] oder *(a+1). Anschließend können Sie das dritte Zeichen in dieser Zeichenkette finden (nennen wir es ‚b‘ vorerst) mit entweder b [2] oder *(b + 2). Setzt man den ursprünglichen zweiten String für 'b', landen wir mit entweder a [1] [2] oder *(*(a+1)+2).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top