Zum Inhalt springen

strlen nachprogrammieren


Empfohlene Beiträge

Geschrieben

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.

Geschrieben

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?

Geschrieben

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...

Geschrieben

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?

Geschrieben

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*

Geschrieben

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?

Geschrieben

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

Geschrieben

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. :D

Geschrieben
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.

Geschrieben

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

Geschrieben
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.

Geschrieben
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. :D

Geschrieben

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

Geschrieben

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 ;)

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.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...