Arrays und Zeiger sind in C nicht dasselbe, obwohl sie verwandt sind und auf ähnliche Weise verwendet werden können. Bisher sind wir uns alle einig.
Ich verstehe jedoch nicht, warum Arrays in C enthalten waren, wenn Zeiger ihre Arbeit perfekt hätten erledigen können.
Ich sage nicht, die Array-Notation zu entfernen (z. B. a [5] oder int a [4] = {0,1,2,3};), was sehr nützlich und praktisch ist. Aber Sie könnten dieselbe Notation als kosmetische Maßnahme auch auf Zeigern verwenden (wie dies der Fall ist). Die Array-Notation ist also kein Grund, Arrays zu haben, sondern nur die Notation!
Der einzige Unterschied, den ich sehe, ist, dass Arrays konstante Zeiger sind und die Größe des Speichers, auf den sie zeigen, nicht geändert werden kann. Dies kann aber auch mit Zeigern erreicht werden, indem sie genau konstant gemacht werden (der Speicher hätte keine feste Größe, aber ich bin mir nicht sicher, ob dies ein Problem ist).
Warum also nicht nur Zeiger haben und den Programmierer entscheiden lassen, wie sich der Zeiger verhalten soll (dh konstant, nicht konstant, feste Größe, variable Größe usw.)?
x = a + b * 2;
wenn Sie dasselbe mit einer Folge einfacher Ausdrücke wie erreichen könntenx = b; x*=2; x+=a;
?Antworten:
Arrays sind zusammenhängende Speicher, die auf dem Stapel erstellt werden. Ohne diesen syntaktischen Zucker können Sie keinen zusammenhängenden Stapelspeicher garantieren, und selbst wenn Sie könnten, müssten Sie einen separaten Zeiger zuweisen, um die Zeigerarithmetik ausführen zu können (es sei denn, Sie wollten dies tun
*(&foo + x)
, was ich nicht bin sicher, aber es könnte die L-Wert-Semantik verletzen, ist aber zumindest ziemlich umständlich und würde nach einer Art syntaktischem Zucker schreien). In Bezug auf das Design handelt es sich auch um eine Form der Kapselung, da Sie mit einem einzigen Bezeichner auf die Sammlung verweisen können (für den sonst ein separater Zeiger erforderlich wäre). Und selbst wenn Sie sie zusammenhängend zuweisen und einen separaten Zeiger zuweisen könnten, um sie zu referenzieren, hätten Sie entwederint fooForSomething, fooForSomethingElse
... was einiges an Kreativität erzwingt, wenn Ihre Sammlung wächst, sodass Sie vielleicht überlegen, mit zu vereinfachenint foo1, foo2
..., das wie ein Array aussieht, aber schwieriger zu warten ist.quelle
static
s) landet je nach Umgebung normalerweise woanders.Die Array-Notation ist praktisch, leichter zu lesen und weniger fehleranfällig. Es bietet einen Formalismus über Zeiger. Es mag syntaktischer Zucker sein, aber wir alle brauchen ab und zu ein bisschen Süße, nicht wahr?
Wie bei allen Abstraktionen geben Sie ein wenig Flexibilität auf, um die Abstraktion zu vereinfachen.
quelle
Ich bin überrascht, dass noch niemand etwas über mehrdimensionale Arrays kommentiert hat.
Wenn Sie eine Matrix aus "verschachtelten Zeigern" haben (sagen wir
int **p
), ist das, was Sie in jeder "Zeile" (äußere Dimension) haben, ein Zeiger, der auf das erste Element in dieser Zeile zeigt. Für den Zugriff auf einen Wert sind also zwei Speicherzugriffe erforderlich. Außerdem ist der erforderliche Speicher erforderlichsizeof(*int)*n + n*m*sizeof(int)
.Im zweidimensionalen Array-Szenario
int p[n][m]
erfordert der Zugriff auf ein Element nur einen Speicherzugriff, da die Adresse der Zeile berechnet und nicht nachgeschlagen wird. und der benötigte Speicher ist geraden*m*sizeof(int)
.Ein anderer Ort, an dem ein Array nicht durch einen Zeiger ersetzt werden kann, befindet sich innerhalb von Strukturen.
ist definitiv nicht dasselbe wie
Die Größe des Arrays ist dort wichtig, und Zeiger haben diese Informationen nicht.
Also ja, eindimensionale Arrays und einzelne Zeiger sind meistens austauschbar, aber ihre Ähnlichkeiten enden dort.
quelle
i,j
anhand berechneni*cols+j
, aber ich denke, dass es ein Grund genug ist, die Existenz von Array-Typen zu rechtfertigen, wenn Sie dies nicht alleine tun müssen.Warum sollte ich keine Arrays für Werttypen verwenden können?
int a[4] = {0,1,2,3};
quelle
Wie würden Sie mit Plattformen wie dem 8031 ohne externen Speicher umgehen, die dies nicht unterstützen
malloc
oderalloca
? Vielleicht vergessen Sie, dass C nicht nur für großes Eisen, sondern auch für Aufzugssteuerungen und Toaster geeignet ist.quelle
In C ist die Array-Notation innerhalb von Ausdrücken immer einfach eine Zeigerarithmetik. Alle Verwendungen einer Array-ID in einem Ausdruck werden sofort von "Array von T" in "Zeiger auf T" konvertiert, und der Wert wird in einen Zeiger auf das erste Element des Arrays konvertiert. Die Array-Notation (z. B.
a[1][2]
) wird immer in Zeigerarithmetik (z*(*(t+1)+2)
. B. ) erweitert.Die Array-Notation in Deklarationen und Definitionen ist jedoch etwas ganz anderes. Ein Array-Deklarator beschreibt ein "Array vom Typ T ", wobei die Werte dieses Typs Sequenzen von Elementen vom Typ T sind . Bei einer Definition eines Array-Objekts geht es darum, eine bequeme und leicht verständliche Array-Notation zu verwenden, um die entsprechende Speichermenge für das gewünschte Array von Objekten zuzuweisen, sodass sich die Array-ID auf diesen Speicher bezieht, ohne dass er wie ein Zeiger aussieht. Tatsächlich ist die Array-Notation in einer Deklaration oder Definition ein Makro, das einen Ausdruck mit
sizeof()
und arithmetisch generiert , und im Fall einer Definition das Äquivalent vonalloca()
für Auto-Arrays oder gleichwertig im Linker für globale Arrays und alles zur Kompilierungszeit (außer bei C99-Arrays mit variabler Länge).Die Verwendung der Array-Notation in Ausdrücken und die Verwendung von Array-Typen ist nicht so eng miteinander verbunden, obwohl es Tradition und Redewendung ist, die Array-Notation in Ausdrücken zu verwenden, um auf die Speicherung in Objekten zu verweisen, die als Arrays deklariert und / oder definiert sind. Sie können die Array-Notation genauso einfach mit einem Zeigertyp verwenden, um die Zeigerarithmetik übersichtlicher und aussagekräftiger zu gestalten. Tatsächlich entspricht in C ein Ausdruck der Form
e1[e2]
genau dem Ausdruck*((e1)+(e2))
. Die übliche binäre Konvertierung wird auf die beiden Operanden angewendet, und das Ergebnis ist immer ein Wert . Da der Indirektionsoperator (*
) einen Zeiger als Operanden haben muss, muss einer vone1
unde2
ein Zeiger und der andere eine Ganzzahl sein, aber es spielt keine Rolle, welcherda die anfängliche unäre Konvertierung für jedes "Array von T" darin besteht, es in "Zeiger auf T" zu konvertieren. Die Array-Notation in Ausdrücken ist praktisch ein Compiler-Makro (auf Sprachebene) zum Generieren von Zeigerarithmetikausdrücken.C funktioniert also bereits so, wie Sie es vorschlagen, aber Sie verwechseln die Verwendung der Notation in zwei sehr unterschiedlichen Kontexten.
quelle