Hallo,
Ich bin noch recht unerfahren was C-Programmierung angeht und habe hier
in meiner Arbeit die Aufgabe, eine Funktion zu schreiben, die aus einem
String einen Teilstring auswählt und ausgibt. Das ganze mache ich mit
dem Atmel Studio 6.2.
Die Grenzen des auszuwählenden Strings sind die Schlüsselworte "svn" und
"src".
Ich habe das ganze erst über eine Reihe von for-Schleifen gelöst, was
schnell und einfach ging und auch funktioniert.
Jetzt würde es mich aber reizen, ob man das nicht schöner auch lösen
kann.
Ich habe hier im Forum schon was in die Richtung gefunden,
weitergeholfen hat es mir aber nicht, wie auch sonst nichts auf google.
Hier wäre der Code:
Am Ende will ich praktisch: "project005_Controller/branches/NEON1_1" als
Ausgabe haben.
Das Problem ist halt, dass nicht immer den Anfang, Ende und Länge des
Strings gleich ist.
Der Code ist nicht mehr genau der, den ich anfangs hatte, aber ich habe
schon so viele Sachen ausprobiert, dass ich nicht mehr sagen kann was
ursprünglich war. Vielleicht habe ich ja nur einen Pointer an der
falschen Stelle oder an der falschen Stelle (De)referenziert?
Aus diesem Forum hier habe ich schon einige nützliche Informationen
bekommen, danke schon mal dafür ;)
Und auch nochmals vielen Dank falls jemand eine Lösung hat!
Gruß
Simon schrieb:> Ich bin noch recht unerfahren was C-Programmierung angeht und habe hier
in diesem Fall solltest Du alle Compiler-Warnungen einschalten, die
Warnungen (die dein Code, so wie Du ihn gepostet hast, in Hülle und
Fülle produzieren wird) genau lesen, verstehen und eine nach der
anderen beheben. Das erzeugt Erfahrung ;).
Simon schrieb:> uint16_t *frontBorder = strstr( repositoryStr,"svn");> uint16_t *backBorder = strstr( repositoryStr,"src"); // hinteres ende> length = backBorder - frontBorder;
Wenn denn "svn" und "src" existieren, dann benötigst du den Abstand als
ein abgerundetes Vielfaches von sizeof(uint16_t)?
Dein Nachfolgender Code sieht eher so aus, als ob du den Abstand in char
benötigst.
> branchStr[50] =
Das ist das 51. Zeichen. Du hast aber nur 50 Zeichen definiert.
> return &branchStr;
Das ist ein No-Go (auch wenn es häufig funktioniert): branchStr liegt
nach der Rückkehr der Funktion auf dem freien Stack.
> Das ganze mache ich mit dem Atmel Studio 6.2.
Grundsätzliche Empfehlung:
Solche Sachen sind nicht plattformabhängig.
Deshalb zuerst auf dem PC ausprobieren.
Das ist deutlich weniger umständlich als auf einem Controller.
stdio.h und string.h sind Standardheader. Die werden beim include mit <>
eingefasst.
strstr gibt ein char* zurück (kein uint16_t*)
Den Rückgabewert von strncpy brauchst du nicht zuweisen. Das ist der
erste Parameter. (Der Wert hilft bei der Verkettung von
Funktionsaufrufen)
Du berechnest length falsch.
frontborder zeigt schon auf den gesuchten String. Das ist kein Offset.
branchStr[length+1] ist um eins daneben.
Adressen von lokalen Variablen darf man nicht zurück geben, da sie
danach sofort ungültig werden.
Simon schrieb:> Der Code ist nicht mehr genau der, den ich anfangs hatte, aber ich habe> schon so viele Sachen ausprobiert, dass ich nicht mehr sagen kann was> ursprünglich war.
"Probieren" ist mit C der ganz grundsätzlich falsche Weg. Selbst wenn es
compiliert und läuft, heißt das nicht, daß es immer laufen wird. C geht
davon aus, daß der Programmierer exakt weiß, was er tut.
Neben den ganzen Anmerkungen, was an dem Code nicht geht:
Fehlerbehandlung fehlt ja auch noch völlig. Was, wenn der String Deine
Schlüsselworte schlichtweg nicht enthält?
Also, schonmal danke für die vielen und schnellen Antworten, mach ich
mich mal ans beantworten ;)
Der Andere schrieb:> mal wieder programming by seek, copy and paste> :-(((((
Wie gesagt, ich muss das in der Arbeit machen und das ist nur eine der
kleinen Aufgaben zwischendurch, weswegen ich da leider auch kein Buch
durcharbeiten kann, selbst wenns mich interessiert. Daher bleibt mir
auch nicht viel als es mit seek and copy zu versuchen, aber mit dieser
Methode verfährt man in der Regel sehr gut. Das Kapitel zu Pointern habe
ich mir aber tatsächlich durchgelesen aber da wird einem nicht alles
beim erstem mal klar, bitte um Verständnis ;)
Normal bin ich hier für die MATLAB Programmierung zuständig und da ist
nunmal einiges anders.
Der Andere schrieb:> Aber eine Programmiersprache LERNEN ist heutzutage scheinbar uncool.
Ähnliches zu dir, da fehlt mir die Zeit. Die Funktion funktioniert wie
gesagt mit den for-Schleifen, alles andere hier ist aus reiner
Interesse, aber dafür hab ich wenig Arbeitszeit :(
Trotzdem werde ich mich mal deinem Dokument annehmen, danke dir auch
hierfür.
Mikro 7. schrieb:> Wenn denn "svn" und "src" existieren, dann benötigst du den Abstand als> ein abgerundetes Vielfaches von sizeof(uint16_t)?
Genau, ich will damit über die Länge nur das benötigte ab Beginn des
Teils kopieren. length gibt mir praktisch mein hinteres Ende.
Nop schrieb:> Was, wenn der String Deine Schlüsselworte schlichtweg nicht enthält?
Tut er dank SVN ;)
Mikro 7. schrieb:>> branchStr[50] => Das ist das 51. Zeichen. Du hast aber nur 50 Zeichen definiert.
Stimmt, danke. Korrigiert.
Dirk B. schrieb:> strstr gibt ein char* zurück (kein uint16_t*)
Korrigiert.
Mikro 7. schrieb:>> return &branchStr;>> Das ist ein No-Go (auch wenn es häufig funktioniert): branchStr liegt> nach der Rückkehr der Funktion auf dem freien Stack.
Als static deklariert, dann passt das?! ODer muss ich auch das '&'
weglassen?
Ich habe jetzt eine Lösung hinbekommen, die funktioniert:
Ich hatte übersehen, dass frontBorder ja schon ein Pointer auf die
Stelle ist, und ich die Zeile "repositoryStr + (frontborder + 3)" nur zu
"frontBorder + 4" ändern musste und schon hats eigentlich geklappt.
Simon schrieb:> static char branchStr[51];> branchStr[51] = strncpy(branchStr, frontBorder + 4, length);
Branch hat 51 Elemente, aber die Zählung beginnt bei 0. Mehr als
branch[50] ist buffer overflow.
Zweitens, mach eine Abfrage rein, ob length <= 50 ist. Wenn nicht,
clippe length auf 50.
Simon schrieb:> branchStr[length+1] = '\0'; // string terminieren
Achso, und das müßte
branchStr[length+1] = '\0';
sein, weil die Zählung bei 0 losgeht. Hast Du einen String von sagen wir
3 chars, dann sind die chars an den Positionen 0, 1, 2. Length ist dann
3. Also muß an Stelle 3 terminiert werden.
Und welchen Sinn (außer dem Buffer Overlow ^^) hat
branchStr[51] = ...
eigentlich? Fragst Du die Stringlänge an der Position später noch ab,
wie bei Pascal-Strings?
Normalerweise würde man das übrigens auch nicht mit einem static char[]
machen, sondern der Aufrufer würde einen char * übergeben, in den das
reinsoll, zusammen mit einer expliziten Information, wie lang der
übergebene Speicherbereich ist. Sizeof funktioniert nicht mit arrays,
die an FUnktionen übergeben werden, daher die explizite Längenangabe.
Vorteil: Wenn mehrere Stellen die Funktion aufrufen, kriegen sie alle
ihr Ergebnis korrekt.
Buffer overflow wurde oben schon geschrieben. Es wurde auch bereits
gesagt was strncpy() zurück liefert. Hast du das gelesen?
Was bezweckst du mit der Zuweisung?
Simon schrieb:> Ich habe jetzt eine Lösung hinbekommen, die funktioniert:
Und bei dem nächsten Trivialproblem doktorst du wieder einen halben Tag
rum und hoffst dann darauf, dass dir jemand in einem Forum hilft?
Simon schrieb:> Wie gesagt, ich muss das in der Arbeit machen und das ist nur eine der> kleinen Aufgaben zwischendurch, weswegen ich da leider auch kein Buch> durcharbeiten kann, selbst wenns mich interessiert.
Du denkst du kommst schneller voran, wenn du dein Handwerkszeug NICHT
lernst?
Welcher Vollhonk von Vorgesetzter lässt jemanden ohne Ahnung sowas
machen?
Der sichere Weg zu Fehlern, und die Realität lehrt, je früher ein Fehler
entdeckt oder erst gar nicht gemacht wird, desto billiger ist seine
Beseitigung. Je mehr Zeit in Grundlagen investiert wird, desto
produktiver wird danach der Einsatz.
Aber es ist deine Arbeit und dein Chef muss mit dem Ergebnis leben...
Viel Spass weiterhin
Mikro 7. schrieb:> Buffer overflow wurde oben schon geschrieben. Es wurde auch bereits> gesagt was strncpy() zurück liefert. Hast du das gelesen?
Hab ich ja, aber nicht genau verstanden was gemeint war, deswegen des
weiteren gelassen^^
Buffer-Overflow Thematik auch gelesen.
Deklaration als static wird auch überdacht.
Danke euch Nop und mikro77.
Zu dir 'Der Andere':
Immerhin hast du dir die Zeit genommen, also will ich dir auch
antworten.
Wie gesagt ist meine Aufgabe eine andere, aber das sollte ich nebenbei
machen und da ich Praktikant bin, und mein Chef weis, dass ich mich da
nicht auskenne, denke ich wollte er mir nur eine kleine interessante
Aufgabe zwischendurch geben.
Das war in 6 Monaten das erste Mal, dass ich etwas mit C machen musste,
mit Pointern habe ich noch nie gearbeitet.
So habe ich das mal als Herausforderung gesehen, und wie oben erwähnt
war das alleine meine Entscheidung das auf diese Weise zu machen, mit 3
for-Schleifen war in 30 min erledigt und hat auch gepasst.
Dazu hab ich den Großteil der Arbeit hier in Pausen gemacht, war also
noch nicht mal Arbeitszeit.
Zwischendurch habe ich die meiste Zeit andere Sachen erledigt, weshalb
die Antwort etwas auf sich warten ließ.
Natürlich macht es Sinn sich das alles von Grund auf anzueignen, man
kann nun mal nicht alles können, bzw. hat einfach nicht die Zeit dazu.
Jetzt habe ich mal ein Problem mit Pointern lösen können, was ja ganz
interessant war.
Zudem hab ich auf google meine Frage einige Male gelesen, aber nie kam
eine vernünftige Antwort, also hilft das vielleicht nochmal jemanden der
etwas in der Art implementieren will.
Gruß
Marc V. schrieb:> Simon S. schrieb:>> Danke euch Nop und mikro77.>> Wobei die beste Antwort schon vorher da war:> Dirk B. schrieb:
Das stimmt ;)
Ich habe nur die beiden erwähnt, weil sie diejenigen waren, die unter
meiner Antwort kommentiert haben. War zum hervorgeben gedacht, da von
den beiden konstruktive Sachen kamen im Gegensatz zu den anderen Posts
;)