Moin Moin,
da ich nun einige Grundlagen soweit gefressen habe -.- hänge ich gerade
bei dem Problem, das ich in dem folgende code irgendwo ein Speicherleak
auftut. :(
Hier erst mal der code!
1
char*ctb(unsignedshortusocfe)// *usocfe = Zeiger "unsigned short of cfe"
2
{
3
char*bin=malloc(sizeof(char)*(9+1));
4
char*temp=malloc(sizeof(char)*(9+1));
5
inta;
6
for(a=7;a>=0;--a)
7
{
8
switch(usocfe%2)
9
{
10
case0:usocfe=usocfe/2;
11
strcpy(temp,"0");
12
break;
13
case1:usocfe=usocfe/2;
14
strcpy(temp,"1");
15
break;
16
}
17
strcat(bin,temp);
18
}
19
free(temp);
20
return(bin);
21
}
ich vermude ein Speicherleak in dieser function. wie ich darauf komme???
> ==8111== Conditional jump or move depends on uninitialised value(s)> ==8111== at 0x4C2836A: strcat (mc_replace_strmem.c:176)> ==8111== by 0x4006F5: ctb (in> home/maik81ftl/Programming/viaC/Test2/Laufende-Programme/Test1/Wandela)> ==8111== by 0x40075B: main (in> /home/maik81ftl/Programming/viaC/Test2/Laufende-Programme/Test1/Wandela)> ==8111==
1
//char *main(const char *cfe) //*cfe = Zeiger "char from extern"
DEBUG: ERROR: main.c: free(_cfe): Es wurde versucht Speicher an Adresse 0x00405BBa freizugeben welcher nicht mittels malloc() oder realloc() angefordert wurde.
Maik Geßner schrieb:> char *_cfe = "AB";Maik Geßner schrieb:> free(_cfe);
du free-st eine stackvariable
Maik Geßner schrieb:> char *ctb(unsigned short usocfe) // *usocfe = Zeiger "unsigned short of cfe"> {> char *bin = malloc(sizeof(char)* (9+1));> return(bin);> }Maik Geßner schrieb:> printf("Wert?! %s \n\n", ctb((unsigned short) _cfe[a]));
du allozierst in einer Funktion, speicher, den du rausgibst, der aber
außerhalb weder gespeichert, noch freigegeben wird
Maik Geßner schrieb:> char *temp = malloc(sizeof(char)* (9+1));
was soll eigentlich der Quatsch?
warum nicht einfach
char temp[(9+1)];
Maik Geßner schrieb:> char *ctb(unsigned short usocfe) // *usocfe = Zeiger "unsigned short of cfe"
was der Kommentar bedeuten soll, weiß wahrscheinlich auch keiner.
Der Rest der funktion ist auch kompletter schrott.
Beschäftige dich bitte nochmal mit C-Strings, char und
Stringoperationen.
Peter II schrieb:> char bin[9+1];
das bin darf nicht lokal definert werden, das wird ja zurückgegeben.
Normalerweise macht man sowas aber trotzdem nicht, sondern übergibt der
Funktion einen Puffer, der beschrieben werden kann.
Normalerweise gilt die Regel: Es gibt der den speicher Frei, der ihn
auch alloziert hat.
Hab ich den Kot eigentlich richtig interpretiert, wenn ich der Meinung
bin, es soll ein Bitmuster als String zurückgegeben werde?
Falls ja:
warum nimmt die funktion Shorts, wenn sie nur 8bit umwandelt?
Außerdem ist das ergebnis verkehrt rum. Das niederwertige bit wird hier
als erstes ausgegeben.
Hier mal ein kleines Beispiel vernünftigen Codestils
1
/**
2
* Converts a given byte to string of its binary representation
3
* @param o_dest the buffer that receives the resulting string
Vlad Tepesch schrieb:> Peter II schrieb:>> char bin[9+1];>> das bin darf nicht lokal definert werden, das wird ja zurückgegeben.
sorry meine temp wie auch schon oben jemand anders geannt hatte.
ggast schrieb:> Ist das jetzt Absicht oder ein Tippfehler?
rate mal
Vlad Tepesch schrieb:> char curBit = (i_byte & 1); // linkestes Bit auslesen
sorry, sollte natürlich rechtestes heißen.
Ich wollts erst andersrum schieben und auslesen
Prinzipiell sei noch zu sagen, dass solche Kommentare nicht sehr
sinnvoll sind, da man eher beschreiben soll, warum etwas gemacht wird,
und nicht der Code nochmal übersetzt werden soll.
Da hier aber die Grundkenntnisse noch recht wackelig zu sein scheinen,
hab ichs trotzdem so gemacht.
> dieser läst sich eindeutisch erkennen, wie das Teil einmal> aussehen soll.
Nein, das ist ein Gewurstel^3 hier kann niemand irgendetwas eindeutiG
erkennen. Gäbe es einen Geigerzähler für die Anzahl der Fehler pro Zeile
hätte dein Code Werte wie in Fukushima. Sorry.
Fakt ist: Jedes mal bei dem du in der Schleife die Funktion ctb()
aufrufst wird durch
1
char *bin = malloc(sizeof(char)* (9+1));
Speicher allokiert. Diesen gibst du nie frei -> Speicherleck.
Desweiteren: Du initialisierst den Speicher in "bin" nicht benutzt
später aber strcat(). Der Speicher muss nicht mit 0 vorinitialisiert
sein. Dadurch schreibt strcat() wild in den Speicher, da es zunächst
das Ende des String sucht (eine ASCII-0) und danach schreibt.
> printf(" %c == %hu ", _cfe[a++], (unsigned short)_cfe[a]);
Das Ergebnis dieser Zeile ist btw undefiniert!
Schöne Grüße
U.R. Schmitt schrieb:> Zusätzlich zu den schon beschriebenen Fehlern ist es IMMER sinnvoll nach> einem malloc() zu prüfen ob der erhaltene Zeiger wirklich ungleich NULL> ist!
macht das wirklich so viel Sinn?
wenn der Rechner so voll ist, dass man nicht mal mehr ein paar Byte
holen kann, dann hast du eh verloren, dann ist RAM+Swap voll.
Auf µCs oder wenn man Speicher im Megabytebereich anfordert ok, aber
sonst.
@Vlad Tepesch
> Prinzipiell sei noch zu sagen, dass solche Kommentare nicht sehr> sinnvoll sind, da man eher beschreiben soll, warum etwas gemacht wird,> und nicht der Code nochmal übersetzt werden soll.
Das weiß ich, Aber für mich ist in dem falle aus Persönlicher ordnung
auch die GROß- und kleinschreibung wichtig. GROß = änderung klein =
info/aufgabe
@klaus
das Hier
1
char*bin=malloc(sizeof(char)*(9+1));
das leak auftritt vermute ich auch, aber wie du hier
1
return(bin);
gebe ich bin über. soll ich ihn nun vor oder nach der zeile wieder
freigeben? vor der zeile lohnt nicht, da sonst inhalt weg.
Nach der zeile macht wohl auch nicht wirklich sin.
ergo entweder in eine header schreiben oder global.
>> printf(" %c == %hu ", _cfe[a++], (unsigned short)_cfe[a]);
Irtum... wenn ich mir der Bleistift und papier methode das alles
durchspiele und || in die konsole schauen lese ich
> Moin : AB> Wert?! 10000010> Wert?! 01000010
Ähmmm wer hat gerade mit µC angefangen??? auf die finger hau...
ich eine Function auf Konsolenebene für ein Programm.
ergo später soll dies in ein *.so/*.dll übertragen werden.
Maik Geßner schrieb:> Das weiß ich, Aber für mich ist in dem falle aus Persönlicher ordnung> auch die GROß- und kleinschreibung wichtig. GROß = änderung klein => info/aufgabe
das bezog sich eigentlich auf meine Kommentare.
Bei dir gibts ja fast keine und die, die es gibt sind falsch oder
unverständlich.
Maik Geßner schrieb:> das leak auftritt vermute ich auch, aber wie du hierreturn(bin); gebe ich bin
über. soll ich ihn nun vor oder nach der zeile wieder
> freigeben? vor der zeile lohnt nicht, da sonst inhalt weg.
vor der Zeile darf nicht> Nach der zeile macht wohl auch nicht wirklich sin.
nach der Zeile geht nicht
du musst den Rückgabewert der Funktion speichern, dann benutzen und dann
freigeben.
Aber wie gesagt:
Vlad Tepesch schrieb:> Normalerweise macht man sowas aber trotzdem nicht, sondern übergibt der> Funktion einen Puffer, der beschrieben werden kann.> Normalerweise gilt die Regel: Es gibt der den speicher Frei, der ihn> auch alloziert hat.
Maik Geßner schrieb:> Ähmmm wer hat gerade mit µC angefangen??? auf die finger hau...> ich eine Function auf Konsolenebene für ein Programm.> ergo später soll dies in ein *.so/*.dll übertragen werden.
Kannst du das nochmal für die übersetzen, deren Glaskugel kaputt ist und
auch nicht über hellseherische Talente verfügen.
Vlad Tepesch schrieb:> annst du das nochmal für die übersetzen, deren Glaskugel kaputt ist und> auch nicht über hellseherische Talente verfügen.
Das Ganze ist für ein Konsolenprogramm für den PC gedacht, entweder
Linux oder Windows, und soll warum auch immer in einer shared library
(.so) oder DLL Datei enden, was für das Problem natürlich ohne Relevanz
ist.
Ansonsten gilt, was Vlad gesagt hat.
Etwas Hirnschmalz in das Design stecken.
Normalerweise alloziert man den Speicher im aufrufenden Programm,
übergibt einen Zeiger auf den Speicher und die Größe des Speichers an
das Unterprogramm das dann was auch immer in den Speicher schreibt.
Es geht auch anders, wenn z.B. das aufrufende Programm die Daten und die
Größe nicht genau kennt, Beispiel File Schnittstelle. Dann schreibt man
aber gewöhnlich eine komplette gekapselte API die den Freigabeprozess
mit beinhaltet. Der Aufrufer ist dann dafür zuständig das auch in jedem
Fall zu gewährleisten.
Im Fall FILE ist das fopen() und fclose().
Maik Geßner schrieb:> soll ich ihn nun vor oder nach der zeile wieder freigeben?
Weder noch. Du allozierst den Speicher im Hauptprogramm, und übergibst
einen Zeiger auf den reservierten Speicher an die Funktion. Sobald der
Speicherbereich im Hauptprogramm nicht mehr benötigt wird, wird er
freigegeben.
Vlad Tepesch schrieb:> hat jemand etwas anders behauptet?
???
Du hast doch geschrieben:
Vlad Tepesch schrieb:> Maik Geßner schrieb:>> Ähmmm wer hat gerade mit µC angefangen??? auf die finger hau...>> ich eine Function auf Konsolenebene für ein Programm.>> ergo später soll dies in ein *.so/*.dll übertragen werden.>> Kannst du das nochmal für die übersetzen, deren Glaskugel kaputt ist und> auch nicht über hellseherische Talente verfügen.
Also habe ich angenommen du hättest das nicht verstanden.
Mark Brandis schrieb:> Du allozierst den Speicher im Hauptprogramm, und übergibst> einen Zeiger auf den reservierten Speicher an die Funktion.
Sauber ist es wenn man auch die Größe des Speichers an das Unterprogramm
mit übergibt.
Maik Geßner schrieb:> gebe ich bin über. soll ich ihn nun vor oder nach der zeile wieder> freigeben? vor der zeile lohnt nicht, da sonst inhalt weg.> Nach der zeile macht wohl auch nicht wirklich sin.
Wenn du ihn davor freigibt erzeugt der Aufrufer der Funktion eine memory
access violation wenn er auf die zurückgegebene Speicheradresse
zugreift. Wenn du ihn nicht freigibst (wie es jetzt ist) übergibst du
dem Aufrufer die Verpflichtung den Speicher freizugeben. Dies tut er
hier nicht, da das Ergebnis direkt in printf() landet
und die Adresse danach verloren ist. Du müßtest du Rückgabe von ctb() in
einem Pointer zwischenspeichern, diesen printf() übergeben und danach
free() aufrufen.
Maik Geßner schrieb:> Irtum... wenn ich mir der Bleistift und papier methode das alles> durchspiele und || in die konsole schauen lese ich
Angenommen a ist 0. Du gehst von folgender Reihenfolge aus:
a) Erster Parameter wird geholt, also _cfe[0]
b) a++ wird gebildet
c) Zweiter Parameter wird geholt, also _cfe[1]
d) Funktionsaufruf
Die Reihenfolge mit der Parameter verarbeitet werden garantiert dir der
Compiler aber nicht. Je nach Compiler/Plattform kann es auch anders
herum laufen, und zwar so:
a) Zweiter Parameter wird geholt, also _cfe[0]
b) Erster Parameter wird geholt, also _cfe[0]
c) a++ wird gebildet
d) Funktionsaufruf
Du siehst dass dies unterschiedliche Resultate sind auch mit Bleistift.
Deshalb habe ich gesagt, dass das Ergebnis dieser Zeile undefiniert ist.
Wikipedia zitiert übrigens ein ähnliches Negativbeispiel von Kernighan
and Ritchie:
http://en.wikipedia.org/wiki/Undefined_behavior
was soll daran nicht sauber sein wenn ein eine funktion einen Zeiger
zurückliefert? Es muss nur klar sein das dieser zeiger auch wieder
Freigeben werden muss.
malloc macht doch auch nichts anderes, es liefert einen zeiger zurück
der mit free wieder freigeben werden muss.
U.R. Schmitt schrieb:> Sauber ist es wenn man auch die Größe des Speichers an das Unterprogramm> mit übergibt.
Ja.
Im übrigen, eine Funktion mit einem Dutzend Zeilen Code, die weder
Massen an Hauptspeicher benötigt noch unheimlich viel Rechenzeit oder
Zugriff auf ein Dateisystem, sollte auf einem kleinen µC genau so
einsetzbar sein wie auf einem PC. Ohne große Änderung. Am besten mit gar
keiner :)
Übrigens übrigens, es gibt kein Speicherleak, sondern nur ein memory
leak oder Speicherleck. ;)
Peter II schrieb:> was soll daran nicht sauber sein wenn ein eine funktion einen Zeiger> zurückliefert? Es muss nur klar sein das dieser zeiger auch wieder> Freigeben werden muss.
Es ist schlechter Stil, weil das passieren kann was in diesem Beispiel
hier passiert (Freigabe wird vergessen). In diesem konkreten Fall hier
ist es außerdem völlig unnötig, da die benötigte Speichergröße von vorne
herein feststeht. Als "good practice" würde man die Funktion wie folgt
definieren:
1
unsigned int ctb(char* buffer, unsigned int size);
Der Speicher und dessen Größe kommt von außen. Die Rückgabe wird
typischerweise die Anzahl der geschriebenen Zeichen angeben.
Vlad Tepesch schrieb:> Klaus schrieb:>> unsigned int ctb(char* buffer, unsigned int size);>> du hast das hauptargument vergessen ;)g stimmt :-)
@Maik
Noch ein kleiner Tipp: Suche und benutze mal "SPLint". Es hat die
meisten deiner Fehler gefunden, z.B. zu
liegt das ggf hier nur daran, das ich dem Zeiger *text schon foher eine
constande mitgebe?
Dann noch, da einige sagten! die Größe des Speichers gleich mit geben.
Leicher gesagt als getan -.-, der eigendlich wert, soll ja von einem
Programm, welches unter Lazarus-IDE geschrieben wird übergeben werden.
die Bibliothek schreibe ich deshalb nur in C, weil via pfc bei der
selben function schon ü 1,5 MB zusammen kommen. Den speicher, welche die
Biliothek dann braucht soll angand des Wertes ermittelt werden.
Maik Geßner schrieb:> liegt das ggf hier nur daran, das ich dem Zeiger *text schon foher eine> constande mitgebe?
Wo tust Du das? Im Codebeispiel von eben tust Du genau das nicht.
Kauf Dir ein C-Buch, und lies es durch. Wirklich.
Empfehlung: "Programmieren in C" von Brian Kernighan & Dennis Ritchie,
2. Ausgabe, erschienen im Hanser-Verlag.
Ist zwar 20 Jahre alt, aber immer noch das Grundlagenwerk, das Dir
alles beibringt, was Du über C wissen musst. Und lesbar ist diese
Ausgabe auch noch (ganz im Gegenteil zur noch älteren ersten Ausgabe).
Maik Geßner schrieb:> Da versteh ich aber eines nicht>> im folgend code, was ja der Grundgedanke war geht's ohne Speicherleck.
Ein Speicherleck entsteht in diesem auch nicht. Die undefiniert
verhaltende
printf() Anweisung ist da aber auch drin.
Ich denke aber man hat dir in diesem Thread genügend Informationen
gegeben und dir die Lösung auf dem Silbertablett serviert. Du solltest
das Problem leicht selbst lösen können. Die Lektüre eines C Buches ist
dennoch dringend anzuraten.
Rufus Τ. Firefly schrieb:> Empfehlung: "Programmieren in C" von Brian Kernighan & Dennis Ritchie,> 2. Ausgabe, erschienen im Hanser-Verlag.
Haben die Übersetzer dazugelernt? In meiner Ausgabe von '83 ist von
einer 'Standard Bücherei' und, wenn ich mich recht erinnere, von 'Schnur
Funktionen' Rede.
Luk4s K. schrieb:> Haben die Übersetzer dazugelernt? In meiner Ausgabe von '83 ist von> einer 'Standard Bücherei' und, wenn ich mich recht erinnere, von 'Schnur> Funktionen' Rede.
"Standard library" und "string functions"? Oh Gott wie schlecht. Das
kommt eben dabei heraus, wenn der Übersetzer keine Ahnung von der
Materie hat - gut, man kann nicht alles wissen - aber wenn dann auch
noch niemand mit Ahnung Korrektur liest... :-(
Luk4s K. schrieb:> In meiner Ausgabe von '83 ist von> einer 'Standard Bücherei' und, wenn ich mich recht erinnere, von 'Schnur> Funktionen' Rede.
*rofl*
Luk4s K. schrieb:> Haben die Übersetzer dazugelernt? In meiner Ausgabe von '83 ist von> einer 'Standard Bücherei' und, wenn ich mich recht erinnere, von 'Schnur> Funktionen' Rede.
Ja, das ist die erste Ausgabe, die ist in der Übersetzung wirklich
grauenerregend.
Fast, als hätte sich daran eine frühe Version eines
Übersetzungsprogrammes versucht, "Zeiger Variable" wird im Deutschen
immer noch zusammengeschrieben, und wurde in den 80ern erst recht
zusammengeschrieben.
Die zweite Ausgabe von 1990 oder 1989 beschreibt einerseits nicht mehr
das steinzeitliche "K&R-C" ohne Typprüfung, sondern ANSI-C bzw. C89, und
ist erheblich besser übersetzt. Auch wird für Codebeispiele keine
Proportionalschrift mehr verwendet.