Effektiver Umgang mit großen Listen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Ausgehend von den von dir angedeuteten Größenordnungen habe ich mal eine Liste mit 30 Mio. Einträgen erzeugt.
Der Prozess des Änderns/Löschens von Elementen könnte dann etwa so aussehen:

Code: Alles auswählen

from random import random
from time import time

t0 = time()
data = [int(random()*500000) for k in xrange(3*10**7)]
print time()-t0
t0 = time()
for i,e in enumerate(data):
    if e > 490000: data[i] = 0 # mark for deletion
    if e < 10000: data[i] += 1 # modify entry
print time()-t0
t0 = time()
data = filter(None,data)
print time()-t0
Output:

Code: Alles auswählen

18.1248118877
7.88669085503
1.17805695534
Die teure Listenerzeugung ist nicht relevant, ob die anderen Zeiten für dich im Rahmen liegen, müsstest du selbst beurteilen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

cofi hat geschrieben:
AllesMeins hat geschrieben:Wenn ich aus "heiterem Himmel" sage "ändere Listenindex 1234567", dann muss dies ja trotzdem erst mal gesucht werden - egal wie es implementiert ist.
Das ist Bloedsinn. Die Python `list` ist ein Array und Indexzugriffe erfolgen in konstanter Zeit, die Liste muss nicht durchgegangen werden. Und das ist sehr wohl von der Implementierung abhaengig.
Das ist doch wesentlicher Aspekt: Ist ein Indexzugriff per Sprachdefinition immer O(1)? Oder kann es auch O(n) sein? Für einen Algorithmus ist das ja entscheidend - CPython ist ja nicht alles! Ich habe in der Doku nichts genaues dazu gefunden; dazu muss es aber doch etwas geben. Ich fände es schön, wenn einer dazu mal Referenzen posten könnte.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
AllesMeins
User
Beiträge: 63
Registriert: Donnerstag 20. November 2003, 13:45
Wohnort: Frankfurt/M.

