Forum: PC-Programmierung char parameter in einem struct array ändert sich


von Franz (Gast)


Lesenswert?

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?

von Ben S. (bensch123)


Lesenswert?

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.

: Bearbeitet durch User
von Mark B. (markbrandis)


Lesenswert?

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;

: Bearbeitet durch User
von Franz (Gast)


Lesenswert?

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

von Ben S. (bensch123)


Lesenswert?

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.

: Bearbeitet durch User
von Mark B. (markbrandis)


Lesenswert?

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.

von Ben S. (bensch123)


Lesenswert?

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.

von Joachim B. (jar)


Lesenswert?

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!

von Theor (Gast)


Lesenswert?

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.

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.