Forum: Mikrocontroller und Digitale Elektronik Rückgabewert


von Kristina (Gast)


Lesenswert?

Hallo,
hab schon lange nichts mehr mit C gemacht und stoße jetzt auf das
Problem mir einen Rückgabewert richtig zurückgeben zu lassen. Hier das
Beispiel:

--------------------------------------------------------------
/* prototype */
unsigned char func1(void);

/* Func1 */
unsigned char func1(void){
  unsigned char xyz[10];
  strcpy(xyz,'test1\0');
  return xyz;
}

/* main */
int main(void)
{
  unsigned char abc[10];

  abc = func1();

  lcd_init(LCD_DISP_ON_CURSOR_BLINK);
  lcd_puts(abc);
}
--------------------------------------------------------------

Wie gebe ich den Wert in xyz richtig zurück ? Über Pointer ?

Bitte die Antwort so ausführlich wie möglich, damit ich den Sachverhalt
einmal für immer verstehe.

Gruß

von Rufus T. Firefly (Gast)


Lesenswert?

unsigned char func1(void){
  unsigned char xyz[10];
  strcpy(xyz,'test1\0');
  return xyz;
}

Hier treten mehrere Probleme auf:

a) Stringkonstanten sind in Anführungszeichen (") einzuschließen,
nicht in Hochkommata ('), die sind für Zeichenkonstanten da.

b) Der Rückgabewert soll ein char sein, zurückgegeben wird aber ein
char*.

c) Die Variable xyz ist eine automatische Variable, die auf dem Stack
angelegt wird.
Der zurückgegebene Pointer verweist somit auf Speicher, der nach dem
Beenden der Funktion nicht mehr gültig ist.

Damit ein Pointer auf diese Variable zurückgegeben werden kann, muss
entweder die Variable als static deklariert werden - damit ist sie
nicht mehr automatisch, sondern einmalig im .Text-Segment angelegt.

Das ist sehr ungeschickt, weil bei aufeinanderfolgenden Aufrufen der
Funktion die Variable jeweils überschrieben wird.

Eine Alternative wäre es, die Variable dynamisch via malloc
anzufordern, dann muss aber der Aufrufer der Funktion nach Gebrauch des
Ergebnisses dafür sorgen, daß der Speicher mit free zurückgegeben wird.
Das wird gerne vergessen und ist auch aus anderen Gründen eine
potentielle Fehlerquelle.

Hier ist eine völlig andere Vorgehensweise sinnvoller:


/* Func1 */
void func1(char* pString){
  strcpy(pString, "test1");
}

/* main */
int main(void)
{
  unsigned char abc[10];

  func1(abc);

  lcd_init(LCD_DISP_ON_CURSOR_BLINK);
  lcd_puts(abc);
}

Der Funktion wird ein Pointer auf den zu beschreibenden Speicher
übergeben, der Speicher wird in main von der Variablen abc zur
Verfügung gestellt.
Die terminierende Null in der Stringkonstante wird von strcpy eh'
hinzugefügt und muss daher nicht explizit geschrieben werden, außderdem
wird sie auch implizit zur Stringskontanten selbst hinzugefügt.

Hier gibt es noch einige potentielle Fehlerquellen:

func1 überprüft nicht das übergebene Argument auf Gültigkeit. Wird NULL
beim Aufruf übergeben, interessieren spannende Dinge.

Desweiteren weiß func1 nicht, wie groß der Speicherbereich ist, auf den
der übergebene Pointer verweist. Wird in main die Größe von abc auf
weniger als 6 Zeichen (Länge von "test1" plus terminierende Null)
reduziert, überschreibt der strcpy-Aufruf in func nicht reservierten
Speicher.

Daher ist es sinnvoll, der Funktion func1 die Länge des Stringpuffers
zu übergeben und diese auch auszuwerten:




/* Func1 */
void func1(char* pString, int Laenge){
  strncpy(pString, Laenge, "test1");
}

/* main */
int main(void)
{
  unsigned char abc[10];

  func1(abc, 10);

  lcd_init(LCD_DISP_ON_CURSOR_BLINK);
  lcd_puts(abc);
}


Uuuund jetzt folgt mein beliebter Hinweis, auf den hier vermutlich
schon alle anderen gierigst gewartet haben:

Mehr zum Thema kann man im Buch "Programmieren in C" von Kernighan &
Ritchie, zweite Auflage, Hanser Verlag nachlesen.

von Kristina (Gast)


Lesenswert?

Danke, hab's auch nachgelesen ;)

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.