Frage zu Pointern



  • Es läuft darauf hinaus, dass man ein Array an manchen Stellen wie einen Pointer behandeln kann (bzw. kompliziert: den Namen des Arrays als Zeiger auf das erste Arrayelement).
    Das ist ein altes, verwirrendes Thema, das unter diesem Link: http://c-faq.com/aryptr/index.html ganz gut aufgeklärt wird. 🙂



  • Arrays können über ihren Namen wie ein Pointer angesprochen werden. Der NAme verweist auf das erste Element vom Array.

    Das ist die Gemeinsamkeit von Arrays und Pointern. Leider führt das gerne zum Missverständnis das Arrays und Pointer gleich sind.

    Andererseits kann man dadurch Pointer wie Arrays ansprechen:

    char* meinstring = "Hallo!";
    printf( "Erster Buchstabe: %c %c %c\n, *(meinstring+0), *meinstring, meinstring[0] ); 
    
    int array[] = { 11, 12, 13, 14 };
    printf( "%i %i\n", *(array+3), array[3] );
    


  • Hey, vielen Dank für die Antworten! Habe mir den Link mal zu meinen Lesezeichen hinzugefügt.

    Und Danke, dass man hier mal sinnvolle Antworten bekommt und kein "Falscher Bereich", "Keine Anfängerfragen", "Benutze die Suchfunktion"… Big respect, tolles Forum! 👍



  • Du wirst früher oder später merken, dass es auch als C# Programmierer relativ wichtig ist zu wissen was Pointer sind, bzw. was man damit anstellen kann. Alleine schon um die Funktionsweise des Garbage Collectors und so manch anderem Konzept (Type Marshalling mit P/Invoke, ...) zu verstehen und mit ihren Konsequenzen umgehen zu können.

    Die Aussage von DirkB stört mich allerdings etwas, so wie sie da steht. Arrays sind sehr wohl das Selbe wie Pointer - zumindest dann wenn es um den Zugriff geht.

    Die Definition von einem Array hat natürlich überhaupt nichts gemein mit der Definition eines Pointers bzw. der eventuell anschließenden dynamischen Speicherallokation (vgl. malloc()) - das sind zwei grundlegend unterschiedliche Mechanismen. Btw. die gepostete Seite finde ich auch toll, werde sie in meinen Schulungen weiterempfehlen.

    Wenn ich allerdings folgendes mir ansehe:

    char test[] = { 'a', 'b', 'c', 'd' };
    
    char* ptr = &test[2];
    printf("%c", &ptr - 1); // b
    
    printf("%c", ptr[-1]); // b
    

    erkenne ich, dass beim Zugriff auf ein Array nichts anderes als Pointerarithmetik passiert.

    Der Compiler bzw. die Laufzeit errechnet die tatsächliche Speicheradresse folgendermaßen:

    Tatsächliche Speicheradresse = offset + base + (index * sizeof(type))

    • offset wird dabei entweder (so wie in diesem Fall, da Stackspeicher) vom Compiler, oder vom Betriebssystem (bei Verwendung von malloc() zb.) festgelegt.
    • base ist die Basisadresse des Arrays.
    • index ist der Index den du beim Arrayzugriff angibst.
    • sizeof(type) gibt dir die Größe eines einzelnen Arrayelements in bytes zurück - in diesem Beispiel 1, weil char in C auf 1 byte standardisiert ist (Achtung: evtl. späterer Fallstrick: char ist in C# 2 byte groß!)

    Beim Zugriff über einen klassischen Pointer fällt lediglich der geklammerte Teil mit dem Index weg. Ansonsten ist die interne Arbeitsweise genau gleich.

    Versuche mal folgendes und es wird vielleicht noch etwas verständlicher:

    #include <stdio.h>
    
    int main (int argc, const char * argv[])
    {
        char array[] = { 0x11, 0x22, 0x33, 0x44 };
    	int condensed = 0x11223344;
    
    	int* intPtr = (int*)&array[0];
    	printf("%x\n", *intPtr);
    	//intPtr++; // (Keine gute Idee, da ein ++ hier um 4 byte springen würde,
    	            // vorausgesetzt sizeof(int) == 4.
    
    	short* shortPtr = (short*)&array[0];
    	printf("%x\n", *shortPtr);
    	shortPtr++;
    	printf("%x\n", *shortPtr);
    	shortPtr = &shortPtr[-1];
    	printf("%x\n", *shortPtr); // Wieder das 'alte' Ergebnis
    
    	// Umgekehrt geht das natürlich auch
    	char* charPtr = (char*)&condensed;
    	for (int i = 0; i < sizeof(int); i++) // ++ ist hier ausreichend, da sizeof(char) immer == 1
    		printf("%x ", *(charPtr++));
    
    	printf("\n");
    
    	shortPtr = (short*)&condensed;
    	for (int i = 0; i < sizeof(int); i += sizeof(short))
    		printf("%x ", *(shortPtr++));
    
        return 0;
    }
    

    Hoffe geholfen und nicht für mehr Verwirrung gesorgt zu haben 😉

    Beste Grüße,

    Alexander



  • picaschaf schrieb:

    ...
    Die Aussage von DirkB stört mich allerdings etwas, so wie sie da steht. Arrays sind sehr wohl das Selbe wie Pointer - zumindest dann wenn es um den Zugriff geht.

    Mit deiner Einschränkung danach behauptest du auch nichts anderes als ich.

    Aber wie sieht es denn mit dem benötigten Speicherplatz und Arrays als lvalue aus?

    // Typischer Speicherbedarf auf 32-Bit Systemen
    char test[] = { 'a', 'b', 'c', 'd' }; // belegt 4 Bytes für das Array
    char *ptest = { 'a', 'b', 'c', 'd' }; // belegt 4 Bytes für das Array + 4 Bytes für den Pointer
    
    char* ptr = &test[2];   // belegt 4 Bytes für den Pointer
    printf("%c", &ptr - 1); // ?  sollte das nicht *(ptr-1) sein?
    
    printf("%c", ptr[-1]); // b 
    
    test = ptest; // lvalue [b]geht nicht[/b]
    ptest = test; // geht
    

    Deshalb nochmal: Arrays und Pointer sind nicht das Selbe.

    Man könnte ja auch auf den Gedanken kommen double und int wären das selbe. Mit beiden kann man rechnen 😃



  • DirkB schrieb:

    picaschaf schrieb:

    ...
    printf("%c", &ptr - 1); // ? sollte das nicht *(ptr-1) sein?

    Ist natürlich ein Fehler, ebenso wie

    int main (int argc, const char * argv[])
    

    nicht standardkonform ist, ebenso wie es akademische, praxisirrelevante Betrachtungen sind, Annahmen darüber zu treffen, wie wohl der Compiler bei der Codeerzeugung für Pointerarithmetik vorgeht, weil nicht der Weg sondern das Ergebnis spezifiziert ist.
    Weiterhin ist ein Zeiger gemäß ANSI Standard ein <modifiable lvalue>, ein Array niemals, schon mal versucht ++array?
    Aus dergleichen Verwendungsweise des Subscript-Operators für Zeiger und Arrays die Gleichheit derselben abzuleiten zeugt von beschränktem Horizont.
    Das Selbe schreibt man übrigens dasselbe außerdem meinte der C# Experte hier wohl dasgleiche.



  • Wutz, du bist wohl offensichtlich ausschließlich darauf aus hier rumzutrollen. Das kannst du dir getrost sparen - braucht hier niemand.

    Um auf einen ersten Punkt trotzdem einzugehen: Lies noch einmal genau den Standard bevor du hier große Töne spuckst. Im Standard ist festgelegt, dass main() 1. einen int oder kompatible zurückgibt, 2. dieser int hat nie einen negativen Wert und 3. der zweite Parameter ist ein Array von Strings oder(!) kompatible. Damit ist diese Definition standardkonform!

    Im Übrigen ist sie sogar besser als das was so oft rumgeistert - wer will schon die Parameter verändern?! Btw. ist das die Standarddefinition in Xcode.

    http://std.dkuug.dk/JTC1/SC22/WG14/www/docs/n843.htm

    @DirkB: Ja da hat sich ein Fehler eingeschlichen. Das Snippet hatte ich nicht compiliert.



  • Nochmal kurz wegen: printf("%c", &ptr - 1);

    Genau das & geht bei einem Pointer. Bei einem Array nicht.
    Und &ptr ist etwas komplett anderes als &test[0]



  • DirkB schrieb:

    Nochmal kurz wegen: printf("%c", &ptr - 1);

    Genau das & geht bei einem Pointer. Bei einem Array nicht.
    Und &ptr ist etwas komplett anderes als &test[0]

    Deswegen ist es auch in dem Codestück ein Fehler - habe dir ja auch nicht widersprochen.

    &(*ptr) == &test[0]

    wäre gültig, wenn auch sinnlos.



  • picaschaf schrieb:

    Arrays sind sehr wohl das Selbe wie Pointer

    Aber das bleibt doch falsch, und darum ging es in den letzten Postings!



  • picaschaf schrieb:

    Im Übrigen ist sie sogar besser als das was so oft rumgeistert - wer will schon die Parameter verändern?! Btw. ist das die Standarddefinition in Xcode.

    Du triffst schon wieder Annahmen darüber, was andere Leute wohl benötigen oder nicht. Lese die Forumsüberschrift und nötige nicht andere Leute mit deinem aufgeschnappten Halbwissen zu nichtstandardkonformem Code.


Anmelden zum Antworten