Hyperion hat geschrieben:Das ist doch wesentlicher Aspekt: Ist ein Indexzugriff per Sprachdefinition immer O(1)? Oder kann es auch O(n) sein?
Ja, da wird es interessant :)
Wenn ich so drüber nachdenke - man könnte eine Liste in der Tat so implementieren, dass ein Zugriff über die Indexnummer in O(1) funktioniert. Soweit ich das sehe geht das aber nur, indem man im Speicher die Liste komplett zusammenhängend ablegt und dann direkt addressiert "Listenbeginn + Indexnummer" und so in die entsprechende Speicherzelle springt (bzw. indirekt adressiert um mit unterschiedlich großen Listeneinträgen fertig zu werden). Solch eine Implementierung dürfte aber schon dann problematisch werden, wenn nicht genug zusammenhängender Speicher vorhanden ist. Außerdem wird an der Stelle auch das löschen sehr aufwendig, denn ich müsste ja wenn ich in der Mitte irgendetwas rauslösche den kompletten Listenblock wieder zusammenschieben, damit das direkte anspringen klappt (also sprich bis zu n/2 Verschiebeoperationen pro Löschvorgang). Da mir das als nicht besonders praktikabel erscheint bleibe ich erst mal dabei: Auch ein Indexzugriff bedeutet normalerweise, dass der entsprechende Eintrag erst mal gesucht werden muss (auch wenn man das deutlich effektiver gestalten kann, als die Suche nach einem bestimmten Wert). Da wären, aus rein wissenschaftlichem Interesse, Implementierungsdetails wirklich mal interessant.
Aber ich denke das führt zu weit. Ich hatte halt gehofft das es bei Python irgend eine Möglichkeit gibt an interne Listenzeiger heranzukommen, denn das wäre wohl das effizienteste gewesen. Aber da es das scheinbar nicht gibt, probiere ich jetzt einfach die von euch vorgeschlagenen Methoden mal durch. Auf jeden Fall schon mal vielen Dank für die zahlreichen beiträge und Ideen.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Hyperion hat geschrieben:Das ist doch wesentlicher Aspekt: Ist ein Indexzugriff per Sprachdefinition immer O(1)? Oder kann es auch O(n) sein? Für einen Algorithmus ist das ja entscheidend - CPython ist ja nicht alles!
Guter Einwand. In der Sprachreferenz wird das leider nicht erwaehnt, von Jython weiss ich, dass sie `ArrayList` nutzen. Bei PyPy werd ich aus dem Code (https://bitbucket.org/pypy/pypy/src/403 ... tobject.py) leider nicht schlau, bei IronPython hab ich jetzt nicht geschaut. IMO macht das von der Dokumentation geforderte Interface aber nicht sonderlich viel Sinn als verkettete Liste.

@OP: Wir reden von CPython? Dann ist `list` keine verkettete Liste von der du scheinbar ausgehst und nicht abruecken willst, auch wenn dir jetzt schon mehrmals gesagt wurde, dass du falsch liegst, sondern ein Array. Und ja, die Probleme existieren.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

cofi hat geschrieben:IMO macht das von der Dokumentation geforderte Interface aber nicht sonderlich viel Sinn als verkettete Liste.
Da hast Du natürlich recht. Ich hätte es halt schön gefunden, etwas ähnliches wie in der Java Dokumentation zu finden:
public interface RandomAccess
Marker interface used by List implementations to indicate that they support fast (generally constant time) random access. The primary purpose of this interface is to allow generic algorithms to alter their behavior to provide good performance when applied to either random or sequential access lists.
Link

Denn dann kann ich Plattform unabhängig Algorithmen entwickeln und muss nicht auf Implementierungsdetails achten, die bei solchen Dingen ja große Auswirkungen haben können.

Irgend wo muss es dazu doch auch etwas in der Python-Doku geben!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
AllesMeins
User
Beiträge: 63
Registriert: Donnerstag 20. November 2003, 13:45
Wohnort: Frankfurt/M.

cofi hat geschrieben:
Hyperion hat geschrieben:@OP: Wir reden von CPython? Dann ist `list` keine verkettete Liste von der du scheinbar ausgehst und nicht abruecken willst, auch wenn dir jetzt schon mehrmals gesagt wurde, dass du falsch liegst, sondern ein Array. Und ja, die Probleme existieren.
Ja, das ändert ja nichts an der Tatsache dass beim iterieren durch die Liste irgendwo ein Zeiger sein muss, wo man gerade ist. Und wenn die Sprache das hergeben würde, dann könnte man das auch ausnutzen. Vollkommen egal ob die Liste als verkette Liste oder als Array implementiert ist. Aber egal, wenn es nicht geht, dann gehts halt nicht.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

AllesMeins hat geschrieben:
cofi hat geschrieben:
Hyperion hat geschrieben:@OP: Wir reden von CPython? Dann ist `list` keine verkettete Liste von der du scheinbar ausgehst und nicht abruecken willst, auch wenn dir jetzt schon mehrmals gesagt wurde, dass du falsch liegst, sondern ein Array. Und ja, die Probleme existieren.
Ich hab das nicht gesagt, cofi wars! ;-)
Ja, das ändert ja nichts an der Tatsache dass beim iterieren durch die Liste irgendwo ein Zeiger sein muss, wo man gerade ist. Und wenn die Sprache das hergeben würde, dann könnte man das auch ausnutzen. Vollkommen egal ob die Liste als verkette Liste oder als Array implementiert ist. Aber egal, wenn es nicht geht, dann gehts halt nicht.
Zeiger gibt es in Python nun mal nicht. Aber was willst Du denn da ausnutzen? Kapiere ich nicht. Du schriebst ja etwas davon, dass man bei einem Element evtl. erkennt, dass man spätere Elemente nicht löschen darf. Was nützt Dir denn da der "Zeiger" auf das aktuelle Element?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
AllesMeins
User
Beiträge: 63
Registriert: Donnerstag 20. November 2003, 13:45
Wohnort: Frankfurt/M.

