mikrocontroller.net

Forum: Compiler & IDEs String zurückgeben


Autor: Bart (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich versuche gerade eine funktion zu schreiben die einen String 
zurückgibt, klappt leider nicht.
char *uart_gets()
{
  char string[20];
  char c;
  int i=1;
  c = uart_getc();
  if(!(c & UART_NO_DATA))
  {
  string[0] = c;
  do {
    c = uart_getc();
    string[i] = c;
    i++;
    }while(c != '\0');
  //uart_puts(string);
  return string;
  }
}
Geht das irgendwie ohne String als Zeiger zu deklarieren?
Gruß
Bart

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bart schrieb:
> Hallo,
> ich versuche gerade eine funktion zu schreiben die einen String
> zurückgibt, klappt leider nicht.
>
char *uart_gets()
> {
>   char string[20];
>   char c;
>   int i=1;
>   c = uart_getc();
>   if(!(c & UART_NO_DATA))
>   {
>   string[0] = c;
>   do {
>     c = uart_getc();
>     string[i] = c;
>     i++;
>     }while(c != '\0');
>   //uart_puts(string);
>   return string;
>   }
> }
> Geht das irgendwie ohne String als Zeiger zu deklarieren?

Nein.
Dein Problem:
Du gibst die Adresse einer lokalen Variable zurück.
In C ist das ein absolutes NoNo.
Die Variable existiert nicht mehr, nachdem die Funktion verlassen wurde. 
Der Aufrufer hat daher die Adresse einer Variablen, die es nicht mehr 
gibt.

Abhilfe:
Gib in die Funktion die Adresse des char Arrays hinein, in die die 
Funktion schreiben darf.

Autor: Stephan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Morgen
char string[20];

ist nur bis zum ende der Funktion gültig und nach dem verlassen weg!
man macht so was anders:

1) man arbeitet über einen globalen Puffer <- hier glaub ich besser
2) man übergibt der Funktion einen Pointer auf den Puffer wo die Werte 
rein geschrieben werden

mfg
Stephan

Autor: ... ... (docean) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
überlegen wir doch mal...

du legst am Anfang der Fkt. deinen String an (entspricht einem 
Speicherbereich) und arbeitest damit.

Am Ende der Fkt. wird dieser Speicher wieder freigegeben, weil denn dann 
ja rein theoretisch keiner mehr brauch...

Daher kann dein Ansatz nicht funktionieren...

Du könntest den String global machen oder eine Zeiger auf einen String 
übergeben und dann dann wieder zurückgeben

Ach ja:
>Geht das irgendwie ohne String als Zeiger zu deklarieren?
Das machst du da oben schon ohne Ende...[]= zeiger in C

Autor: Bart (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke euch, mir fehlt irgendwie echt die Disziplin für C ;)
void uart_gets(char *test)
{
  char string[20];
  char c;
  int i=1;
  c = uart_getc();
  if(!(c & UART_NO_DATA))
  {
  *test = c;
  do {
    test++;
    *test = uart_getc();
    }while(*test != '\0');
  }
}
 So läufts falls es jemandem weiterhilft.

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und ist ein potentieller Buffer-Overflow, weil du keine Puffergroesse 
uebergibst und pruefst...

Autor: Marcus Kunze (marcusk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und wozu brauchst du jetzt noch

 char string[20];
 int i=1;

oder willst du dem optimierer auch etwas übrig lassen

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bart schrieb:
> Danke euch, mir fehlt irgendwie echt die Disziplin für C ;)
>
void uart_gets(char *test)
> {
>   char string[20];
>   char c;
>   int i=1;
>   c = uart_getc();
>   if(!(c & UART_NO_DATA))
>   {
>   *test = c;
>   do {
>     test++;
>     *test = uart_getc();
>     }while(*test != '\0');
>   }
> }
> 
 So läufts falls es jemandem weiterhilft.

Ähm. schau dir bitte die Funktion noch einmal genau an.
Vor allem der 2.te Aufruf der uart_getc() bzw. die Auswertung dessen was 
er retourniert ist nicht koscher. Stell dir einfach vor, du hast einen 
Schweizer, der etwas langsamer tippt, am anderen Ende der Leitung.
Auch die Steuerung der do-while Schleife ist ... gelinde gesagt: Mist. 
Was muss denn ein Benutzer drücken, damit die uart_gets das als 
Stringende interpretiert?

