Funktion in ansi c

Hallo Leute,
ich schlage mich mal wieder mit Zeigern rum und mein C-Unterricht ist immenroch in weiter ferne.
Ich will mir eine Funktion schreiben, der ich ein Array von Zeichen (konkret eine Zeile aus einer Datei) übergebe und die mir dann das LF abschneidet und mir dann die Zeichenkette ohne LF zurückgibt, der Compiler (cc) meckert nicht aber das Teil gibt mir nix zurück:

char cstring(char* source)
{
char target[255]; //zielvariable,die ich zurückgeben will
for (int pos=0;pos

Hallo Alex,

Ist ein typischer Anfängerfehler :wink:

was mach ich falsch … ich denke mal ich mache irgendeinen
Fehler mit den Zeigern?

JAIN.

Also.
Wenn cstring() aufgerufen wird, wird als erstes der Wert von „* source“ auf dem Stack abgelegt, dann die Rücksprungadresse und nach cstring() verzweigt.
Der Code von cstring() sichert dann mal die benötigten CPU-Register auf dem Stack und schaft auf dem Stack auch den nötigen Speicherplatz für „target[255]“.

„return *target;“ bewirkt nun, dass die Speicheradresse von target in das Rückgabe-register übertragen wird. Danach werden die geretteten Register wieder vom Stack genommen und der STack wieder in den Zustand versetzt wie er beim Aufruf von cstring() war …
HALT !!!
„target[255]“ war doch auf dem Stack ???
Du gibst also einen Zeiger zurück, welcher auf einen Speicherbereich zeigt, welcher nun wieder zur weiteren Verwendung freigegeben wurde !!!
Wenn du also nach dem Rücksprung mit dem Zeiger zugreiffst, kann da alles mögliche stehen, nur nicht mehr diejenigen Zeichen, welche du mal dahin kopiert hast.

Abhilfe wäre „char target[255];“
als
" static char target[255];" zu deklarieren, dann wird der Speicher nicht auf dem Stack reserviert, sondern im normalen Variablen-Bereich.

Allerdings hat das, den Nachteil, dass bei zwei aufeinanderfolgenden Aufrufen von cstring() jedesmal der Inhalt von „target“ verändert wird.

Ein weiteres Problem deiner Funktion ist noch, dass dein Programm aufs übelste Abstürzen kann, wenn strlen(source) grösser als 255 ist. Das ist dann so ein Bug, den man manchmal lange suchen kann !!!Besonders weil er nicht unbedingt reproduzierbar ist, weil es nur dann knallt, wenn zum richtigen Zeitpunkt ein Interrupt im System auftritt.

Pracktisch sollte man cstring() anders schreiben:
char cstring(char*target, char* source, int maxlen);

die Zeile:
char target[255]; //zielvariable,die ich zurückgeben will
entfällt dann !!
Mit „maxlen“, kannst du dann sicherstellen, dass du keine Bufferoverruns erzeugst.

MfG Peter(TOO)

> char cstring(char\* source)  
> {  
> char target[255]; //zielvariable,die ich zurückgeben will  
> for (int pos=0;pos

Hallo Alex,

Ist ein typischer Anfängerfehler :wink:

Ja ich weiss, aber ich drehe mich im Kreis, vorallem,weil ich das schonmal konnte.

was mach ich falsch … ich denke mal ich mache irgendeinen
Fehler mit den Zeigern?

JAIN.

Also.
Wenn cstring() aufgerufen wird, wird als erstes der Wert von
„* source“ auf dem Stack abgelegt, dann die Rücksprungadresse
und nach cstring() verzweigt.
Der Code von cstring() sichert dann mal die benötigten
CPU-Register auf dem Stack und schaft auf dem Stack auch den
nötigen Speicherplatz für „target[255]“.

„return *target;“ bewirkt nun, dass die Speicheradresse von
target in das Rückgabe-register übertragen wird. Danach werden
die geretteten Register wieder vom Stack genommen und der
STack wieder in den Zustand versetzt wie er beim Aufruf von
cstring() war …
HALT !!!
„target[255]“ war doch auf dem Stack ???
Du gibst also einen Zeiger zurück, welcher auf einen
Speicherbereich zeigt, welcher nun wieder zur weiteren
Verwendung freigegeben wurde !!!

Ja was gebe ich dann zurück?

Wenn du also nach dem Rücksprung mit dem Zeiger zugreiffst,
kann da alles mögliche stehen, nur nicht mehr diejenigen
Zeichen, welche du mal dahin kopiert hast.

Abhilfe wäre „char target[255];“
als
" static char target[255];" zu deklarieren, dann wird
der Speicher nicht auf dem Stack reserviert, sondern im
normalen Variablen-Bereich.

Allerdings hat das, den Nachteil, dass bei zwei
aufeinanderfolgenden Aufrufen von cstring() jedesmal der
Inhalt von „target“ verändert wird.

Was wäre dann komfortabler zu lösen, ich muss ja mit zeigern Arbeiten, das static char cstring… , funktioniert auch nicht.

Ein weiteres Problem deiner Funktion ist noch, dass dein
Programm aufs übelste Abstürzen kann, wenn strlen(source)
grösser als 255 ist. Das ist dann so ein Bug, den man manchmal
lange suchen kann !!!Besonders weil er nicht unbedingt
reproduzierbar ist, weil es nur dann knallt, wenn zum
richtigen Zeitpunkt ein Interrupt im System auftritt.

Pracktisch sollte man cstring() anders schreiben:
char cstring(char*target, char* source, int maxlen);

erwartet er jetz nicht source als übergabeparameter?

die Zeile:
char target[255]; //zielvariable,die ich zurückgeben will
entfällt dann !!
Mit „maxlen“, kannst du dann sicherstellen, dass du keine
Bufferoverruns erzeugst.

also prüfe ich mit maxlen, die Länge der Variablen?

MfG Peter(TOO)

THX!!!

char cstring(char* source)
{
char target[255]; //zielvariable,die ich zurückgeben will
for (int pos=0;pos

Hallo Alex,

Ist ein typischer Anfängerfehler :wink:

Ja ich weiss, aber ich drehe mich im Kreis, vorallem,weil ich
das schonmal konnte.

Glück gehabt beim letzten mal *SCNR*

„target[255]“ war doch auf dem Stack ???
Du gibst also einen Zeiger zurück, welcher auf einen
Speicherbereich zeigt, welcher nun wieder zur weiteren
Verwendung freigegeben wurde !!!

Ja was gebe ich dann zurück?

Einen Zeiger der dahin zeigt wo die Daten einmal abgelegt waren.
Ob die noch dort sind, wenn du darauf zugreiffen willst, wissen nur die Götter.

Was wäre dann komfortabler zu lösen, ich muss ja mit zeigern
Arbeiten, das static char cstring… , funktioniert auch
nicht.

Ich habe da noch eine Kleinigkeit übersehen.
Bei:
return *target; //ergebnis zurück
muss der * weg, damit du die Adresse übergibst
also
return target; //ergebnis zurück

Dafür fehlt er bei der Deklaration der Funktion:
char cstring(char* source)
muss
char *cstring(char* source)
lauten.

Pracktisch sollte man cstring() anders schreiben:
char cstring(char*target, char* source, int maxlen);

erwartet er jetz nicht source als übergabeparameter?

Du musst ihm den Speicherplatz für target und source übergeben, damit es funktioniert !!

Mit „maxlen“, kannst du dann sicherstellen, dass du keine
Bufferoverruns erzeugst.

also prüfe ich mit maxlen, die Länge der Variablen?

Jain, du kannst damit sicherstellen, dass du nicht ausserhalb des reservierten Speicherplatzes schreibst, den dort befinden sich ja andere Variablen, welche du dann versehentlich überschreibst. Das tolle ist, dass sich diese Fehler dann an einer ganz anderen Stelle in deinem Programm zeigen … und wenn du etwas am Programm änderst legt der Compiler die Variablen anders ab und der Fehler ist plötzlich ganz wo anders im Programm, DANN drehst du dich im Kreis :wink:)

MfG Peter(TOO)