Hyperion hat geschrieben:Zeiger gibt es in Python nun mal nicht. Aber was willst Du denn da ausnutzen? Kapiere ich nicht. Du schriebst ja etwas davon, dass man bei einem Element evtl. erkennt, dass man spätere Elemente nicht löschen darf. Was nützt Dir denn da der "Zeiger" auf das aktuelle Element?
Ich muss sowieso alle Elemente durchgehen und in jedem Schritt auch immer nur dieses eine derzeit gelesene Element bearbeiten. Und da wäre es halt einfach sehr effizient sich einfach die Speicherposition merken zu können und dann direkt wieder darauf zuzugreifen ohne das Python im Hintergrund mehrfach die Speicherposition suchen muss.
Das mit den späteren Elementen bezog sich nur darauf, dass ich nicht von vorneherein sagen kann "Alle Elemente mit Wert X sollen raus", sondern sich die Anforderungen mit meinen Aktionen ändern. Ich will aber nicht in der Liste "rumspringen", sondern würde mir nur (stark vereinfacht) merken: "Okay, ich habe Werte X, Y und Z" bereits gelöscht also darf ich Wert A nicht mehr löschen (falls ich an einem vorbei kommen sollte). Hätte ich X, Y und Z aber noch nicht gefunden könnte A gelöscht werden (oder soetwas).

Nachtrag:
Also wie gesagt. Unterm Strich ging es mir um eine möglichst effiziente Methode Listeneinträge einen nach dem anderen abarbeiten zu können. Wenn es da aber nichts direktes gibt, dann nehm ich einfach die existierenden methoden. Ist auch kein beinbruch, anders wäre es nur schöner gewesen.
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

AllesMeins hat geschrieben: Ich muss sowieso alle Elemente durchgehen und in jedem Schritt auch immer nur dieses eine derzeit gelesene Element bearbeiten. Und da wäre es halt einfach sehr effizient sich einfach die Speicherposition merken zu können und dann direkt wieder darauf zuzugreifen ohne das Python im Hintergrund mehrfach die Speicherposition suchen muss.
Die "Speicherposition" ist der Index der Liste. Mehr brauchst du nicht. Index-Zugriff ist O(1). Was willst du mehr?
Bottle: Micro Web Framework + Development Blog
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

AllesMeins hat geschrieben: Ich muss sowieso alle Elemente durchgehen und in jedem Schritt auch immer nur dieses eine derzeit gelesene Element bearbeiten. Und da wäre es halt einfach sehr effizient sich einfach die Speicherposition merken zu können und dann direkt wieder darauf zuzugreifen ohne das Python im Hintergrund mehrfach die Speicherposition suchen muss.
Dazu muss man aber - unabhängig von Python - doch immer eine Art Suche durchführen! Denn alleine das Wort "merken" impliziert ja, dass Du die Position (bzw. allgemeiner eine Zugriffsmöglichkeit) irgend wo ablegst, um später darauf zuzugreifen. Und dieser spätere Zugriff kostet nun einmal. Das kannst Du also nicht verhindern.

Die Fragen, um die sich alles dreht, sind also doch schlicht und ergreifend, ob Du bei der gewählten Datenstruktur konstante Kosten erreichst, oder nicht und ob das ggf. von der Implementierung des verwendeten Interpreters abhängig ist?

Nach Klärung dieser Fragen kann man sich dann ggf. immer noch Gedanken darüber machen, ob eine andere Datenstruktur bessere Bedingungen für Dein Problem bietet.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

