2016-08-03 9 views
2

Ich mache shenanigans mit Zeigern für ein Arduino-Hobby-Projekt, und ich habe eine Situation, die ich nicht lösen kann.Initialisieren anonymen Array von Zeigern

Grundsätzlich habe ich eine globale (weil Arduino) Array von Zeigern zu Thing. Ich möchte es nicht während der Deklaration initialisieren, aber ich möchte die nette Array-Initialisierungssyntax nutzen.

Bitte beachten Sie, dass dies ein Arduino-Projekt ist und so eine ungewöhnliche Mischung aus C und C++ verwendet, weil Arduino. Von einigen Grundlagenforschung, sieht es so aus, wenn es in C oder C++ ohne Bibliotheken funktioniert, wird es dafür funktionieren.

Hinweis: Ich verwende NULL als eine Möglichkeit, das Ende des Arrays zu erkennen, während ich es an anderer Stelle im Code überstreiche.

So etwas so:

struct Thing { 
    int i; 
}; 
Thing * MakeThing() { 
    return new Thing; 
} 
Thing * things[] = { 
    NULL 
}; 
void setup() { 
    things = (Thing*[]){ 
    MakeThing(), 
    NULL 
    }; 
} 

Allerdings wird dies mir eine error: incompatible types in assignment of 'Thing* [2]' to 'Thing* [1]'

Ich habe versucht:

Thing* _things[] { 
    MakeThing(), 
    NULL 
    }; 
    things = _things; 

gleichen Fehler.

Ich habe versucht:

things = new Thing*[] { 
    MakeThing(), 
    NULL 
    }; 

gleichen Fehler.

Ich habe versucht:

things = new Thing** { 
    MakeThing(), 
    NULL 
    }; 

, die ich versuchte, ein error: cannot convert '<brace-enclosed initializer list>' to 'Thing**' in initialization

bekommt:

things = new Thing*[] { 
    MakeThing(), 
    NULL 
    }; 

die error: incompatible types in assignment of 'Thing**' to 'Thing* [1]'

Was ist los wird, dass dies nicht funktioniert? Wie kann ich es zum Laufen bringen?

+3

Hinweis: Es gibt keinen 'neuen' Operator in C. – wildplasser

+0

Ich soll die Variable von' c' nach 'C++' ändern – chqrlie

+0

Sie können keine Arrays zuweisen. Ich glaube nicht, dass C++ zusammengesetzte Literale hat. – 2501

Antwort

1

Mit Thing* things[] = {NULL}:

erklären Sie variable things als eine Anordnung von einem einzigen Element (vom Typ Thing*).

Sie können dieses Array nicht ändern, nachdem Sie es deklariert haben - weder seine Größe noch seine Adresse.

Das einzige, was Sie ändern können, ist der Inhalt dieses Arrays, d. H. Das erste (und einzige) Element.

1

ich Ihnen things wollen eine zugeordnete Array von Größe Punkt 2, müssen Sie 3-Anweisungen schreiben:

things = new Thing*[2]; 
things[0] = MakeThing(); 
things[1] = NULL; 

Die neue Stil C99 Verbindung Literalsyntax ist nicht in C unterstützt ++ oder nur als eine Erweiterung von einige C++ - Compiler, aber dies würde immer noch nicht zu Ihrem Zweck passen, da das Array eine automatische oder statische Lebensdauer hätte, nicht dynamisch.

EDIT: auf der Frage erledigt die Umformulierung gegeben, ist die Antwort ganz einfach: Der globale things Array muss als mit 2 Elementen definiert werden und kann in setup mit 2 Aussagen initialisiert werden:

struct Thing { 
    int i; 
}; 
Thing *MakeThing(void) { 
    Thing *t = calloc(sizeof(t)); 
    return t; 
} 
Thing *things[2]; // implicitly initialized to { NULL, NULL }; 
void setup(void) { 
    things[0] = MakeThing(); 
    things[1] = NULL; 
} 

oder wenn Sie unbedingt darauf bestehen, die C99-Verbindung Literale auf Kosten der Lesbarkeit auf der Verwendung können Sie verwenden:

void setup(void) { 
    memcpy(things, (Thing*[]){ MakeThing(), NULL }, sizeof things); 
} 

Aber ich bin nicht sicher, dass der Arduino-Compiler s unterstützt diese Syntax. Arduino-C ist weder C noch C++.

+0

