Forum: Compiler & IDEs String zurückgeben


von Bart (Gast)


Lesenswert?

Hallo,
ich versuche gerade eine funktion zu schreiben die einen String 
zurückgibt, klappt leider nicht.
1
char *uart_gets()
2
{
3
  char string[20];
4
  char c;
5
  int i=1;
6
  c = uart_getc();
7
  if(!(c & UART_NO_DATA))
8
  {
9
  string[0] = c;
10
  do {
11
    c = uart_getc();
12
    string[i] = c;
13
    i++;
14
    }while(c != '\0');
15
  //uart_puts(string);
16
  return string;
17
  }
18
}
Geht das irgendwie ohne String als Zeiger zu deklarieren?
Gruß
Bart

von Karl H. (kbuchegg)


Lesenswert?

Bart schrieb:
> Hallo,
> ich versuche gerade eine funktion zu schreiben die einen String
> zurückgibt, klappt leider nicht.
>
1
char *uart_gets()
2
> {
3
>   char string[20];
4
>   char c;
5
>   int i=1;
6
>   c = uart_getc();
7
>   if(!(c & UART_NO_DATA))
8
>   {
9
>   string[0] = c;
10
>   do {
11
>     c = uart_getc();
12
>     string[i] = c;
13
>     i++;
14
>     }while(c != '\0');
15
>   //uart_puts(string);
16
>   return string;
17
>   }
18
> }
> 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.

von Stephan (Gast)


Lesenswert?

Morgen
1
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

von ... .. (docean) Benutzerseite


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

von Bart (Gast)


Lesenswert?

Danke euch, mir fehlt irgendwie echt die Disziplin für C ;)
1
void uart_gets(char *test)
2
{
3
  char string[20];
4
  char c;
5
  int i=1;
6
  c = uart_getc();
7
  if(!(c & UART_NO_DATA))
8
  {
9
  *test = c;
10
  do {
11
    test++;
12
    *test = uart_getc();
13
    }while(*test != '\0');
14
  }
15
}
 So läufts falls es jemandem weiterhilft.

von P. S. (Gast)


Lesenswert?

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

von Marcus K. (marcusk)


Lesenswert?

und wozu brauchst du jetzt noch

 char string[20];
 int i=1;

oder willst du dem optimierer auch etwas übrig lassen

von Karl H. (kbuchegg)


Lesenswert?

Bart schrieb:
> Danke euch, mir fehlt irgendwie echt die Disziplin für C ;)
>
1
void uart_gets(char *test)
2
> {
3
>   char string[20];
4
>   char c;
5
>   int i=1;
6
>   c = uart_getc();
7
>   if(!(c & UART_NO_DATA))
8
>   {
9
>   *test = c;
10
>   do {
11
>     test++;
12
>     *test = uart_getc();
13
>     }while(*test != '\0');
14
>   }
15
> }
16
>
 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?

von Bart (Gast)


Lesenswert?

Oh, harsche Kritik...
1
void uart_gets(char *test)
2
{
3
  char c;
4
  c = uart_getc();
5
  if(!(c & UART_NO_DATA))
6
  {
7
  *test = c;
8
  do {
9
    test++;
10
    *test = uart_getc();
11
    }while(*test != '\0');
12
  }
13
}
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.

von Karl H. (kbuchegg)


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.

1
  do {
2
    test++;
3
    *test = uart_getc();
4
    }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

von Karl H. (kbuchegg)


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 :-)

von Peter (Gast)


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...
1
char *uart_gets()
2
{
3
  static char string[20];   //nicht auf dem Stack...
4
  char c;
5
  int i=1;
6
  c = uart_getc();
7
  if(!(c & UART_NO_DATA))
8
  {
9
  string[0] = c;
10
  do {
11
    c = uart_getc();
12
    string[i] = c;
13
    i++;
14
    }while(c != '\0');
15
  //uart_puts(string);
16
  return string;
17
  }
18
}

von Marcus K. (marcusk)


Lesenswert?

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

von P. S. (Gast)


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.

von Karl H. (kbuchegg)


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:
1
   char* FirstString;
2
   char* SecndString;
3
4
   FirstString = uart_gets();
5
   SecndString = uart_gets();

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

von P. S. (Gast)


Lesenswert?

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

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.