cofi hat geschrieben:von Jython weiss ich, dass sie `ArrayList` nutzen.
Habe meinen Code oben gerade mit Jython 2.5 ausgeführt: :(

Code: Alles auswählen

Traceback (most recent call last):
  File "largelist.py", line 5, in <module>
    data = [int(random()*500000) for k in xrange(3*10**7)]
java.lang.OutOfMemoryError: Java heap space
lunar

@Hyperion: Die „Referenzimplementierung“ CPython hat konstante Komplexität, und insofern werden sich die anderen Implementierungen wohl daran orientieren. Eine verkettete Liste ist in imperativen Sprachen auch ein eher unnatürliches Konstrukt, und findet eher in funktionalen Sprachen Anwendung.

@AllesMeins: Was genau willst Du an einem „Zeiger“ denn ausnutzen?! Bei einem Feld sind Indexzugriff und Zugriff über einen Zeiger auf das aktuelle Element faktisch identisch. In C bedeutet "a[10]" nichts anderes als "*(a + 10)", also ein direkter Speicherzugriff. Genau deswegen geschieht der Index-Zugriff auf Felder ja in konstanter Zeit.

In Python werden beim Index-Zugriff natürlich noch Attributzugriff und diverse andere Dinge durchgeführt werden. Das aber sind inhärente Operationen des Python-Interpreters, die sich aus dem Objekt- und Ausführungsmodell von Python ergeben. Wenn Dir das zu „ineffizient“ ist, dann darfst Du nicht Python programmieren.

@numerix: Das ist eine künstliche Grenze, der der JVM zur Verfügung stehende Speicher lässt sich über Kommandozeilenoptionen erhöhen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

numerix hat geschrieben:
cofi hat geschrieben:von Jython weiss ich, dass sie `ArrayList` nutzen.
Habe meinen Code oben gerade mit Jython 2.5 ausgeführt: :(

Code: Alles auswählen

Traceback (most recent call last):
  File "largelist.py", line 5, in <module>
    data = [int(random()*500000) for k in xrange(3*10**7)]
java.lang.OutOfMemoryError: Java heap space
Das liegt afair an der JVM, die per Default meist nur mit einer relativ geringen Speichermenge gestartet wird. Die kann dann keinen Speiche mehr dynamisch dazu allozieren (Oder darf?). Daher muss man diese Speichergröße beim Start einer JVm Instanz einstellen.

Code: Alles auswählen

java -X
liefert Dir da hilfreiche Parameter.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Danke für die Hinweise zum Heap der JVM. Ein Aufruf der Art

Code: Alles auswählen

jython -DXms=4000000000 largelist.py
sollte nach meinem Verständnis bewirken, dass der Heap eine Ausgangsgröße von rund 4 GB erhält. Richtig?
Falls ja, war auch das noch nicht genug ...

Interessant auch pypy (Version 1.3.0, entspricht Python 2.5.2). Laufzeiten für den Code oben: :shock:

Code: Alles auswählen

402.39693594
110.075237036
5.70352101326
Die Zeiten von CPython 2.6 waren (s.o.):

Code: Alles auswählen

18.1248118877
7.88669085503
1.17805695534
Außerdem noch CPython 3.1:

Code: Alles auswählen

16.6592679024
8.52411317825
1.23679995537
Und ganz frisch CPython 3.2:

Code: Alles auswählen

16.38372302055359
8.843859910964966
1.2578709125518799
Benutzeravatar
sparrow
User
Beiträge: 4183
Registriert: Freitag 17. April 2009, 10:28

numerix hat geschrieben:Danke für die Hinweise zum Heap der JVM. Ein Aufruf der Art

Code: Alles auswählen

jython -DXms=4000000000 largelist.py
sollte nach meinem Verständnis bewirken, dass der Heap eine Ausgangsgröße von rund 4 GB erhält. Richtig?
Falls ja, war auch das noch nicht genug ...
Nee, das ist doch keine System-Property die du das setzt.

Code: Alles auswählen

java -Xms512m -Xmx4096m
zumindest an der Windows-Kiste mit Java 1.6 an der ich gerade sitze.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Da jython selbst die Parameter -X... nicht kennt, dachte ich, über -DX... könnte ich das erreichen. :oops:
Auf die Idee, jython selbst explizit über einen Aufruf von java zu starten, bin ich zunächst nicht gekommen. So funktioniert es:

Code: Alles auswählen

java -Xms512m -Xmx4096m -jar jython.jar largelist.py
Laufzeiten sind dann:

Code: Alles auswählen

39.0980000496
34.8320000172
4.34000015259
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

AllesMeins hat geschrieben:Außerdem wird an der Stelle auch das löschen sehr aufwendig, denn ich müsste ja wenn ich in der Mitte irgendetwas rauslösche den kompletten Listenblock wieder zusammenschieben, damit das direkte anspringen klappt (also sprich bis zu n/2 Verschiebeoperationen pro Löschvorgang).
Das schrieb ich schon…
Da mir das als nicht besonders praktikabel erscheint bleibe ich erst mal dabei: Auch ein Indexzugriff bedeutet normalerweise, dass der entsprechende Eintrag erst mal gesucht werden muss

[...]

Ich muss sowieso alle Elemente durchgehen und in jedem Schritt auch immer nur dieses eine derzeit gelesene Element bearbeiten. Und da wäre es halt einfach sehr effizient sich einfach die Speicherposition merken zu können und dann direkt wieder darauf zuzugreifen ohne das Python im Hintergrund mehrfach die Speicherposition suchen muss.
Wie oft muss ich eigentlich noch schreiben, dass das ein C-Array und der Integer der Index des Eintrags? Da muss nichts gesucht werden, der Index *ist* die Speicheradresse minus eine Konstante.
Defnull hat geschrieben:List comprehension ist bei sehr großen Listen eine eher schlechte Idee, schließlich wird dadurch eine Kopie erzeugt.
Habe ich doch geschrieben…und der Generator bringt dort auch nicht sehr viel, wenn AllesMeins hinterher wieder eine Liste braucht.
Benutzeravatar
snafu
User
Beiträge: 6736
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Python speichert also folglich die Speicheradresse des jeweils ersten Elements von einer Liste ab. Diese Information ist dann meinetwegen erreichbar über den vom Benutzer festgelegten Namen `mylist`. Wenn `mylist` einen Verweis auf die Speicheradresse 1240 enthält, dann bedeutet `mylist[3]` nichts anderes als den Inhalt von Speicheradresse 1243 zu holen, und zwar ohne, dass man dafür irgendwas über die Vorgänger-Elemente wissen muss. Ist doch richtig, oder?

Aber wenn dem so ist, dann verstehe ich die (nicht zitierten) Einwände von AllesMeins durchaus: Sobald der Speicher für die Liste nicht mehr zusammenhängend ist, klappt dieser "Trick" nicht mehr. Dies ist ja bei sehr großen Listen nicht unwahrscheinlich. Wie wird denn dann verfahren, um möglichst effizient zu bleiben? Ich könnte mir ja vorstellen, dass die Listen in Teil-Listen umgewandelt werden, so dass zusätzlich "nur" die Informationen aus dem letzten Element der Teil-Liste geholt werden müssen, um zu wissen, wo es weitergeht. Aber das ist erstmal geraten.
lunar hat geschrieben:Bei einem Feld sind Indexzugriff und Zugriff über einen Zeiger auf das aktuelle Element faktisch identisch. In C bedeutet "a[10]" nichts anderes als "*(a + 10)", also ein direkter Speicherzugriff. Genau deswegen geschieht der Index-Zugriff auf Felder ja in konstanter Zeit. In Python werden beim Index-Zugriff natürlich noch Attributzugriff und diverse andere Dinge durchgeführt werden. Das aber sind inhärente Operationen des Python-Interpreters, die sich aus dem Objekt- und Ausführungsmodell von Python ergeben.
Das heißt also, dass Python die konkrete Ablage der Werte und den späteren Zugriff komplett dem C-Array überlässt? Keine schlechte Idee, da das Rad ja hier kaum neu erfunden werden muss. Python greift also nur noch vor dem eigentlichen Zugriff mit seiner eigenen "Interpretation" ein, d.h. unter Beachtung einer möglichen alternativen `__index__()`-Implementierung seitens des Python-Programmierers, wenn ich das richtig sehe.
Zuletzt geändert von snafu am Donnerstag 24. Februar 2011, 09:21, insgesamt 1-mal geändert.
Benutzeravatar
snafu
User
Beiträge: 6736
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

AllesMeins hat geschrieben:
cofi hat geschrieben:
Hyperion hat geschrieben:@OP: Wir reden von CPython? Dann ist `list` keine verkettete Liste von der du scheinbar ausgehst und nicht abruecken willst, auch wenn dir jetzt schon mehrmals gesagt wurde, dass du falsch liegst, sondern ein Array. Und ja, die Probleme existieren.
Ja, das ändert ja nichts an der Tatsache dass beim iterieren durch die Liste irgendwo ein Zeiger sein muss, wo man gerade ist. Und wenn die Sprache das hergeben würde, dann könnte man das auch ausnutzen. Vollkommen egal ob die Liste als verkette Liste oder als Array implementiert ist. Aber egal, wenn es nicht geht, dann gehts halt nicht.
Finde dich damit ab: Der "Zeiger" ist der Index. Und den bekommst du mit `enumerate()`. Was hälst du eigentlich genau von dem genannten Vorschlag, die zu löschenden Elemente zu markieren und dann in bestimmten Abständen in einem Rutsch zu löschen?
AllesMeins hat geschrieben:Das mit den späteren Elementen bezog sich nur darauf, dass ich nicht von vorneherein sagen kann "Alle Elemente mit Wert X sollen raus", sondern sich die Anforderungen mit meinen Aktionen ändern. Ich will aber nicht in der Liste "rumspringen", sondern würde mir nur (stark vereinfacht) merken: "Okay, ich habe Werte X, Y und Z" bereits gelöscht also darf ich Wert A nicht mehr löschen (falls ich an einem vorbei kommen sollte). Hätte ich X, Y und Z aber noch nicht gefunden könnte A gelöscht werden (oder soetwas).
Speichere die zu löschenden Indizes halt irgendwo ab. Du wirst, so wie sich das anhört, einfach nicht um die Verwendung des Tupels `(index, value)`, wie er von `enumerate()` zurückgeliefert wird, herumkommen. Falls das für dich nicht akzeptabel ist, dann dürfte Python in dieser Hinsicht nichts für dich sein.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Ich muss an dieser Stelle doch mal die Bitte loswerden, sich mal kurz mit C-Arrays auseinanderzusetzen. Dann erübrigen sich die Mutmaßungen ziemlich schnell.
snafu hat geschrieben:Wenn `mylist` einen Verweis auf die Speicheradresse 1240 enthält, dann bedeutet `mylist[3]` nichts anderes als den Inhalt von Speicheradresse 1243 zu holen, und zwar ohne, dass man dafür irgendwas über die Vorgänger-Elemente wissen muss. Ist doch richtig, oder?
Im Prinzip ja, wobei die Größe der Speicherzelle von Typen des C-Arrays abhängt. Auf Bytes runtergebrochen, ist die die Speicherstelle von mylist[3]: (mylist + 3 * Größe eines Elementes in Bytes)
Für typisierte Arrays übernimmt aber der Compiler die Einbeziehung der Elementgröße in die Pointerarithmetik und es verkürzt sich auf (mylist + 3).
snafu hat geschrieben:Sobald der Speicher für die Liste nicht mehr zusammenhängend ist...
Ein Array in C respräsentiert einen zusammenhängenden Speicherbereich.
Antworten