Hallo, deshalb ist dies nur C markiert, nicht C * und * C++. – Narfanator

0

Sie können nur eine Menge mit statischer Initialisierung tun, zum Beispiel (das ist eine doppelt verknüpfte Liste):

struct list { 
     struct list *prev; 
     struct list *next; 
     int val; 
     }; 

struct list arr[] = 
{ {arr+1, arr+2, 1} 
, {arr+3, arr+4, 2} 
, {arr+5, arr+6, 3} 
, {arr+3, arr+4, 4} 
, {arr+3, arr+5, 5} 
, {arr+4, arr+6, 6} 
, {arr+5, arr+6, 7} 
     }; 

Wenn Sie im Array mehr Platz mögen Sie eine Sentinel-Code verwenden könnten zu ermöglichen, den Beginn des ungenutzten Raum bestraft:

struct list arr[ 100] = 
{ {arr+1, arr+2, 1} 
, {arr+3, arr+4, 2} 
, {arr+5, arr+6, 3} 
, {arr+3, arr+4, 4} 
, {arr+3, arr+5, 5} 
, {arr+4, arr+6, 6} 
, {arr+5, arr+6, 7} 
, { NULL, NULL, -1} 
     }; 

... Oder den Präprozessor als Zeilenzähler missbrauchen:

struct list arr[ 100] = 
# /* reset preprocessor line counter */ 
# 0 "omg" 
{ {arr+1, arr+2, 1} 
, {arr+3, arr+4, 2} 
, {arr+5, arr+6, 3} 
, {arr+3, arr+4, 4} 
, {arr+3, arr+5, 5} 
, {arr+4, arr+6, 6} 
, {arr+5, arr+6, 7} 
     }; 
unsigned watermark = (__LINE__ -1); 

... und natürlich könnte das obige geändert werden, indem die angegebene Initialisierungssyntax verwendet wird.

BTW: Dies ist kein DoublyLinkedList, (die Offsets falsch aussehen), aber Sie bekommen die Idee ...

+0

Danke! Wenn ich das machen wollte, aber "arr" auf dem Heap und nicht den Stack zugewiesen bekommen hat, wie würde ich das tun? – Narfanator

+1

Das ist unmöglich. Heap-Allocation benötigt Code, Sie müssen malloc() oder zumindest brk() aufrufen. Nochmals: Sie können in Initialisierern keinen Code (Aufruffunktionen) verwenden. (außer manchmal in C++, mit einem Konstruktor) – wildplasser

1

Zunächst einmal all jene nicht kompiliert, weil es illegal ist, zu einem Array zuweisen (zu einer Variablen des Array-Typs) in C.

Zweitens, selbst wenn Sie ein Array in C zuweisen könnten (nehmen wir an, es kopiert alle Elemente), was Sie versuchen, immer noch nicht funktionieren, weil Sie würde zwischen verschiedenen Array-Typen zuweisen - die Größe ist Teil eines Array-Typs. Thing *[1] und Thing *[2] sind völlig verschiedene Arten. Wenn Sie eine Variable vom Typ Array haben, wird die Größe zum Zeitpunkt der Kompilierung fest codiert. Ihre Variable things hat den Typ Thing *[1] und ist zur Kompilierzeit fest codiert und kann nicht geändert werden. (Bei C99-VLAs können Sie eine Array-Variable haben, deren Größe zur Kompilierungszeit nicht fest codiert ist, aber zu dem Zeitpunkt festgelegt ist, zu dem die Array-Variable definiert ist und die später während der Lebensdauer der Variablen nicht geändert werden kann.)

Wenn Sie also eine Variable haben möchten, die sich auf Arrays mit unterschiedlichen Größen während der Lebensdauer der Variablen bezieht, kann sie keinen Array-Typ haben. Sie müssen es vom Zeigertyp deklarieren (in diesem Fall Thing **). Das Array, auf dessen Elemente der Zeiger zeigt, muss dann dynamisch zugewiesen werden, und Sie müssen diese Zuordnung im Speicher verwalten. Dies ist im Grunde, was chrqlie's Antwort zeigt. Ich bin nicht sicher, welcher dynamische Zuteilungsmechanismus in diesem Arduino verwendet wird, da Sie sagen, dass es eine Mischung von Sprachen ist, aber in C++ würden Sie new []/delete [] verwenden und in C würden Sie malloc/free für dynamische verwenden Zuweisung.