Forum: Mikrocontroller und Digitale Elektronik Pointer Gymnastik Ist mein Code zulässig?


von C. H. (hedie)


Lesenswert?

Hallo zusammen

Ich habe folgenden Code:
1
char *copy_from_until(unsigned char from, char until_sign, char *SearchIn)
2
{
3
  char TempString[20];
4
  char *pTempString;
5
  pTempString = TempString;
6
  
7
  SearchIn += from; //Offset definieren!
8
  
9
  while( (*SearchIn != 0) && (*SearchIn != until_sign) )
10
  {
11
    *pTempString = *SearchIn;
12
    SearchIn++;
13
    pTempString++;
14
  }
15
  *pTempString = 0;
16
  return pTempString;
17
}

Ziel ist es, einen bestimmten Bereich in einem String zu kopieren.
Definiert wird dabei der Startoffset vom übergebenen String und ein 
EndZeichen!

Meine Frage bezieht sich nun auf den return Befehl.
1
  return pTempString;

Ist es zulässig, dass ich einen Pointer auf eine Funktions-lokale 
Variable zurückgebe?

Irgendwie erscheint mir dies als nicht möglich.

Falls nein, gibt es einen elegante Lösung, zur vermeidung von diversen 
globalen Variablen?


Danke schonmal!

von Rene H. (Gast)


Lesenswert?

Nein, ist es nicht. Das macht Ärger...

Übergib in C einen Doppelpointer oder in C++ eine Referenz.

Grüsse,
R.

von Kein Name (Gast)


Lesenswert?

Die strcpy() Varianten bekommen alle einen Pointer auf den 
Ausgabepuffer. Warum willst du es anders machen?

von C. H. (hedie)


Lesenswert?

Kein Name schrieb:
> Warum willst du es anders machen?

Möchte ich nicht :) Hab nur den Wald vor lauter Bäumen nicht gesehen...

Ist wohl das beste!


Danke

von Thomas Z. (tezet)


Lesenswert?

Claudio Hediger schrieb:
>
> Ist es zulässig, dass ich einen Pointer auf eine Funktions-lokale
> Variable zurückgebe?

A) Lokale Variablen existieren nach dem Funktionsaufruf nicht mehr
B) Du willst doch den Zielbuffer ausserhalb der Funktion benutzen, also 
definiere ihn doch dort und übergebe einen ZielZeiger

von C. H. (hedie)


Lesenswert?

Vielen Dank!

Funktioniert einwandfrei!

1
void copy_from_until(unsigned char from, char until_sign, char *SearchIn, char *Output)
2
{
3
  SearchIn += from; //Offset definieren!
4
  
5
  while( (*SearchIn != 0) && (*SearchIn != until_sign) )
6
  {
7
    *Output = *SearchIn;
8
    SearchIn++;
9
    Output++;
10
  }
11
  *Output = 0;  
12
}

von LOL (Gast)


Lesenswert?

Keine Ahnung, ob das nur Beispielcode war, aber ich würde mir noch 
folgende Fragen stellen:

1.)
SearchIn=blablubb
from=100

Was passiert bei:
1
  SearchIn += from; //Offset definieren!

2.)
Änderst du "from", "until_sign" und ggf. *SeachIn?
1
char *copy_from_until(unsigned char from, char until_sign, char *SearchIn)

Wenn nicht, sollten die vermutlich const sein.

von Cube_S (Gast)


Lesenswert?

pTempString zeigt auf TempString, sprich einer lokalen Variablen auf dem 
Stack der nach Aufruf der Funktion nicht mehr gültig ist. Also wie Du 
schon vermutet hast nicht zulässig.

Der Witz daran: Es hat gute Chancen in der aufrufenden Funktion u.U. zu 
funktionieren, da der Stack sehr wahrscheinlich noch nicht überschrieben 
wurde. Kann also sein, dass der Fehler erst mal nicht auffällt.

TempString kann maximal 20 Zeichen fassen, SearchIn hat vielleicht mehr. 
Das könnte den Stack ruinieren und ein Angriffsziel darstellen bzw einen 
Absturz verursachen.

von chris (Gast)


Lesenswert?

Es geht, du musst aber deinen Stringbuffer als static declarieren.
Weiters hast du einen Denkfehler, du lieferst den Pointer auf das 
Stringende zurück.
Normalerweise macht man dies so:

