Warum faengt das Array bei 0 an?



  • seldon schrieb:

    Es ist für Ringstrukturen ausgesprochen praktisch:

    array[raw_index % array_size]
    

    Das (bzw. ähnliches) dürfte beispielsweise in Hashtables oft zu sehen sein.

    Außerdem wäre es mit Blick auf Zeigerarithmetik ziemlich verwirrend, das erste Element mit Index 1 anzusprechen.

    Naja, wohl eher ein Restklassenring, oder ? 😃

    $\mathbb{Z}_n$

    Das das Array bei null anfängt ist doch ganz klar, wenn man sich die übersetzung anguckt:

    type & array.operator[] (int i)
    {
    // prüfe index
    ....
    // gebe referenz zurück
    return *(array_ptr+i); //der Compiler übersetzt hier zu return start_addr+i*sizeof(type)
    };
    

    Der Index i=0 ist also der faktorielle Abstand des "ersten" Array Inhaltes zu der Startposition im Speicher....

    Und das
    11

    als "normaler" startindex genommen wird ist keine konvention, sondern weil es das multiplikative neutrale element (des Körpers) der Reelen Zahlen ist,...

    greetz



  • volkard schrieb:

    CSpille schrieb:

    volkard schrieb:

    Könnte vielleicht ein paar Locks vermeiden und bei 12 Kernen überlegen viele Leute schon viel rum, Locks zu vermeiden als Standardrundumallheilmittel.

    Eventuell stehe ich gerade auf dem Schlauch, aber wo brauch man Locks bei new und delete?

    Gehts auch ohne? Ich will den Speicherblock doch wieder in die verkettete Liste hängen oder Baum, Heap, oder mit Nachbarn verschmelzen oder nur den freispeicherzähler inkrementieren, ohne daß ein anderer Thread auch an meinen Nachbarn rumfummelt oder gleichzeitig Zähler ändert.

    mkay...
    Damit verschiebst du den Lock ja eigentlich nur...

    Also bei gleichzeitigem Arbeiten auf einer Datenstruktur, auf der Objekte gelöscht werden können...

    thx,
    volkard



  • zeusosc schrieb:

    Das das Array bei null anfängt ist doch ganz klar, wenn man sich die übersetzung anguckt:

    type & array.operator[] (int i)
    {
    // prüfe index
    ....
    // gebe referenz zurück
    return *(array_ptr+i); //der Compiler übersetzt hier zu return start_addr+i*sizeof(type)
    };
    

    Du verwechselst hier Ursache und Wirkung. Die Frage war, warum die "Übersetzung" genau so und nicht anders aussieht. Sie könnte auch so aussehen, womit Arrays 1-basierend wären:

    array[i] == *(array+i-1)
    

    (Und btw: der Index wird nicht geprüft)

    zeusosc schrieb:

    Und das
    11

    als "normaler" startindex genommen wird ist keine konvention, sondern weil es das multiplikative neutrale element (des Körpers) der Reelen Zahlen ist,...

    Verstehe ich jetzt ehrlich gesagt nicht. Du meinst der Mensch fängt gerne bei 1 mit zählen an, weil a*1=a?
    Außerdem ist 0 das neutrale Element der Addition und Addition passt viel besser zum Zählen als Multiplikation.



  • Das war bei einigen früheren Compilern (erste FORTRAN-Compiler) anders, da fingen die Arrays tatsächlich bei 1 an. Das schuf aber manchmal Probleme für die Programmierung. Deshalb der heute allgmein übliche Standard mit dem Anfangsindex = Null. Ist einfach besser. Bei C-Strings macht das noch mehr Sinn wegen des abschliessenden Nullzeichens.



  • berniebutt schrieb:

    Bei C-Strings macht das noch mehr Sinn wegen des abschliessenden Nullzeichens.

    Nö.



  • 'array[i] == *(array+i-1)' Hat das Problem das es nicht korrekt ist, wenn man annimmt das 'array[i] == *(array+i)' korrekt ist, oder?

    Damit es korrekt ist muesste es doch 'array[i+1] == *(array+i-1)' heissen, wobei sich dann die frage Stellt warum man die 1 nicht wegkuerzt.

    Wenn man jetzt die Basis 0 um eins nach rechts verschiebt um die 1 als Basis zu haben, heisst es wieder 'array[i] == *(array+i)'. Oder man hat eine gemischte Basis, dann koennte auch 'array[i] == *(array+i-1)' korrekt sein.

    Jedoch weiss ich nicht wie man mit gemischter Basis rechnet, vielleicht kann ja hier ein Mathematiker mal Licht in den Sinn und Unsinn reinbringen.

    Oder bringe ich hier was durcheinander?

    Gruss
    Baracke



  • Baracke_out schrieb:

    'array[i] == *(array+i-1)' Hat das Problem das es nicht korrekt ist, wenn man annimmt das 'array[i] == *(array+i)' korrekt ist, oder?

    Natürlich kann nicht x == y und x == y-1 gleichzeitig wahr sein.

    Baracke_out schrieb:

    Oder bringe ich hier was durcheinander?

    Ja. Warum soll array[i+1] das Gleiche sein wie *(array+i-1) ? Wenn schon +1 .

    Aber ich sehe nicht, was es hier überhaupt zu diskutieren gibt. Dass array[i] dem Wert *(array+i) entspricht, ist das absolut Naheliegendste. Ein +1 benötigte wieder eine Addition mehr und würde für Verwirrung sorgen. Es wäre nicht einfacher, da man zwei verschiedene Konzepte lernen müsste (direkte Adressierung ist nicht mehr analog zur Verwendung eines Index). Was hätte man für einen Gewinn?



  • Nexus schrieb:

    Was hätte man für einen Gewinn?

    Der "Gewinn" ist vor allem für Anfänger. Wenn man 3 Äpfel vor sich liegen hat, sagt man intuitiv "1. Apfel, 2. Apfel, 3. Apfel" und nicht "0. Apfel, 1. Apfel, 2. Apfel". Gerade für Anfänger ist die 0-Basierung deshalb zuerst unlogisch (die interne Adressierung über Pointeraddition ist ja zu dem Zeitpunkt vollkommen irrelevant).
    Allerdings stimme ich dir zu, dass man sich daran schnell gewöhnt und in vielen Fällen die 0-Basierung schlussendlich logischer und konsistenter ist.



  • Ja, aber C++ hat noch nie den Schwerpunkt auf Anfängerfreundlichkeit gelegt. Auf eine gewisse Weise ist das auch gut so. Zu starke Einfachheit kommt oft fortgeschrittenen Programmierern ungelegen und behindert diese in ihrer Flexibilität.

    Zumal es hier ja wirklich kein Problem ist, den ersten Index einfach bei 0 statt 1 zu setzen. Als C++-Anfänger hat man ohnehin andere Probleme...



  • Ein kleiner Vorteil wäre noch, dass man den Baumindex beim Heapsort mit *2 leichter berechnen könnte, aber zuerst 1 addieren, mit 2 malnehmen und dann wieder 1 subtrahieren funktioniert auch gut.



  • wxSkip schrieb:

    zuerst 1 addieren, mit 2 malnehmen und dann wieder 1 subtrahieren funktioniert auch gut.

    oder
    n*2+1 ?



  • Ich nichts verstehen. 😕 daddeldu - ich habe fertig! :p



  • Shade Of Mine schrieb:

    wxSkip schrieb:

    zuerst 1 addieren, mit 2 malnehmen und dann wieder 1 subtrahieren funktioniert auch gut.

    oder
    n*2+1 ?

    Ja, stimmt. Wobei ich mich vertan habe, die Unterknoten sind n*2+2 und n*2+3, wenn das Array bei 1 anfangen würde, wären sie n*2 und n+2+1



  • wxSkip schrieb:

    Shade Of Mine schrieb:

    wxSkip schrieb:

    zuerst 1 addieren, mit 2 malnehmen und dann wieder 1 subtrahieren funktioniert auch gut.

    oder
    n*2+1 ?

    Ja, stimmt. Wobei ich mich vertan habe, die Unterknoten sind n*2+2 und n*2+3, wenn das Array bei 1 anfangen würde, wären sie n*2 und n+2+1

    Bei uns sind die bei 2*n und 2*n+1 (0-basiert) bzw 2*n+1 und 2*n+2 (1-basiert).



  • Hmmm...
    0 ist der Stammknoten, die Unterknoten sind 1 und 2
    also bei 0-basiert n*2+1 und n*2+2
    bei 1-basiert:
    1 ist der Stammknoten, die Unterknoten sind 2 und 3
    also sind die Unterknoten n*2 und n*2+1

    So, jetzt sollte es aber stimmen.



  • Naja, bei 0-basierten Heaps kann man sich je nach Implementierung aber dennoch die Freiheit nehmen, n*2 und n*2+1 zu postulieren, fürchte ich.
    Das hat lustige Effekte. Zum Beispiel ist das Papafinden ab 10 so: 10 5 2 1 0 0 0 0 0..., also 0 ist sein eigener Papa, was zu einem recht natürlichen Schleifenabbruch führt beim Hochblubbern führt. Ich könnte mir denken, daß man bei Heapsort auch gewisse Freiheiten hat.


Anmelden zum Antworten