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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Franz (Gast)


Bewertung
0 lesenswert
nicht lesenswert
hallo,
ich habe einen struct
typedef struct
{
    uint8 id;
    outputType_T type;
    char* name;
} output_T;

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
for(uint8 number=0; number<=10 number++)
{
  zehner = ((number-PWM_MIN)+1) / 10;
  einer = ((number-PWM_MIN)+1) % 10;
  sprintf(enumNameChar, "PWM_%d%d",zehner, einer);

    output[number].id = number;
    output[number].type = OUTPUT_PWM;
    output[number].name = enumNameChar;
}

Also am schluss haben alle den Namen vom letzten bekommen. Was mache ich 
hier falsch?

von Ben S. (bensch123)


Bewertung
1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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:
#define MAX_NAME_LENGTH (20) 
// oder was eben die maximale Länge für einen Namen sein soll 

typedef struct
{
    uint8 id;
    outputType_T type;
    char name[MAX_NAME_LENGTH];
} output_T;

: Bearbeitet durch User
von Franz (Gast)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
1 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.