foo(char*str,char c, int offset) {
static char buff[500]; // als beispiel
int i=0;
   if(str&&offset<strlen(str))
   for(str+=offset;*str&&*str!=c&&i<sizeof(buff)/sizeof(buff[0]);)
      buff[i++]=*str++;
   buff[i]='\0';
   return buff;
}

von C. H. (hedie)


Lesenswert?

Cube_S schrieb:
> TempString kann maximal 20 Zeichen fassen, SearchIn hat vielleicht mehr.
> Das könnte den Stack ruinieren und ein Angriffsziel darstellen bzw einen
> Absturz verursachen.

Vielen Dank für diesen Hinweis :)

LOL schrieb:
> 1.)
> SearchIn=blablubb
> from=100
>
> Was passiert bei:  SearchIn += from; //Offset definieren!

Dann stürzt das Teil ab!
Soll ich also noch "> strlen(SearchIn)" machen?

LOL schrieb:
> 2.)
> Änderst du "from", "until_sign" und ggf. *SeachIn?char
> *copy_from_until(unsigned char from, char until_sign, char *SearchIn)
>
> Wenn nicht, sollten die vermutlich const sein.

Vielen Dank für diesen Hinweis!

Dazu muss ich gestehen, dass ich mir noch nicht ganz im klaren bin, wann 
man const macht und wann nicht. Und was es für vorteile hat.

Bezieht sich dein "änderst du nochmals" lediglich auf die Funktion?
Also ob ich from und until innerhalb der funktion ändere?
Wenn dies die Frage war, dann nein.

von c-hater (Gast)


Lesenswert?

Claudio Hediger schrieb:

> Ist es zulässig, dass ich einen Pointer auf eine Funktions-lokale
> Variable zurückgebe?

Zulässig ist es.

> Irgendwie erscheint mir dies als nicht möglich.

Möglich ist es, da es zulässig ist. Sinnvoll ist es nicht. Das ist halt 
C, wie es leibt und lebt.

> Falls nein, gibt es einen elegante Lösung, zur vermeidung von diversen
> globalen Variablen?

Ja. Der Caller übergibt eine Referenz auf einen ihm gehörenden 
Speicherbereich, in dem der Callee die Auschnittskopie zurückgibt. 
Natürlich nur dann, wenn der Platz dort dafür reicht. Außer der 
Speicherreferenz muß also auch die Größe des referenzierten 
Speicherbereichs übergeben werden und der Callee muß verschiedene 
Situationen zurückmelden können, als da wären:

Fehler:
Nullreferenz Quelle
Nullreferenz Ziel
Ungenügender Speicher im Ziel (komfortabler: soundsoviel Zeichen 
benötigt)

Gut.
oder:
Besser: soundsoviel Zeichen im Ziel

Programmierst du den ersten Tag in dieser Drecks-Sprache?

von chris (Gast)


Lesenswert?

Und i<sizeof(buff)/sizeof(buff[0]) sollte
 1+i<sizeof(buff)/sizeof(buff[0])  sein, ich mache dies meistens mit 
Konstanten arbeite, z.B. LINE_LEN und dann bei der Deklaration einfach
buff[LINE_LEN+1] ,

von LOL (Gast)


Lesenswert?

> Dann stürzt das Teil ab!
> Soll ich also noch "> strlen(SearchIn)" machen?

Oder halt einfach und ineffizient den *char komplett in der Schleife 
zeichenweise durchgehen und abbrechen wenn \0 kommt.

Wenn du mehr Durchläufe als "from" hast, fängst du an zu verlgeichen, 
wenn du mehr als from+20 Durchläufe hast, brichst du ab (-> Cube_S).

Die Sache mit dem "const" im Funktionskopf ist eher "hübsch", damit wird 
jedem der die Funktion sieht klar, dass du diese Variablen nicht 
änderst, im Gegensatz halt zu den Rückgabevariablen/Pointern/Referenzen 
wie auch immer man das gerade nennen mag.

von Cube_S (Gast)


Lesenswert?

Claudio Hediger schrieb:
> Dazu muss ich gestehen, dass ich mir noch nicht ganz im klaren bin, wann
> man const macht und wann nicht. Und was es für vorteile hat.

Das wäre an dieser Stelle rein akademischer Natur. Die übergebenen Werte 
sind "call by value" und werden in der aufrufenden Funktion nicht 
verändert. Sie sind defakto lokale Variablen und ein "const" wäre nur 
die Absichtserklärung sie nicht zu ändern. Neuere Sprachen verzichten 
auf das "const"

