Forum: Mikrocontroller und Digitale Elektronik Strukturmember zuweisung falscher Datentyp


von Markus (Gast)


Lesenswert?

Hi,


bin gerade dabei ein Menü zu erstellen. Jetzt bin ich auf ein Problem 
gestossen, das ich mir bisher nicht beantworten kann und hoffe das ihr 
mich auf den Pfad der Erleuchtung führen könnt :)




ich habe diese header Datei erstellt
1
#ifndef MEN_MENUE_H
2
#define MEN_MENUE_H
3
4
5
extern struct page_t hauptmenue;
6
7
8
/*   Struktur der Anzeige-Page. Jede Menüseite sowie Funktionsseite
9
*   wird durch diesen Struct definiert
10
*/
11
struct page_t{
12
  char bezeichnung[15];          // Menütext der Seite
13
  struct page_t *untermenuseiten_p[5];  // Array von Zeigern auf die Unterpages der aktuellen Page
14
  unsigned char selectedIndex;      // Aktuell ausgewählte unterpage 
15
  struct page_t *stammPage_p;        // Zeiger auf die Stamm/Elternpage
16
  void (*action)(unsigned char);      // Zeiger auf die Funktion die durch aktivieren ausgelöst wird
17
};
18
19
20
extern void MEN_initPages(void);
21
22
23
24
#endif // MEN_MENUE_H


Wollte nun in einer Funktion eine Page initialisieren. Wollte den Namen 
"Hauptmenue" einfach mal in "Test" ändern.

1
#include "MEN_Menue.h"
2
3
struct page_t hauptmenue = {"Hauptmenue",{0,0,0,0,0},0,0,0};
4
5
void MEN_initPages(void)
6
{
7
8
  hauptmenue.bezeichnung = "Test";
9
10
11
}


Wenn ich das aber mache, bekomme ich diese Fehlermeldung
(../Menue/MEN_main.c:8: error: incompatible types in assignment)
und er markiert mir die Zeile   ( hauptmenue.bezeichnung = "Test"; )



Ändere ich jetzt in meiner Struktur den member "bezeichnung", das 
anstatt
1
char bezeichnung[15];
2
char *bezeichnung;

geschrieben wird, bekomme ich beim kompilieren keinerlei Fehlermeldungen 
mehr.


Wo liegt hier der Fehler ? die Zeichenkette "Test" war doch weniger wie 
15 Zeichen lang.......



danke schonmal fürs lesen

gruss Maggus ;)

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Guck dir mal an, was Strings in C eigentlich sind.


Gruß
Lasse

von Dirk (Gast)


Lesenswert?

Versuchs mal damit:

strcpy(hauptmenue.bezeichnung,"Test");

von Markus (Gast)


Lesenswert?

Lasse S. schrieb:
> Guck dir mal an, was Strings in C eigentlich sind.

Ich weiss das Strings aus einem char Array mit '/0' am Ende bestehen. 
Und das "bezeichnung[0]" eigentlich ein Zeiger auf die Adresse der 
ersten Stelle dieses Arrays ist.
Wenn ich eine Zeichenkette zuweise, die länger ist wie char's reserviert 
wurden, überschreibe ich mir den Arbeitsspeicher. Die Gefahr laufe ich 
bei der zweiten Zuweisung von
1
 
2
char *bezeichnung = "test";
3
bezeichnung = "Das ist zu lang"
wenn mich nicht alles täuscht.



Das erklärt mir aber nicht, wieso ich beim initialiseren von
1
struct page_t hauptmenue = {"Hauptmenue",{0,0,0,0,0},0,0,0};
die Zwueisung machen darf, und später in der Funktion
1
hauptmenue.bezeichnung = "Test";
auf einmal nichtmehr.


Das würde ja bedeuten, das der Compiler bei einer einfachen Zuweisung 
und einer initialisierung unterschiede mit den Datentypen machen würde.


Will das jetzt nicht bis ins kleinste erklärt bekommen wenn es zu 
Umfangreich ist, aber ich würde mich über einen Schups in die Richtige 
Richtung freuen, damit ich weiss wo ich nachlesen muss (das wird 
wahrscheinlich nicht wenig sein :D )


