GMKai Geschrieben 15. Oktober 2003 Geschrieben 15. Oktober 2003 Nun die nächste Funktion: soweit habe ich es schon: #include <stdio.h> int main() { char text[255]; int ownstrlen(*text); int length; printf("Text eingeben:\n"); gets(text); ownstrlen(text); printf("Textlänge: %i\n",length); return 0; } int ownstrlen(*text) { int i=0,lenght; do { if (text!=10) { lenght=i; } i++; } while(text!=10); return (lenght); } vor den zeilen 16 und 24 hakt es noch, wo der syntax error liegt, weiss ich aber nicht. Zitieren
FinalFantasy Geschrieben 15. Oktober 2003 Geschrieben 15. Oktober 2003 zunächst mal in Zeile 6, das ist die Deklaration deiner Funktion, die gehört sich ausserhalb von main(), ma besten gleich nach den Includes. Die Funktion selber gehört sich natürlich auch ausserhalb von main. Beim Aufruf deiner Funktion solltest du natürlich auch den Rückgabewert auffangen. Etwas so: length = ownstrlen(text); also ich würd das in etwa so lösen: #include <stdio.h> int mystrlen(const char*); void main() { char text[255]; int length; strcpy(text, "blablablablablabl"); length = mystrlen(text); printf("Der Text hat %d Zeichen", length); //oder gleich: // printf("Der Text hat %d Zeichen", mystrlen(text)); } int mystrlen(const char* text) { for(int i = 0; text != '\0'; i++); return i; } Hab den Code jetzt nicht getestet, sollte so aber funktionieren. *-- edit: Warum werden die Leerzeichen am Zeilenanfang rausgelöscht? Is ja ****e, wie soll man so einen halbwegs leserlichen Code schreiben können? Warum willst du das ganze Zeug eigentlich nachprogrammieren, wenns doch schon fertig ist? Zitieren
GMKai Geschrieben 15. Oktober 2003 Autor Geschrieben 15. Oktober 2003 ich soll das nachprogramieren, damit der awe-lehrer zufrieden ist. Zitieren
Jusky Geschrieben 15. Oktober 2003 Geschrieben 15. Oktober 2003 Ich würde es auch so machen wie FinalFantasy. Nur du musst für die Funktion strcpy noch die Bibliothek string.h aufrufen. Des Weiteren würde ich in der Unterfunktion die Zählvariable i vor der Schleife deklarieren, da bei mir so ein Fehler auftaucht. @FinalFantasy Ich denke mal, GMKai braucht dieses Programm einfach nur mal zum Nachvollziehen der C-Algorithmik. Wir haben auch in einer internen Schulung mal die Aufgabe gehabt, die Rechenarten nur mit der Grundrechenart zu programmieren... Zitieren
FinalFantasy Geschrieben 15. Oktober 2003 Geschrieben 15. Oktober 2003 Hi, ok, ich habs schon verstanden, war ja auch nicht bös gemeint. *gg* Stimmt, die String.h hab ich vergessen. Ok, das geb ich auch zu, wenn man i erst in der Schleife deklariert, dürfte sie beim Return nach der Theorie schon nicht mehr existieren, oder? Visual Studio 6.0 hat damit allerdings keine Problem. Mit was programmierst denn du? Zitieren
Jusky Geschrieben 15. Oktober 2003 Geschrieben 15. Oktober 2003 Auch Visual Studio 6.0, nur bei mir funzt das nicht... Zitieren
GrEnE Geschrieben 15. Oktober 2003 Geschrieben 15. Oktober 2003 Hmm, kannst du es nicht so machen - oder ist es verboten (für den Lehrer)? int mystrlen( char* str) { std::string string(str); return string.size(); } [/PHP] Zitieren
GMKai Geschrieben 15. Oktober 2003 Autor Geschrieben 15. Oktober 2003 was ist das denn für ein konstrukt??? edit: ouch, das php hab ich zu spät gesehen, "leider" soll das ganze in c geschrieben werden. und nur ums erwähnt zu haben, als compiler verwende ich den gcc, bzw dev-c. kann man kostenlos unter bloodshed.net downloaden *werbung mach* Zitieren
GMKai Geschrieben 15. Oktober 2003 Autor Geschrieben 15. Oktober 2003 den vorschlag von FinalFantasy krieg ich jetzt compiliert, nur das ergebnis ist völlig falsch! da kommt 4240832 raus! fehlt in dem default-string nicht das \0 oder \n? Zitieren
Diablo999 Geschrieben 15. Oktober 2003 Geschrieben 15. Oktober 2003 Also, die Version von Final... funktioniert!!! Aber was hälst du hiervon? int StrLen(char* sz) { int nRet; __asm { mov eax, 0 mov ebx, sz START: cmp [ebx], 0 je END inc eax inc ebx jmp START END: mov nRet, eax } return nRet; } könnte man natürlich nochn bisschen schöner machen, ist aber ca. um faktor 4 schneller als der C-Code, übrigens genauso schnell wie die orginal strlen(). Gruß Diablo999 Zitieren
FinalFantasy Geschrieben 15. Oktober 2003 Geschrieben 15. Oktober 2003 Meine Version hat aber noch einen kleinen aber verzwickten Fehler: Strlen gibt eins mehr zurück, weil ich ja bei null zu zähle anfange. Man müsste also unten "return ++i;" schreiben. Wenn man aber jetzt einen leeren String hätte, würde aber auch 1 zurückgegeben. Ganz sicher wäre es dann eigentlich nur so: int mystrlen(char* text) { if(text[0] == '\0') return 0; else for(i = 0; text != '\0'; i++); return ++i; } wobei man bei der Vorschleife eigentlich wegen der ersten abfrage gleich bei 1 anfangen könnte. Ich glaub die Assemblerlösung, hilft ihm nicht sonderlich viel, wenns um einen C-Kurs geht. Aber mal nebenbei: Mich würd Assembler mal interessieren, find allerdings kaum was dazu. Also wenn jemand Assembler kann, und Zeit hätte, könnte er mir da mal einiges erklären. Zitieren
GrEnE Geschrieben 15. Oktober 2003 Geschrieben 15. Oktober 2003 Original geschrieben von FinalFantasy int mystrlen(char* text) { if(text[0] == '\0') return 0; else for(i = 0; text != '\0'; i++); return ++i; } wobei man bei der Vorschleife eigentlich wegen der ersten abfrage gleich bei 1 anfangen könnte. Okay wegen deinen Einwand würde ich wirklich bei 1 anfangen und nun noch eine ganz kleine Kleinichkeit - die mir duch meine Ausbildung "eingeprügelt" wurde. Nämlich anstatt "i++" - "++i" - der Unterschied ist, dass bei "++i" keine temporäre Variable vom Compiler angelegt wird. Ist eigentlich nur eine Performancesache. Zitieren
Diablo999 Geschrieben 15. Oktober 2003 Geschrieben 15. Oktober 2003 Nämlich anstatt "i++" - "++i" - der Unterschied ist, dass bei "++i" keine temporäre Variable vom Compiler angelegt wird. Ist eigentlich nur eine Performancesache. Das ist leider nicht ganz richtig, der eigentliche Unterschied zwischen "++i" und "i++" ist das bei ++i die Variable vor dem Ausführen der eigentlichen Befehlszeile inkrementiert wird, bei i++ wird die Variable erst nach dem Ausführen der Befehlszeile inkrementiert. das heißt z.B. i = 3; FunktionX( i++ ); Die Funktion X bekommt eine 3 als Übergabeparamter. und so: i = 3; FunktionX( ++i ); Die Funktion X bekommt eine 4 als Übergabeparamter. Der Compiler legt nicht zwansläufig ne TempVar an, des kommt auf dem Compiler an, würde ich behaupten. Wenn des auch noch nicht ganz stimmt bitte ich um Berichtigung... Gruß Diablo999 Zitieren
Klotzkopp Geschrieben 16. Oktober 2003 Geschrieben 16. Oktober 2003 Original geschrieben von Diablo999 Der Compiler legt nicht zwansläufig ne TempVar an, des kommt auf dem Compiler an, würde ich behaupten. Wenn des auch noch nicht ganz stimmt bitte ich um Berichtigung... Der Compiler darf, wenn der Rückgabewert des Ausdrucks i++ nicht gebraucht wird (z.B. wenn es ein alleinstehender Ausdruck oder das letzte Argument einer for-Anweisung ist), i++ durch ++i ersetzen, wenn er ausschließen kann, das i++ nicht noch andere Seiteneffekte hat. Das können gängige Compiler auf jeden Fall bei eingebauten Datentypen. Bei Klassen (z.B. Iteratoren von manchen Containerklassen) geht das üblicherweise nicht, weil operator++() und operator++(int) überschrieben sind, und der Compiler nicht erkennen kann, ob er den einen einfach durch den anderen ersetzen darf. Dann muss der Compiler bei i++ eine temporäre Variable anlegen, was je nach Typ recht aufwändig sein kann. Darum sollte man sich angewöhnen, überall dort, wo man den Seiteneffekt des Postinkrements nicht braucht, Preinkrement zu benutzen. Kurz: Wenn es egal ist, nimm ++i. Kann nicht schaden, kann eventuell sogar nutzen. Zitieren
GrEnE Geschrieben 16. Oktober 2003 Geschrieben 16. Oktober 2003 Original geschrieben von Diablo999 Das ist leider nicht ganz richtig, der eigentliche Unterschied zwischen "++i" und "i++" ist das bei ++i die Variable vor dem Ausführen der eigentlichen Befehlszeile inkrementiert wird, bei i++ wird die Variable erst nach dem Ausführen der Befehlszeile inkrementiert. Ja das ist der inhaltliche Unterschied der Operatoren - aber wie bewerkstelligen sie das? - durch temporäre Variable(n). Aber genug, denn Klotzkopp hat es sehr gut erklärt. Zitieren
nic_power Geschrieben 18. Oktober 2003 Geschrieben 18. Oktober 2003 Hallo, Original geschrieben von Diablo999 int StrLen(char* sz) { int nRet; __asm { mov eax, 0 mov ebx, sz START: cmp [ebx], 0 je END inc eax inc ebx jmp START END: mov nRet, eax } return nRet; } könnte man natürlich nochn bisschen schöner machen, ist aber ca. um faktor 4 schneller als der C-Code, übrigens genauso schnell wie die orginal strlen(). Im Vergleich zu welcher C-Version (und welchen Compiler-Optionen, Compiler, usw)? Was mich bei all den Beispielen wundert ist die Tatsache, dass ein ineffizienter Algorithmus für die Berechnung der String-Länge verwendet wird. Dieser wird auch nicht durch die Implementierung in Assembler schneller (der Code wird eher langsamer, da ein guter C-Compiler im Zweifelsfall die entsprechende Optimierung von selbst durchführt). In allen Code-Beispielen werden zwei Variablen benötigt, die innerhalb der Schleife modifiziert werden. Zum einen der Pointer auf den String und zum anderen eine Zählvariable. Das ist aber völlig unnötig, da uns C die Pointer-Arithmetik geschenkt hat. Nicht umsonst ist im K&R als Beispiel für strlen folgendes Code-Fragment zu finden: int strlen(char *s) { char *p=s; while (*p) p++; return (p-s); } [/php] Im inneren Loop der Schleife wird nur der Pointer erhöht (d.h. man spart sich pro Schleifendurchlauf eine Operation!), die eigentliche Länge des Strings wird später mit genau einer Operation berechnet. Und hier noch ein kleines Assemblerbeispiel für strlen: [php] .section ".text" .align 4 .global myStrlen .type myStrlen,#function myStrlen: mov %o0, %g3 ! pointer retten ! Argument wird in %o0 uebergeben loop: ldsb [%o0], %g2 ! char nach %o0 laden cmp %g2, 0 ! stringende erreicht ? bne,a loop ! nein, dann naechstes zeichen inc %o0 retl ! sprung zum aufrufer sub %o0, %g3, %o0 ! vorher noch laenge berechnen Nic Zitieren
FinalFantasy Geschrieben 18. Oktober 2003 Geschrieben 18. Oktober 2003 Hm, auch eine interessante Lösung, für einen C-Anfängerkurs aber doch wohl eher etwas zu viel verlangt. Aber ich muss ehrlich sagen, da wäre ich auch nicht drauf gekommen. *gg* Zitieren
Diablo999 Geschrieben 19. Oktober 2003 Geschrieben 19. Oktober 2003 @Nic Da hast du allerdings recht!!! Muss zzugeben das es ganz schön unsinnig ist zwei Vars zu verwenden... Diablo999 Zitieren
nic_power Geschrieben 19. Oktober 2003 Geschrieben 19. Oktober 2003 Hallo, Eine Anmerkung noch zum Assembler-Code bei der Umsetzung von strlen(). Viele Archtekturen stellen in ihrem Befehlssatz Instruktionen bereit, die die Abrarbeitung von Strings auf Assembler-Ebene unterstützen. Intel implementiert beispielsweise String-Operationen, die die Suche nach einem Null-Byte innerhalb des Strings zulassen. Damit ist eine 1:1 Abbildung des C-Codes auf eine Assemberinstruktion möglich. Die Schleife sähe dann wie folgt aus: repne scasb [/php] Bei HP siehts ähnlich aus, da hier die Load-Befehle die entsprechende Inizierung/Registermodifikation zum zählen unterstützen: [php] strloop: comib,<>,n 0,%r1,strloop ; Vergleich auf Null-Byte ldbs,mb 1(%r28),%r1 ; nächstes Byte in %r1 Laden bv %r0(%r2) ; Rücksprung zum Aufrufer sub %r28,%r26,%r28 ; Differenz berechnen Man sollte bei einer Umsetzung von strlen in Assember den Befehlssatz nach passenden Instruktionen durchsuchen, um optimale Code zu erhalten. Nic PS: Alle Beispiele ungeachtet der Tatsache, dass die Speicherlatenzen beim Byteweisen Laden die größere Bremse sein können. Das würde jetzt aber ein bisschen zu weit führen Zitieren
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.