char parameter in einem struct array ändert sich

Gast #6377844
hallo,
ich habe einen struct
1
typedef struct
2
{
3
    uint8 id;
4
    outputType_T type;
5
    char* name;
6
} output_T;
7

8
output_T output[10];

Die Parameter beschreibe ich in einer for-schleife.
Beim Namen gibt es aber Probleme. der wird zwar gesetzt, aber die Alten 
nehmen alle den namen vom neuen an
1
for(uint8 number=0; number<=10 number++)
2
{
3
  zehner = ((number-PWM_MIN)+1) / 10;
4
  einer = ((number-PWM_MIN)+1) % 10;
5
  sprintf(enumNameChar, "PWM_%d%d",zehner, einer);
6

7
    output[number].id = number;
8
    output[number].type = OUTPUT_PWM;
9
    output[number].name = enumNameChar;
10
}

Also am schluss haben alle den Namen vom letzten bekommen. Was mache ich 
hier falsch?
#6377851
Franz schrieb:
> for(uint8 number=0; number<=10 number++)

for(uint8 number=0; number<10 number++) denn du machst hier 11 
Schleifendurchläufe! Und was ist "uint8"?

Franz schrieb:
> zehner = ((number-PWM_MIN)+1) / 10;
>   einer = ((number-PWM_MIN)+1) % 10;

Wenn PWM_MIN > 1 hast du (vermutlich) einen Überlauf.

Franz schrieb:
> sprintf(enumNameChar, "PWM_%d%d",zehner, einer);

char * name ist ein Zeiger. Bei jedem Schleifendurchlauf überschreibst 
du "enumNameChar" und alle Elemente zeigen nunmal auf diesen String. 
Somit zeigen alle auf den selben String.
#6377875
So wie du es gemacht hast wird kein Speicherplatz für den String 
angelegt, sondern nur der Speicherplatz für den Zeiger auf einen String. 
Wenn die Struktur den Namen enthalten soll kann man sie zum Beispiel so 
definieren:
1
#define MAX_NAME_LENGTH (20) 
2
// oder was eben die maximale Länge für einen Namen sein soll 
3

4
typedef struct
5
{
6
    uint8 id;
7
    outputType_T type;
8
    char name[MAX_NAME_LENGTH];
9
} output_T;
Gast #6377879
Ben S. schrieb:
> for(uint8 number=0; number<10 number++) denn du machst hier 11
> Schleifendurchläufe! Und was ist "uint8"?

uint8 sind 255

Ben S. schrieb:
> Wenn PWM_MIN > 1 hast du (vermutlich) einen Überlauf.

PWM_MIN ist 0

Ben S. schrieb:
> char * name ist ein Zeiger. Bei jedem Schleifendurchlauf überschreibst
> du "enumNameChar" und alle Elemente zeigen nunmal auf diesen String.
> Somit zeigen alle auf den selben String.

wie kann ich den denn variable lang machen?

könnte auch char name[10] machen. das wäre der länste name und dann mit 
strncpy den namen beschreiben.
Dann würde aber hinten immer müll stehen wenn der name kürzer ist.

Dies kommt vor, da noch andere outputs hinzukommen, die aber alle im 
selben structarray kommen
#6377886
Franz schrieb:
> uint8 sind 255

Ich meinte eher, ich kenne nur uint8_t ?

Franz schrieb:
> wie kann ich den denn variable lang machen?

Du musst entweder Speicher auf dem Heap mit malloc initiieren oder in 
jedem Element char name[10]; genug eigenen Speicher bereitstellen.

Franz schrieb:
> Dann würde aber hinten immer müll stehen wenn der name kürzer ist.

Das ist korrekt. Geht aber nicht anders, wenn du keinen Heap mit malloc 
und somit dynamischen Speicher nutzen willst - wovon ich dir dringend 
abrate.
#6377890
Franz schrieb:
> Dann würde aber hinten immer müll stehen wenn der name kürzer ist.

Nö, weil Strings in C null-terminiert sind. Die Funktion sprintf() weiß 
das und handelt entsprechend. Dafür muss freilich genug Platz sein: Wenn 
man z.B. char name[10] definiert, dann kann der Name maximal 9 Zeichen 
lang sein da ein Zeichen für die Terminierung des Strings benötigt wird.
#6377906
Mark B. schrieb:
> Nö, weil Strings in C null-terminiert sind. Die Funktion sprintf() weiß
> das und handelt entsprechend. Dafür muss freilich genug Platz sein: Wenn
> man z.B. char name[10] definiert, dann kann der Name maximal 9 Zeichen
> lang sein da ein Zeichen für die Terminierung des Strings benötigt wird.

Beides wichtige Punkte, die man leider zu oft als Grundwissen annimmt.
#6378014
Mark B. schrieb:
> Nö, weil Strings in C null-terminiert sind. Die Funktion sprintf() weiß
> das und handelt entsprechend. Dafür muss freilich genug Platz sein: Wenn
> man z.B. char name[10] definiert, dann kann der Name maximal 9 Zeichen
> lang sein da ein Zeichen für die Terminierung des Strings benötigt wird.

nur wenn man sprintf oder str Funktionen nutzt.
wer weiss das der String ohne Nullterminierung ist kann den auch mit 
memcpy und der Länge ohne Null kopieren und verarbeiten!
Gast #6378091
Es ist zusätzlich bemerkenswert, dass nicht nur die Namen alle gleich 
sind, sondern der Name, den enthaltenen Ziffern nach, auch dem letzten 
Durchlauf der for-Schleife entspricht.

Du hast in der Struktur einen Zeiger als Element der Struktur.

Mit dem sprintf schreibst Du zwar immer wieder in die temporäre 
Variable, aber Du setzt .name jedesmal auf den gleichen Zeiger auf 
diese Variable. Beim lesenden Zugriff mithilfe dieser Zeiger, erhältst 
Du dann natürlich den zuletzt geschriebenen Inhalt der String-Variablen 
name.


Zur Nomenklatur: name ist ein "Mitglied" oder ein "Element" der 
Struktur.
Es gibt da durchaus mehrere Möglichkeiten. Aber "Parameter" ist 
ungünstig, weil Parameter in C mit Funktionen in Zusammenhang stehen. 
Das ist in diesem Thread zwar nicht entscheidend, aber kann zu 
ungewollten Überschneidungen  führen, falls man über Funktionen im Zshg. 
mit Strukturen nachdenkt.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 6 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.