gruss Maggus

von Markus (Gast)


Lesenswert?

Alles klar,

danke dir Dirk.

Strings im Nachinein zu verändern geht ja in C garnicht so einfach wie 
ich mir das gerade vorgestellt hatte.

Ich glaube ich lasse die Initialisierung bei der Variablendeklaration 
einfach weg.

Eben hab ichs verstanden......... ;)

von Markus (Gast)


Lesenswert?

oder auch nicht :D


Wieso muss ich den String mit

strcpy(hauptmenue.bezeichnung,"Test");

in die Struktur kopieren?
Selbst wenn ich die initialiserung am Anfang weglasse und nur zuweise, 
schreibt er den selben Fehler heraus.


Ich hab irgendwo noch einen ziemlich dicken Denkfehler drin......

von Huch (Gast)


Lesenswert?

Das habe ich mir gedacht :-)

Der Knackpunkt ist, wann und wie der Compiler die tatsächliche Länge des 
Strings überhaupt feststellen kann.

Deswegen der Unterschied zwischen Initialiserung und Zuweisung.Die 
Initialisierung sieht nur oberflächlich so aus wie eine Zuweisung. Der 
Punkt ist nicht der Typ sondern, das der Compiler, da er bei der 
Initialisierung die Länge des Strings kennt auch den Speicher dafür 
reservieren kann. Eine Zuweisung aber findet nicht zur Compilierzeit 
sondern zur Laufzeit statt. Dann aber kann der Compiler nichts mehr 
machen. Er ist garnicht mehr aktiv. Und die Programme bekommen keinen 
Code mit um zur Laufzeit die Länge von String zu berechnen wenn eine 
Zuweisung auftritt.

Das Ergebnis von dem oben gesagten ist, das Du zur Laufzeit selbst 
Speicher reservieren musst (alloc, malloc) und den String selbst 
kopieren musst (strcpy).

Das der Compiler bei strcpy denselben Fehler bringt wie bei dem Versuch 
der Zuweisung halte ich, sagen wir mal, für einen Irrtum.

von Huch (Gast)


Lesenswert?

>Selbst wenn ich die initialiserung am Anfang weglasse und nur zuweise,
>schreibt er den selben Fehler heraus.

Uups. Halt. Da habe ich falsch gelesen.

Der Knackpunkt ist wiegesagt, die Zuweisung. Zur Laufzeit kann das 
Programm nicht selbst die Länge berechnen und Speicher reservieren. Das 
musst Du dann selbst machen.

von Markus (Gast)


Lesenswert?

ok, ....

Lars hatte recht. Ich muss nochmal lesen wie ich Strings in C behandeln 
muss :D

das deklarieren von Strings über ein Array mit
1
 char text[15];
birgt doch mehr verständniss das man haben muss.


ich merke mir mal:
Wenn das char Array bereits angelegt wurde, sprich der Speicher 
bereitgestellt, muss dieser per Hand befüllt werden
text[0] = 'a'
text[1] = 'b'
etc.

Das ist deshalb nötig , da zur Laufzeit der Reservierte Speicher durch 
zuweisungen wie
text = "Test";
nichtmehr automatisch angepasst werden kann, wie es der Compiler machen 
würde.


Glaube das klingt ganz gut.....

von Karl H. (kbuchegg)


Lesenswert?

Markus schrieb:

> ich merke mir mal:
> Wenn das char Array bereits angelegt wurde, sprich der Speicher
> bereitgestellt, muss dieser per Hand befüllt werden
> text[0] = 'a'
> text[1] = 'b'
> etc.

Quatsch,
Das kann man so machen, wenn man Masochist ist.
Man kann aber auch ganz einfach die Sammlung der str.. Funktionen 
benutzen, die in deiner Laufzeitumgebung schon fertig vorhanden sind.

> Das ist deshalb nötig , da zur Laufzeit der Reservierte Speicher durch
> zuweisungen wie
> text = "Test";
> nichtmehr automatisch angepasst werden kann, wie es der Compiler machen
> würde.

Jain.
Der Knackpunkt ist, dass man in C keine Arrays zuweisen kann.
Arrays sind in C Bastarde, die sich nicht ganz so verhalten, wie andere 
Datentypen.