von C. H. (hedie)


Lesenswert?

Cube_S schrieb:
> Claudio Hediger schrieb:
>> Dazu muss ich gestehen, dass ich mir noch nicht ganz im klaren bin, wann
>> man const macht und wann nicht. Und was es für vorteile hat.
>
> Das wäre an dieser Stelle rein akademischer Natur. Die übergebenen Werte
> sind "call by value" und werden in der aufrufenden Funktion nicht
> verändert. Sie sind defakto lokale Variablen und ein "const" wäre nur
> die Absichtserklärung sie nicht zu ändern. Neuere Sprachen verzichten
> auf das "const"

Achsoo...

Na dann habe ich ja bisher nichts verpasst :)

Danke für die Erklärung!

von LOL (Gast)


Lesenswert?

Nur der Vollständigkeit halber - hier schrieb ich offensichtlichen 
Blödsinn:

> wenn du mehr als from+20 Durchläufe hast

Das sollten 20 gültige weitere Durchläufe nach dem Startzeichen/Offset 
sein, wegen der Pufferlänge.

von C. H. (hedie)


Lesenswert?

LOL schrieb:
> Nur der Vollständigkeit halber - hier schrieb ich offensichtlichen
> Blödsinn:
>
>> wenn du mehr als from+20 Durchläufe hast
>
> Das sollten 20 gültige weitere Durchläufe nach dem Startzeichen/Offset
> sein, wegen der Pufferlänge.

Achsoo

Ok jetzt ergibt es mehr sinn :)

von Cube_S (Gast)


Lesenswert?

Hedie scherzt ein wenig mit uns.

von ah8 (Gast)


Lesenswert?

Cube_S schrieb:

> Das wäre an dieser Stelle rein akademischer Natur. Die übergebenen Werte
> sind "call by value" und werden in der aufrufenden Funktion nicht
> verändert. Sie sind defakto lokale Variablen und ein "const" wäre nur
> die Absichtserklärung sie nicht zu ändern. Neuere Sprachen verzichten
> auf das "const"

Das ist nicht richtig, zumindest nicht solange wir nicht wissen, wie die 
consts gesetzt werden. Es gibt ein Unterschied zwischen
1
char *const    // konstanter Pointer auf char
2
char const*    // Pointer auf konstanten char
3
char const*const  // konstanter Pointer auf konstanten  char

Ein char const* macht auch bei call by value durchaus Sinn, da es 
verhindert, dass ein durch den Pointer referenziertes Objekt verändert 
wird. Allerdings bin ich mir nicht sicher, ab welchem C-Standard diese 
Qualifier für den Compiler bindend sind. Bei ANSI-C heißt es noch:

„Except that it should diagnose explicit attempts to change a const 
object, the compiler may ignore these qualifiers.“

Der Compiler sollte also warnen, muss es aber nicht. Spätestens bei C++ 
allerdings sind dies Qualifier binden.

von Cube_S (Gast)


Lesenswert?

ah8 schrieb:
> Spätestens bei C++
> allerdings sind dies Qualifier binden.

Alles in allem hast Du natürlich recht. Aber ich habe bei größeren 
Projekten nicht erlebt, dass sich das "const" konsequent durchsetzen 
lässt. Gerade bei C++ Klassen mit const Zeigern darauf. Man kommt immer 
an einen Punkt wo das Objekt der Begierde zwar im Prinzip "const" sein 
soll aber man doch irgend etwas unbedeutendes darin ändern will. Damit 
tritt man oft eine nicht aufzuhaltende Lawine los.

C# und Java verzichten darauf. Ich denke nicht ganz zu unrecht.

von Karl H. (kbuchegg)


Lesenswert?

Cube_S schrieb:
> ah8 schrieb:
>> Spätestens bei C++
>> allerdings sind dies Qualifier binden.
>
> Alles in allem hast Du natürlich recht. Aber ich habe bei größeren
> Projekten nicht erlebt, dass sich das "const" konsequent durchsetzen
> lässt. Gerade bei C++ Klassen mit const Zeigern darauf. Man kommt immer
> an einen Punkt wo das Objekt der Begierde zwar im Prinzip "const" sein
> soll aber man doch irgend etwas unbedeutendes darin ändern will.

Dann machst du den Member 'mutable'

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.