Pages: [1] 2   Go Down
Author Topic: dynamisches Array  (Read 1613 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hallo zusammen,
ich würde gerne eine Feld erstellen in dem die Anzahl der Feldelemente zufällig sein soll.

Ich habe mir das so gedacht:

int zufall = random(2,5);
int zufallsarray[zufall] = {};

und dann später das Feld in einer Schleife mit Werten füllen.

Jetzt kriege ich aber die Fehlermeldung :

   error: variable-sized object 'zufallsarray' may not be initialized

was bedeutet das? muss ich meine Idee vielleicht doch mit malloc realisieren?

wäre super wenn mir jemand helfen könnte smiley
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 78
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Der C++-Standard sieht keine Arrays dynamischer Länge vor. Willst du solche hinzufügen bedarf es also solcher Dinge wie new oder malloc.
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1397
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Zum Beispiel so:
Code:
void setup() {
 // groesse des arrays ermitteln
 int zufall = random(2,5);

 //erstmal nur ein zeiger auf das array
 int* zufallsarray;
 
  //speicher in der passenden groesse reservieren
  zufallsarray = (int*)malloc(zufall*(sizeof(int)));

  //an allen stellen auf 0 setzen (optional)
  for (int i=0;i<zufall;i++) {
    zufallsarray[0] = 1;
  }
}
...
void loop() {
    ....
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Perfekt! Danke smiley vielen vielen Dank smiley
Logged

Offline Offline
Full Member
***
Karma: 2
Posts: 213
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Code:
//an allen stellen auf 0 setzen (optional)
  for (int i=0;i<zufall;i++) {
    zufallsarray[0] = 1;
Ist das so richtig? Wenn ja, muss ich nochmal zurück zu den basic tutorials...

ich hätte jetzt
Code:
zufallsarray[i] = 0;
erwartet...

« Last Edit: October 01, 2012, 12:53:03 pm by o_lampe » Logged

It's not my fault when my Posts are full of Errors. This stupid autocorrection from my browser is set up for german grammar.

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 78
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Deine Fassung sieht auf jeden Fall sinnvoller aus.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 92
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Code:
//an allen stellen auf 0 setzen (optional)
  for (int i=0;i<zufall;i++) {
    zufallsarray[0] = 1;
Ist das so richtig? Wenn ja, muss ich nochmal zurück zu den basic tutorials...

ich hätte jetzt
Code:
zufallsarray[i] = 0;
erwartet...



Das Füllen mit 0 kann man sich übrigens sparen, wenn man statt malloc die Funktion calloc verwendet, die macht das gleich mit.

Rudi
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1397
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ist das so richtig? Wenn ja, muss ich nochmal zurück zu den basic tutorials...
ich hätte jetzt
Code:
zufallsarray[i] = 0;
erwartet...
Das ist natürlich richtig. Sorry für die Nachlässigkeit, das Beispiel war nur fix aus der Hüfte geschossen. Im Prinzip ging es mir vorwiegend darum, das wie man dynamisch den Speicher für ein Array alloziiert.
Mario.
Logged

D-49565 Bramsche
Offline Offline
Sr. Member
****
Karma: 6
Posts: 477
Geht nich ? Gipp's nich !
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich greife diesen sehr informativen Fred noch mal auf, weil er (fast) genau mein Prob trifft.
Jetzt komme ich progtechnisch aus der Delphi-Ecke und bin des C nicht soooo mächtig. Zum anderen ist mein Mega zum selbstprobieren noch nicht da.
Also hier erstmal ein theoretische Anfrage.
Die Aufgabenstellung mal kurz:

Ich möchte einen Stepper sozusagen eine "Figur" fahren lassen - soll heissen: Einige U's langsam vorwärts, diverse U's schneller vorwärts, dann einige U's gemäßigt rückwärts usw. Dazu bekommt die Steuerung/der Arduino jeweils ein Kommando aus Integern: Richtung, Anzahl Steps, Geschwindigkeit (und ggf.noch ein paar mehr).
Eine "Figur" (oder auch Sequenz) besteht aus aus einer definierten Anzahl gleicher Kommandos, deren Anzahl nicht festliegt !
D.h., es können mal weniger als 10 sein oder auch nur ein Kommando, durchaus aber auch mal mehr. 20, 50, 100 ?

So ein Kommando würde ich dann in eine Struktur verpacken wollen:
Code:
typedef struct CMD_record
   {
       int Dir;
       int Steps;
       int Speed;
   };
Das wäre doch so weit OK - oder ?

Nun kommt die Dynamik ins Spiel. Ich bräuchte ein Array aus der o.g. Struct in variabler Länge, da ich wie gesagt nicht weiß, wie lang so eine Sequenz ist/werden kann. Statisch zu groß vereinbart verballer ich entweder immer jede Menge Speicher oder bekomme umgekehrt nie/selten eine komplette Sequenz in den Speicher.
Also liegt der Gedanke nahe, ein dynamischen Array aus o.g. Struktur zur Laufzeit anzulegen.
In Delplhi für mich kein Thema, aber auf dem Arduino mit C .....

Der steuernde PC würde erst mal anfragen, ob ich für "NumSeq" auch genug Speicher habe.
Als (globale) var würde ich definieren:
Code:
CMD_record* CMD_Seqence

Wäre folgendes zum "Speicherholen" richtig ?! (mit calloc gleich alles auf 0 setzen)
Code:
CMD_Sequence  = (int*) calloc (NumSeq * (sizeof (CMD_Record)));
Ist dieses (int*) vor dem calloc OK so ? Sind ja alles nur int's ....

Ob nun wie auch immer OK oder nicht (ihr werdet mich sicher belehren) - wie bekomme ich heraus, das diese Alloziierung auch erfolgreich war ?
Sprich (noch) genügend Speicher vorhanden und Befehl erfolgreich ?
Oder muss/sollte man das vorher prüfen ? Wenn ja, wie ?

Vorrausgesetzt, alles ist "grün", würde ich dann in meine Seriell-Auswerteroutine die Daten vom PC wie folgt setzen:
Code:
for (int i=0; i<NumSeq; i++) {
  /* hier wird jeweils vorher Dir, Steps und Speed ausgewertet */
  CMD_Sequence.Dir[i].Dir = Dir;
  CMD_Sequence.Dir[i].Steps = Steps;
  CMD_Sequence.Dir[i].Speed = Speed;
}

Und zum Schluss: Wie werde ich die alloziierten Daten in CMD_Sequence wieder rückstandsfrei los ?

Zusatzfrage für die Spezi's:
Wenn man solche "Aktionen" z.B. mit/bei mehreren Motoren durchführt, welche alle unabhängig laufen und unterschiedlich lange "Figuren" haben, könnte ich mir sehr gut vorstellen, das irgendwann mal der Speicher in der Belegung etwas "zerklüftet" ist und sich größere Blöcke nicht mehr am Stück belegen lassen.
Managed ein Arduino so etwas selbsttätig oder muss man da mit so was wie in der Art eines Festplattendefragmentieres ran und aufräumen ?
« Last Edit: June 25, 2013, 07:53:38 am by TERWI » Logged

To young to die - never to old for rock'n roll

Offline Offline
Faraday Member
**
Karma: 79
Posts: 2707
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

http://www.cplusplus.com/reference/cstdlib/calloc/

Calloc gibt dir null zurück wenn es nicht funktioniert hat und einen void pointer wenn es geglückt ist. Der int Pointer ist falsch, du du ein Array von Pointern auf structs willst und nicht ein array aus integer Pointern.

Das Gegenstück zu malloc/calloc ist "free":
http://www.cplusplus.com/reference/cstdlib/free/

Was theoretisch auch möglich wäre ist ein Vector aus der Standard Template Library:
http://andybrown.me.uk/wk/2011/01/15/the-standard-template-library-stl-for-avr-with-c-streams/

Sieht Ressourcen-mäßig gut aus:
Quote
Dynamic memory usage for a vector is quite good as there is almost no additional overhead over and above the space required for the objects themselves. I have implemented a default allocate-ahead policy of 20 objects which you can change if you want (see later). If you have a rough idea of how many objects you are going to need then you can greatly cut down on memory resizing by calling the reserve(n) function ahead of time.
« Last Edit: June 25, 2013, 09:28:46 am by Serenifly » Logged

Germany
Offline Offline
Faraday Member
**
Karma: 49
Posts: 2719
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Statisch zu groß vereinbart verballer ich entweder immer jede Menge Speicher oder bekomme umgekehrt nie/selten eine komplette Sequenz in den Speicher.
Also liegt der Gedanke nahe, ein dynamischen Array aus o.g. Struktur zur Laufzeit anzulegen.
In Delplhi für mich kein Thema, aber auf dem Arduino mit C .....

Auf einem Controller kann man keinen Speicher verballern.
Entweder du hast so viel wie du brauchst, dann reserviere ihn gleich, oder eben nicht.

Natürlich kann man zur Laufzeit ausprobieren, ob malloc funktioniert, aber eigentlich sollte man bei solchen Anwendungen vorher wissen, was geht. Kann auch sein, dass malloc dir zwar einen Speicherbereich zurückliefert, aber wehe du machst danach noch einen Funktionsaufruf.
Der Stack ist nicht so rücksichtsvoll, sondern zerschreibt dir deinen Speicher. Oder durch Schreiben in den dynamischen Speicher machst du dir den Stack kaputt.

Wenn du dir eh Gedanken machst, krieg doch gleich raus, wieviel geht, beleg das statisch und merk dir die Größe als Konstante.

Oder nutzen Controller heutzutage ihren RAM-Speicher, wenn nichts los ist, temporär für einen Bildschirmschoner ?
 
Das Problem mit dem Stackoverflow hast du mit statischem Speicher natürlich auch, zugegeben. Aber da bist du dann selber schuld.
Ich wollte ja auch nur mal gewarnt haben smiley-wink

Logged

Germany, Osnabrück
Offline Offline
God Member
*****
Karma: 25
Posts: 572
E-Technik Student - Master
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wir haben auch im Studium in Unterschiedlichen Fächern / andere Professoren gelernt, dass wir niemals dynamische Speicherverwaltung auf einem Mikrocontroller verwenden sollen. 2kB - 8kB Ram sind sehr schnell belegt wenn ein Fehler in der Anwendung auftritt und dann such mal.

Es kam schon schlaue Leute die das versucht haben bei einem Koffer Gebäck System an einem Flughafen. Resultat der Flughafen hat deutlich später eröffnet. Der Schaden ging in die Millionen. Der Fehler lag an einem zu klein gedachten Speicherbereich. Die Suche nach dem Fehler hat Monate gedauert. So wie ich mich dran erinnere war der Speicher nur wenige Bytes zu klein .....

Logged

D-49565 Bramsche
Offline Offline
Sr. Member
****
Karma: 6
Posts: 477
Geht nich ? Gipp's nich !
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@Serenifly
Also wäre das dann so richtig ?!
Code:
CMD_Sequence  = (CMD_Record*) calloc (NumSeq * (sizeof (CMD_Record)));
Das mit den Vektoren check ich (noch) nicht ...

@michael_x
Wenn ich von vornherein wüsste, wieviele Sequenzen für eine Figur kommen, würde ich mir da sicher keinen Kopf machen.
Das soll ja eben der Clou an dieser Steuerung sein - in Kombination mit einem Flag "Endlos" dann auch bis zum Sankt Nimmerleinstag.
Natürlich kann ich auch hingehen und rechen: Was brauch ich für Variablen ? Wie groß könnte der max. Bedarf für den Stack sein, lasse noch ein paar hundert Byte Luft und greife mir dann den Rest (sagen wir einfach mal 6 KB) und hätte dann Platz für max. 1000 Records äh Structs.
Sicherlich funktionell, aber da sträubt sich in mir irgendwie alles.
Quote
... aber wehe du machst danach noch einen Funktionsaufruf.
Der Stack ist nicht so rücksichtsvoll, sondern zerschreibt dir deinen Speicher. Oder durch Schreiben in den dynamischen Speicher machst du dir den Stack kaputt.
Natürlich kommt mit Sicherheit danach nicht nur ein Funktionsaufruf ! Wie darf ich "nicht so rücksichtsvoll" verstehen ? Schreibt ein Arduino einfach so planlos in den Speicher und guckt nicht vorher irgendwo nach, ob der schon reserviert ist ?
Das wäre ja fatal, desaströs !

@Jomelo
Ja, eben sind 2-8KB ratzfatz belegt. Vor allem, wenn man es vom PC her so gewohnt, sich mal eben schnell nen Paar MB zu holen ....
Es könnte ja auch durchaus sein, das wenn man noch andere LIBs mit eingebunden hat und diese sich auch noch die einen oder anderen Bytes in unbekannter Menge holen (wollen) sehr schnell ein Prob mit zuvor benannter Rechenweise bekommt und der kleine Kalkulator dann out of memory ist ...

Mich beschleicht da eher so ein Gefühl, dass diejenigen, welche mit erhobenem Zeigefinger vor dynamischer Speicherverwaltung warnen, eher keinen Plan davon haben, wie man es richtig und sicher macht.
Es sei denn, der Arduino macht mit seiner vermeintlich seltsamen Speicherverwaltung (das sage ich nur einfach mal so) einem tatsächlich einen trich durch die Rechnung macht.

PS: Wer bei zu klein dimensioniertem Speicher nicht in der Lage ist, mittels Logik, Debuggern oder im worst-case jeden Schritt protokollieren lassen, so einen Fehler nicht in adäquater Zeit findet, der sollte sich vielleicht mal nach nem anderen Job umsehen. Natürlich bib es fiese Käfer, die sich gut tarnen & verstecken - aber finden tut man die mit Verstand und Logik immer !


Logged

To young to die - never to old for rock'n roll

Germany
Offline Offline
Faraday Member
**
Karma: 49
Posts: 2719
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Schreibt ein Arduino einfach so planlos in den Speicher und guckt nicht vorher irgendwo nach, ob der schon reserviert ist ?
Das wäre ja fatal, desaströs !

Ich denke mal: ja. Was soll er denn sonst machen ?

Der RAM enthält von der einen Seite her statische Variable, von der anderen den Stack. Dazwischen ist der dynamische Speicher.
Dass (ohne new oder malloc) der Stack und statische Variable sich überschneiden können, hab ich schon erlebt: Führt nicht immer zu einem Reset smiley-wink

Die wenigsten ( die new / malloc verwenden ), prüfen zur Laufzeit, ob sie den Speicher überhaupt bekommen haben, habe ich den Eindruck... 
Logged

Offline Offline
Faraday Member
**
Karma: 79
Posts: 2707
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Das mit den Vektoren check ich (noch) nicht ...
Ein Vektor ist eine Datenstruktur, die einem Array ähnelt, aber die Größe passt sich dynamisch an und man kann Elemente beliebig hinzufügen und entfernen. In C++ ist das Teil der Standard Template Library, aber diese ist in der Arduino IDE standardmäßig nicht enthalten. Wohl auch da sie mit dynamischem Speicher arbeitet. Wurde aber von Usern implementiert.

Ein Vektor hat im Hintergrund ein Array und wird mit einer einstellbaren Standardgröße initialisiert (da nimmt man was man ungefähr erwartet + etwas mehr). Wenn diese Größe erreicht ist, wird ein neues, größeres Array erstellt und das alte hinein kopiert. Das geschieht automatisch im Hintergrund. Damit ist man nicht auf eine Feste Größe beschränkt, aber erkauft sich das mit etwas Overhead. Im Gegensatz zu komplexeren Strukturen hält sich das aber in Grenzen.

Hier ist die Dokumentation der Standard C++ Version:
http://www.cplusplus.com/reference/vector/vector/

Bezüglich deiner Anweisung. Wenn du so ein einzelnes Struct erstellen willst, muss noch das NumSeq raus. Das brauchst du nur wenn so für das ganze Array auf einmal Speicher reservieren willst (Anzahl der Structs * Größe eines Structs). Dann musst du den Pointer aber auch einem Array zuweisen. Dessen Variable ist zwar auch ein Pointer auf das Struct, aber du musst irgendwann mal sowas machen:
CMD_Record CMD_Sequence[10];

Sowie ich das sehe bringst du da zwei Sachen durcheinander. Entweder du hast ein Array aus Structs. Dann musst du mit calloc den gesamten Speicher reservieren und den Pointer einem Array zuweisen. Oder du hast ein Array aus Pointer auf Structs. Dann musst du einmal Speicher für die Pointer allozieren und dann jedes Struct einzeln erstellen (so wie du es jetzt hast, aber ohne das "mal NumSeq"). Das wäre für dich wahrscheinlich praktischer, da die Structs dann irgendwo im Speicher liegen können und das Array kleiner ist (an Speicher, nicht an Länge).
« Last Edit: June 26, 2013, 06:18:37 am by Serenifly » Logged

Pages: [1] 2   Go Up
Jump to: