Initialisierung des gesamten 2D-Arrays mit einem Wert

81

Mit der folgenden Erklärung

Ich bekomme das Array mit allen Nullen, aber mit der folgenden

Ich bekomme das Array nicht mit allen einem Wert. Der Standardwert ist immer noch 0.

Warum dieses Verhalten und wie kann ich mit allen 1 initialisieren?

EDIT: Ich habe gerade verstanden, dass bei Verwendung memsetmit dem Wert 1 jedes Byte auf 1 gesetzt wird und daher der tatsächliche Wert jeder Array-Zelle nicht 1 ist, sondern 16843009. Wie setze ich es auf 1?

Krake
quelle
1
@ckruse: Die Frage ist nicht wie , sondern warum .
Masoud
@ MM. Die Antwort finden Sie in dem Thread, den ich verlinkt habe.
ckruse
Das Problem war eigentlich why and howbeides. :)
Kraken
@Kraken Die Frage in Ihrer Bearbeitung sollte möglicherweise als separate Frage von dieser gestellt werden.
Lundin
1
@ Kraken Eigentlich habe ich diese Frage hier gefunden . Ich würde empfehlen, wie in meiner Antwort vorgeschlagen (natürlich!) Zu tun und mich nicht auf GCC-Erweiterungen zu verlassen.
Lundin

Antworten:

123

Sie erhalten dieses Verhalten, weil int array [ROW][COLUMN] = {1};dies nicht bedeutet, dass "alle Elemente auf eins gesetzt werden". Lassen Sie mich versuchen, Schritt für Schritt zu erklären, wie dies funktioniert.

Die explizite, zu klare Methode zum Initialisieren Ihres Arrays lautet wie folgt:

Mit C können Sie jedoch einige Elemente in einem Array (oder einer Struktur / Vereinigung) weglassen. Sie könnten zum Beispiel schreiben:

Das heißt, initialisieren Sie die ersten Elemente mit 1 und 2 und den Rest der Elemente "als ob sie eine statische Speicherdauer hätten". In C gibt es eine Regel, die besagt, dass alle Objekte mit statischer Speicherdauer, die vom Programmierer nicht explizit initialisiert werden, auf Null gesetzt werden müssen.

Im obigen Beispiel wird die erste Zeile auf 1,2 und die nächste auf 0,0 gesetzt, da wir ihnen keine expliziten Werte gegeben haben.

Als nächstes gibt es in C eine Regel, die einen lockeren Klammerstil zulässt. Das erste Beispiel könnte genauso gut geschrieben werden wie

Obwohl dies natürlich ein schlechter Stil ist, ist es schwieriger zu lesen und zu verstehen. Diese Regel ist jedoch praktisch, da wir damit schreiben können

Dies bedeutet: "Initialisieren Sie die allererste Spalte in der ersten Zeile auf 0 und alle anderen Elemente so, als ob sie eine statische Speicherdauer hätten, dh setzen Sie sie auf Null."

Deshalb, wenn Sie es versuchen

es bedeutet "initialisiere die allererste Spalte in der ersten Zeile auf 1 und setze alle anderen Elemente auf Null".

Lundin
quelle
2
Vielen Dank dafür, was kann ich tun, um das gesamte Array mit 1 zu initialisieren? wenn man bedenkt, dass meine Zeilen und Spalten eine Größe von Hunderten haben?
Kraken
1
@ Kraken Mit Makro-Tricks. Sehen Sie das .
Lundin
Ist es nur ich oder brauchen Sie den zweiten Satz Klammern:int array [ROW][COLUMN] = {{0}};
user1794469
@ user1794469 Nein, tust du nicht.
Lundin
1
@ user1794469 Ja, und das ist gut so, denn in den meisten Fällen ist das Überspringen von Klammern eine schlechte Praxis. Der Compiler muss jedoch keine Diagnose stellen. Bezüglich der guten / schlechten Praxis für diesen Fall siehe meine Antwort auf diese Frage .
Lundin
40

Wenn Sie das Array initialisieren möchten, -1können Sie Folgendes verwenden:

Aber das wird funktionieren 0und -1nur

user2021512
quelle
15
Es ist einfacher, "sizeof (Array)" anstelle von "sizeof (Array [0] [0]) * row * count" zu verwenden.
Vladyslav Savchenko
Es funktioniert für jedes konstante Byte, obwohl mir nicht klar ist, was neben 0000und1111
user1794469
4
müssen <cstring>in c ++
mtk
Aber warum funktioniert das nur für 0 und -1?
user9989615
12

Dies initialisiert nur das erste Element auf 1. Alles andere erhält eine 0.

In der ersten Instanz machen Sie dasselbe: Sie initialisieren das erste Element auf 0 und der Rest auf 0.

