Unterschied Array und Zeiger



  • Was ist eigentlich der genaue Unterschied zwischen einem Array und einem Zeiger?

    Folgendes Beispiel habe ich gefunden:

    #include <stdio.h>
    #include <stdint.h>
    
    int main(int argc, char **argv)
    {
        char* s1 = "Hallo Welt";
        char s2[] = "Hallo Welt";
    
        s1[0] = 'A';  // Hier kracht es
        s2[0] = 'A';
    	printf("hello world\n");
    	return 0;
    }
    

    Im Falle von s1 wird einem Zeiger ein String Literal zugewiesen. Nun wird das String Literal vom Compiler wie ein static const behandelt und enstsprechend Im Programm-Modul abgespeichert. Deswegen kracht die Zuweisung s1[0] = 'A'.

    Im Falle von s2 wird dem Array ein String zugewiesen bzw. die Inhalte des String Literals werden in ein Array kopiert. Deswegen funktioniert die Zuweisung.

    Des weiteren ist mir bewusst, dass man von einem Array die Größe bestimmen kann, während bei einem Zeiger auf ein Array, die Größe nur durch einen weiteren Parameter oder einem Ende-Feld (siehe Nullterminierte Strings) gegeben ist.

    Kennt jemand noch weitere Unterschiede?

    PS:
    Das Ganze zieht sich bis zu den C++ Templates durch.

    std::unique_ptr<Foo> p1(new Foo);
    std::unique_ptr<Foo[]> p2(new Foo[8]);
    


  • Der Arrayname steht für die Anfangsadresse des Array / die Adresse vom ersten Element.

    Diese Adresse kannst du mit * bzw. [] dereferenzieren.

    Das ist aber auch schon die einzige Gemeinsamkeit zwischen Array und Pointer.

    Ansonste gilt: Ein Array ist kein Pointer, ein Pointer ist kein Array.



  • Bitte ein Bit schrieb:

    Nun wird das String Literal vom Compiler wie ein static const behandelt und enstsprechend Im Programm-Modul abgespeichert.

    Quatsch.
    Vom Compiler wird nichts als "const behandelt". Was ist ein Programmmodul?
    s1 wird als Zeiger auf char definiert und initialisiert mit der Adresse eines Objektes mit static storage duration, das wiederum vom Compiler definiert wurde mind. groß genug um alle Elemente des Stringliterals inkl. '\0' aufzunehmen, wobei der ändernde Zugriff auf eines dieser Elemente (chars) UB darstellt.
    Erfahrene C-Programmierer verwenden deswegen bei der Definition dieses Zeigers - wenn sinnvoll und der Zeiger nicht noch anderswo gebraucht wird - zusätzlich explizit den Qualifizierer const.

    Bitte ein Bit schrieb:

    während bei einem Zeiger auf ein Array,

    s2 ist kein Zeiger auf ein Array.

    Bitte ein Bit schrieb:

    Im Falle von s2 wird dem Array ein String zugewiesen bzw. die Inhalte des String Literals werden in ein Array kopiert. Deswegen funktioniert die Zuweisung.

    Quatsch.
    s2 wird als Array von char definiert und mit Elementen des Stringliterals initialisiert. Das ist ein wesentlicher Unterschied.
    Arrays kann man kein Stringliteral zuweisen sondern nur damit initialisieren.

    Bitte ein Bit schrieb:

    Das Ganze zieht sich bis zu den C++ Templates durch.

    Deswegen sollen C++ler auch string benutzen und nicht irgendwelche Annahmen über C-Strings machen und versuchen, diese nachzubilden.

    Bitte ein Bit schrieb:

    Was ist eigentlich der genaue Unterschied zwischen einem Array und einem Zeiger?

    Es gibt genau 6 durch den Standard definierte Situationen, in denen ein Arrayname nicht in einen Zeiger zerfällt bzw. immer.
    Wenn du 25 Jahre C programmiert hast, dann wirst du diese kennen.



  • @Wutz

    Vom Compiler wird nichts als "const behandelt". Was ist ein Programmmodul?

    Schau dir die Exe von meinem Beispiel mit einem Hex-Editor an und du wirst "Hallo Welt" finden.

    Unter einem Programm-Modul verstehe ich eine ausführbare Datei. Diese kann die Dateiendung exe, dll, oder was auch immer haben.

    Und natürlich achte ich auf const correctness. Aber du wirst lachen. Ich kenne sehr viele C Programmierer für denen const ein nutzloses Schlüsselwort ist.

    s1 wird als Zeiger auf char definiert und initialisiert mit der Adresse eines Objektes mit static storage duration, das wiederum vom Compiler definiert wurde mind. groß genug um alle Elemente des Stringliterals inkl. '\0' aufzunehmen, wobei der ändernde Zugriff auf eines dieser Elemente (chars) UB darstellt.

    Verzeih mir bitte dass ich mich mit den Begrifflichkeiten nicht so auskenne. Aber ich behandele Konstanten und String Literale so, als wären sie static const dekaliert worden.

    Und ich glaube ich weis auch was du meinst. Bei einem kleinen Embedded-Prozessor wurden const Variablen im Flash gespeichert und beim Programm-Start ins Ram geladen. Wurden Variablen dagegen als static const deklariert, so wurde der Zugriff direkt auf den Flash Speicher umgebogen. Und der war schreibgeschützt.

    Bei einem anderen Betriebssystem könnte dies anderes implementiert sein.

    s2 ist kein Zeiger auf ein Array.

    Ich habe auch überhaupt nicht s2 gemeint, sondern folgendes:

    #include <stdio.h>
    #include <stdint.h>
    
    int Sum(const int* L, int Size)
    {
      int sum = 0;
    
      for (int i = 0; i < Size; i++)
        sum += L[i];
      return sum;
    }
    
    int main(int argc, char **argv)
    {
        int a[] = {1, 2, 3, 4};
    
        printf("%i", Sum(a, 4));
    	return 0;
    }
    

    L ist ein Zeiger auf ein Array.

    Deswegen sollen C++ler auch string benutzen und nicht irgendwelche Annahmen über C-Strings machen und versuchen, diese nachzubilden.

    Es gibt genau 6 durch den Standard definierte Situationen, in denen ein Arrayname nicht in einen Zeiger zerfällt bzw. immer.
    Wenn du 25 Jahre C programmiert hast, dann wirst du diese kennen.

    Habe ich schon erwähnt dass ich einige C Programmierer kennen, welche nicht const kennen? Ja auch solche welche void CalcSum(void) Programme schreiben?

    Ich will hier auch keinen Flamewar starten, sondern ich stöbere gerade das Buch Effective Modern C++ durch, und da tauchen so viele Detailfragen im Bezug auf Templates Type Deduction auf. Und die eine ist halt der Unterschied zwischen Array und Zeiger.

    s2 wird als Array von char definiert und mit Elementen des Stringliterals initialisiert. Das ist ein wesentlicher Unterschied.
    Arrays kann man kein Stringliteral zuweisen sondern nur damit initialisieren.

    So jetzt bitte nicht ärgern. Hier kommt eine Detailfrage.

    Bedeutet dass das man unter C Variablen mittels = initialisiert?

    Dann dürfte der Code unter C++ nicht funktionen, da ich das Array hier nicht initialisiere, sondern einem String Literal mittels dem = Operator zuweise. 🤡


  • Mod

    Bitte ein Bit schrieb:

    @Wutz

    Vom Compiler wird nichts als "const behandelt". Was ist ein Programmmodul?

    Schau dir die Exe von meinem Beispiel mit einem Hex-Editor an und du wirst "Hallo Welt" finden.

    Das ist aber vollkommen unabhängig davon, ob const oder nicht const. Const ist eine Absicherung für den Programmierer, keine Anweisung an den Compiler.

    s2 wird als Array von char definiert und mit Elementen des Stringliterals initialisiert. Das ist ein wesentlicher Unterschied.
    Arrays kann man kein Stringliteral zuweisen sondern nur damit initialisieren.

    So jetzt bitte nicht ärgern. Hier kommt eine Detailfrage.

    Bedeutet dass das man unter C Variablen mittels = initialisiert?

    Dann dürfte der Code unter C++ nicht funktionen, da ich das Array hier nicht initialisiere, sondern einem String Literal mittels dem = Operator zuweise. 🤡

    Variablen werden in C mittels = initialisiert. Das geht in C++ genauso. Da wird garantiert (im Sinne von :Vom Standard garantiert!) nirgendwo erst ein unitialisiertes Objekt erstellt, dem dann etwas zugewiesen wird. Stattdessen ist das Ding auf der rechten Seite des = der Initialwert der Variablen.



  • Bitte ein Bit schrieb:

    L ist ein Zeiger auf ein Array.

    Nein, du hast keine Ahnung wovon du redest.
    L ist ein Zeiger auf int.
    Du hast weder Zeiger noch Array verstanden und verstehst dann natürlich erst recht nicht "Zeiger auf Array".

    Warum stellt du überhaupt die Titelfrage obwohl du doch selbst genau weißt, was ein Zeiger und ein Array ist?
    Deine "erfahrenen" C Programmierer sind nur Stümper wenn sie das behaupten was du hier vorträgst.

    static ist kontextabhängig, pauschale Behauptungen darüber sind also naiv und falsch.



  • @Wutz
    Sag mal was soll das eigentlich? Ich will die Feinheiten von C kennen lernen und bockst hier rum. Wenn du miese Laune hast, dann lass die bitte an anderen aus. 😡



  • Bitte ein Bit schrieb:

    @Wutz
    Sag mal was soll das eigentlich? Ich will die Feinheiten von C kennen lernen und bockst hier rum. Wenn du miese Laune hast, dann lass die bitte an anderen aus. 😡

    Halte einfach die Klappe von Dingen, von denen du keine Ahnung hast.
    Niemand hat hier was dagegen, wenn du eine Frage stellst.
    Wenn du aber selbst sagst, dass du schon alles weißt und alle Feinheiten kennst, dann trolle dich und halte den Platz frei für Leute, die nicht schon alles wissen und hier gegebene Antworten auch akzeptieren.
    Und ich lasse mir von niemandem hier erklären, was Zeiger und Arrays sind.



  • Oh leck, was kotzen mich zickige Leute an, welche absichtlich Dinge falsch verstehen. Wo habe ich dir denn erklärt was Zeiger sind und was Arrays? 😡

    PS: Die "Stümper" hatten 2015 einen Umsatz 2,29 Milliarden US Dollar.

    @Andere:
    Danke für die Antworten



  • Bitty, manche reagieren wenns um Standard-C/C++ ( <- :D, *schenkelklopf* ) geht auf ungenaue Formulierungen regelrecht allergisch ...

    ... und, tschuldige, wennst schon const int L* hinschreibst und dann erzählst L wär ein Pointer to array of sonstwas dann musst Du Dir schon die Frage gefallen lassen, ob Du uns verarschen willst oder eventuell nicht lesen kannst. Rückwärts lesen hilft (wenn du es auch vorwärts richtig hinschreibst): int const * L --> L is a pointer to const int.

    Wutzy schrieb:

    Es gibt genau 6 durch den Standard definierte Situationen, in denen ein Arrayname nicht in einen Zeiger zerfällt bzw. immer.

    Erzähl mal?



  • Das werde ich dir natürlich nicht erzählen.
    Genauso wenig wie ich die mir bisher bekannten 4 Situationen ausbreite, in denen ein Zeigercast notwendig ist und nichts kaputt macht.



  • "Ich weiß was!"
    "Aha. Was denn?"
    "Sag ich dir doch nicht!"

    Alles klar.



  • Swordfish schrieb:

    ... und, tschuldige, wennst schon const int L* hinschreibst und dann erzählst L wär ein Pointer to array of sonstwas dann musst Du Dir schon die Frage gefallen lassen, ob Du uns verarschen willst oder eventuell nicht lesen kannst.

    Ich sehe das wesentlich lockerer.

    In diesem Beispiel ist L im einzigen Aufruf der Funktion Sum ein Pointer auf ein Array. Nämlich auf das Array a aus main . Übrigens ist L hier natürlich auch ein Pointer auf das erste Element von a .

    Das ist aus der Laufzeit-Sicht, also aus der Sicht auf das, was wirklich im Zeiger drin steht. Das ist natürlich nicht dasselbe wie der Blick, der nur die Signatur der Funktion Sum isoliert betrachtet. Der Typ von L sagt mir nicht, worauf L zur Laufzeit wirklich zeigen wird.

    Der Typ kann allerdings einen Hinweis geben. Hier ist der Typ "Zeiger auf int" (einem void* könnte man z.B. gar nichts ansehen, aber auch eine void* -Variable könnte auf ein Array zeigen). Daher finde ich es nicht falsch zu sagen, dass L hier auf ein Array zeigt, obwohl der Typ von L "Zeiger auf int" ist.

    Wenn man als Typ auch Zeiger auf Array haben wollte, dann würde die Signatur z.B. so aussehen:

    int Sum(int (*L)[4])
    

    Der Parameter "Size" wäre dann überflüssig.



  • Durch Wiederholung von Unsinn steigt nicht der Wahrheitsgehalt.
    Zwei Blinde ergeben noch keinen Sehenden.



  • Schalt mal einen Gang runter du Blindfisch! Wo hab ich unsinn verbreitet?



  • Bitte ein Bit schrieb:

    Was ist eigentlich der genaue Unterschied zwischen einem Array und einem Zeiger?

    ein array ist eine ansammlung aufeinenderfolgender daten.
    ein zeiger ist eine adresse.
    🙂


Log in to reply