Spar dir das rumraten, kauf dir ein C Buch und arbeite das erste Drittel 
durch. Dann kennst du das alles und brauchst nicht mehr raten.

In der Zwischenzeit, bis du dein Buch hast, kannst du dich hier mal über 
Strings einlesen.
http://www.mikrocontroller.net/articles/FAQ#Wie_funktioniert_String-Verarbeitung_in_C.3F

von Blif (Gast)


Lesenswert?

Hallo,

mit
1
 struct page_t hauptmenue = {"Hauptmenue",{0,0,0,0,0},0,0,0};
sagst du dem Compiler, er solle dir die Strucktur 'hauptmenu', wie in 
den geschweiften Klammern beschrieben vor initialisieren. - Der Compiler
erledigt das.

Weiter unten in
1
 hauptmenue.bezeichnung = "Test";
weist du einen Zeiger einem Array zu. Der String "Test" ist als 
Konstante
im Code abgelegt und du hältst einen Zeiger darauf. Der C Compiler hat 
keine
Ahnung wie er den Zeiger dem Array zuweisen soll. Du musst also den Text 
mit
strcpy() hinein kopieren.

Hoffe es hilft weiter

Gruss

von Markus (Gast)


Lesenswert?

Auf jedenfall habt ihr mir schonmal ein gutes Stück weitergeholfen was 
mein Verständnissproblem betrifft.Danke nochmal...


Habe mir

"Programieren in C" von Kernighan und Ritchie gekauft
( Sehr detailliert, aber was das Thema hier betrifft schwer zu erlesen)

und

"Softwareentwicklung in C für Microprozessoren und Microcontroller" von
J. Wiegelmann
( Cooles Buch, macht Spass zu lesen)

gekauft


Meiner Meinung nach sind solche Kniffe die den Compiler betreffen, aus 
diesen Büchern (falls überhaupt vorhanden) nur schwer auszulesen.

Gibt es denn gute Bücher über den GCC Compiler zu kaufen, die auf 
Anfänger wie mich hin zielen und mir bei solchen Problemen weiterhelfen 
können ?

Wenn ich das hier so lese, ist das ja ziemlich verständlich, aber der 
Vorteil von diesem Forum ist das ihr auf meine Fragen eingehen könnt. 
Das kann ein Buch nicht.


Bin ja echt froh das es das Forum hier gibt ;)

von Huch (Gast)


Lesenswert?

>Meiner Meinung nach sind solche Kniffe die den Compiler betreffen, aus
>diesen Büchern (falls überhaupt vorhanden) nur schwer auszulesen.

Das ist kein Kniff. Das ist die Sprachdefinition und die lernst Du aus 
Deinem Buch. Man Vektoren initialisieren aber nicht zuweisen. Punkt.

>Gibt es denn gute Bücher über den GCC Compiler zu kaufen, die auf
>Anfänger wie mich hin zielen und mir bei solchen Problemen weiterhelfen
>können ?

Das hat nichts mit GCC zu tun, sondern folgt aus der Sprachdefinition. 
Jeder Compiler macht das (hoffentlich) so.

von Huch (Gast)


Lesenswert?

Tatsächlich ist meine Erklärung sozusagen eine nachträgliche.

Aber man kann das schliessen, wenn man mal selbst einen Compiler 
schreibt. Wenn Zuweisungen möglich wären müsste man Speicher 
alloziieren, evtl. den Zeiger verändern und sich Gedanken darüber 
machen, ob andere Zeigervariablen nicht evtl. auch diesen Zeiger 
enthalten. Wegen der Probleme die das mit sich bringt, ist man dankbar, 
das Zuweisungen nicht möglich sind.

von Markus (Gast)


Lesenswert?

Ich glaube das Problem ist das ich gelernter Autoelektriker bin mit 
garkeine Ahnung von Informatik.

Ich versuche mir das ganze Autodidaktisch beizubringen, und da muss man 
eben einfach auf die Hilfe von Büchern zurückgreifen (od. Foren).

Deshalb entschuldigt die Fragen, ..... ;)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.