Und wie kriegt ein Benutzer eigentlich einen leeren String an deine 
Funktion durch?

Wozu benötigt deine Funktion die lokalen Variablen string und i?

Und weißt du, was an der C-Standardfunktion gets() schlecht designed 
ist? So schlecht, dass diese Funktion nicht benutzt werden sollte, 
sondern statt dessen immer fgets() benutzt werden muss?

Autor: Bart (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh, harsche Kritik...
void uart_gets(char *test)
{
  char c;
  c = uart_getc();
  if(!(c & UART_NO_DATA))
  {
  *test = c;
  do {
    test++;
    *test = uart_getc();
    }while(*test != '\0');
  }
}
Die Kritik mit dem Bufferoverflow verstehe ich ja noch, aber was ist an 
der Schleife so schlecht? \0 ist das End of Stringzeichen, und damit 
werden die gesendeten Strings immer abgeschlossen. Leere Strings werden 
nicht gesendet, das wird auf PC-Seite so gemanaged.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bart schrieb:

> der Schleife so schlecht? \0 ist das End of Stringzeichen, und damit
> werden die gesendeten Strings immer abgeschlossen.

Dann musst du dazu sagen, WER denn die Strings sendet!
Ist die Funktion so universell geschrieben, dass das egal ist, dann 
braucht man nichts dazusagen. Aber wenn eine Funktion nur in bestimmten 
Sonderfällen funktioniert, dann sollte man das auch dazusagen.

  do {
    test++;
    *test = uart_getc();
    }while(*test != '\0');

Das wird bei langsamen Baudraten wahrscheinlich immer noch die 
uart_getc() outperformen und entweder ein vorzeitiges Stringende 
anzeigen oder aber den zuletzt empfangenen Character entsprechend oft 
duplizieren oder den String mit UART_NO_DATA fluten.
Je nachdem wie uart_getc den Fall behandelt: Ich hab noch nichts weiter 
gekriegt. Dass es den Fall behandelt sieht man ein paar Zeilen darüber. 
Da liefert die Funktion einen Fehler UART_NO_DATA

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
BTW:
Kann es sein, dass wir hier über die Fleury Lib und deren uart_getc 
reden?
Wenn ja, dann hat c den falschen Datentyp :-)

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst die lokle string Variable auch als static deklarieren, dann 
wird die Variable nicht temporär auf dem Stack abgelegt sondern bleibt 
am "leben" auch wenn die Funktion verlassen wird...
char *uart_gets()
{
  static char string[20];   //nicht auf dem Stack...
  char c;
  int i=1;
  c = uart_getc();
  if(!(c & UART_NO_DATA))
  {
  string[0] = c;
  do {
    c = uart_getc();
    string[i] = c;
    i++;
    }while(c != '\0');
  //uart_puts(string);
  return string;
  }
}

Autor: Marcus Kunze (marcusk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter (Gast)
string wird schon lange nicht mehr gebraucht, es gibt schon lange ein 
neue version des code abschnittes

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:

> Du kannst die lokle string Variable auch als static deklarieren,

Womit die Funktion nicht mehr reentrant ist. Das mag auf einem 
Mikrocontroller meist keine Rolle spielen, auf grossen Systemen geht's 
spaetestens mit Threads uebel schief.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
> Du kannst die lokle string Variable auch als static deklarieren, dann
> wird die Variable nicht temporär auf dem Stack abgelegt sondern bleibt
> am "leben" auch wenn die Funktion verlassen wird...

Aber Vorsicht mit dieser Technik. Sowas geht ganz schnell ins Auge:
   char* FirstString;
   char* SecndString;

   FirstString = uart_gets();
   SecndString = uart_gets();

Und dann such mal schön, warum FirstString immer identisch ist zu 
SecndString :-)

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im uebrigen verbraucht man da ganz schnell viel wertvollen Speicher ohne 
es zu merken, der auf vielen Controllern ja nicht gerade reichlich ist.

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.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

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