Der Grund ist einfach: Für ein Array initialisiert der Compiler jeden Wert, den Sie nicht mit 0 angeben.

Mit einem charArray können Sie memsetjedes Byte festlegen, dies funktioniert jedoch im Allgemeinen nicht mit einem intArray (obwohl es für 0 in Ordnung ist).

Eine allgemeine forSchleife erledigt dies schnell:

Oder möglicherweise schneller (je nach Compiler)

teppic
quelle
1
@Kraken - Das tut es nicht - 0initialisiert auch nur den ersten Wert. Der Rest 0wird dann standardmäßig mit initialisiert .
Teppic
@EricPostpischil also setzt es alle Bytes mit 1, also wenn ich 32bit Integer betrachte, wenn mein valueFeld in memset1 ist, dann ist der tatsächliche Wert in der Matrix nicht 1, aber 2^0 + 2^8 + 2^16 + 2^24?
Kraken
@ Kraken: Im Wesentlichen ja. memsetSetzt jedes Byte in seinem Ziel auf den angegebenen Wert. Dies funktioniert nicht, um einen Wert intauf 1 zu setzen . Es memsetkann nicht zum Festlegen von Werten für Mehrbyte-Objekte verwendet werden, es sei denn, Sie möchten, dass jedes Byte des Objekts auf denselben Wert gesetzt wird.
Eric Postpischil
@EricPostpischil Es gibt also keine andere Möglichkeit, als jede manuell zu initialisieren? Wenn man bedenkt, dass meine Zeilen und Spalten sogar in den wenigen Tausend sind?
Kraken
@ Kraken Ich habe eine Erklärung gepostet, warum {1} nicht funktioniert. Und tatsächlich gibt es keinen anderen Weg als die manuelle Initialisierung. Sie müssen zwar nicht Tausende von Zahlen eingeben, es gibt Makrotricks, aber das ist vielleicht ein Thema für eine andere Frage.
Lundin
8

Beachten Sie, dass GCC eine Erweiterung der angegebenen Initialisierungsnotation hat, die für den Kontext sehr nützlich ist. Es ist auch clangkommentarlos erlaubt (teilweise weil es versucht, mit GCC kompatibel zu sein).

Mit der Erweiterungsnotation können Sie ...einen Bereich von Elementen festlegen, die mit dem folgenden Wert initialisiert werden sollen. Zum Beispiel:

Die Ausgabe ist nicht überraschend:

Beachten Sie, dass Fortran 66 (Fortran IV) Wiederholungszählungen für Initialisierer für Arrays hatte; Es kam mir immer seltsam vor, dass C sie nicht bekam, als der Sprache bestimmte Initialisierer hinzugefügt wurden. Und Pascal verwendet die 0..9Notation, um den Bereich von 0 bis einschließlich 9 zu bestimmen, aber C wird nicht ..als Token verwendet, so dass es nicht verwunderlich ist, dass dies nicht verwendet wurde.

Beachten Sie, dass die Leerzeichen um die ...Notation im Wesentlichen obligatorisch sind. Wenn sie an Zahlen angehängt sind, wird die Zahl als Gleitkommazahl interpretiert. Zum Beispiel 0...9würde , wie in Token aufgeteilt werden 0., ., .9und Gleitkommazahlen dürfen nicht als Array - Indizes. Mit den genannten Konstanten ...ROW-1würde das keine Probleme verursachen, aber es ist besser, sich in die sicheren Gewohnheiten zu begeben.


Nachträge:

Ich stelle nebenbei fest, dass GCC 7.3.0 Folgendes ablehnt:

Hier gibt es einen zusätzlichen Satz geschweifter Klammern um den skalaren Initialisierer 1( error: braces around scalar initializer [-Werror]). Ich bin mir nicht sicher, ob dies korrekt ist, da Sie normalerweise geschweifte Klammern um einen Skalar in angeben können int a = { 1 };, was vom Standard ausdrücklich zugelassen wird. Ich bin mir auch nicht sicher, ob es falsch ist.

Ich frage mich auch, ob eine bessere Notation wäre [0]...[9]- das ist eindeutig, kann nicht mit einer anderen gültigen Syntax verwechselt werden und vermeidet Verwechslungen mit Gleitkommazahlen.

Vielleicht würde das Normungsgremium das in Betracht ziehen?

Jonathan Leffler
quelle
6

Verwenden Sie die folgende Methode, um ein 2d-Array mit Null zu initialisieren: int arr[n][m] = {};

HINWEIS : Die obige Methode funktioniert nur zum Initialisieren mit 0;

Gaurav Suthar
quelle
3

Verwenden Vektor Array statt:

Jogendra Kumar
quelle
3
Möglich, aber OP hat C ++ nicht erwähnt.
Sangeet
0

Dies dient zum Initialisieren von Char-Array-Elementen in Leerzeichen.

Inhalator
quelle