Lowlevel

Lowlevel => Lowlevel-Coding => Thema gestartet von: Cool-Andy am 17. October 2009, 19:43

Titel: char nach int umwandeln
Beitrag von: Cool-Andy am 17. October 2009, 19:43
Hallo nochmal,
ich hätte da nochmal ne wahrscheinlich ziemlich dumme Anfängerfrage:
wie kann man mit möglichst Standard-C-Funktionen einen char-String in eine int-Zahl umwandeln?
Titel: Re: char nach int umwandeln
Beitrag von: erik.vikinger am 17. October 2009, 19:59
Hallo,


wenn Du ein char[] mit z.B. "123" meinst dann ist 'sscanf()' Dein Freund.


Grüße
Erik
Titel: Re: char nach int umwandeln
Beitrag von: Cool-Andy am 17. October 2009, 20:03
Und wie implentier ich die in mein OS?  :?
Titel: Re: char nach int umwandeln
Beitrag von: erik.vikinger am 17. October 2009, 20:11
Hallo,


"Standard-C-Funktionen" sind in der Standard-C-Bibliothek. Wenn Du die nicht in Deinen Kernel mit reinlinken möchtest, was auch nicht empfehlenswert ist, dann schau Dich mal beim Linux-Kernel um die haben eine abgespeckte Fassung (sscanf unterstützt z.B. keine Gleitkommazahlen) aus der Du bestimmt alles benötigte herrausfiletieren kannst.


Grüße
Erik
Titel: Re: char nach int umwandeln
Beitrag von: Tobiking am 17. October 2009, 20:17
atoi() währe wohl die direkte Funktion wenn du die hättest.

Und wie implentier ich die in mein OS?  :?
Ich würde Zeichen für Zeichen einlesen, die entsprechende Ziffer finden und dann die Ziffern zusammensetzen. So nach dem Motto "1234" ist 1*1000+2*100+3*10+4*1.
Titel: Re: char nach int umwandeln
Beitrag von: Jidder am 17. October 2009, 20:21
Von sscanf würde ich abraten solange man sich solche Fragen stellt.

Einfacher ist atoi:

1. Setze Variable x auf 0
2. Zeichen einlesen
3. Zeichen von ASCII in den Wert der Stelle umwandeln
4. x <- x * 10 + Wert aus 3.
5. Wenn noch nicht am Ende -> gehe zu 2.
6. Gib x zurück.
Titel: Re: char nach int umwandeln
Beitrag von: kevin am 17. October 2009, 20:23
strtol() ist noch besser. Muss aber auch erst implementiert werden. ;)

Der Ansatz von Tobiking dürfte dich schnell zum Ziel führen. Ein einzelnes Zeichen (von dem du weißt, dass es eine Ziffer ist) wandelst du am geschicktesten mit c - '0' in eine Zahl um.
Titel: Re: char nach int umwandeln
Beitrag von: Cool-Andy am 17. October 2009, 20:58
Vielen Danke für die Antworten,
aber die von PorkChicken hab ich noch nich so wirklich verstanden, könntest du mal ein Stück Code posten (ich denke, Pseudocode würde reichen).

Titel: Re: char nach int umwandeln
Beitrag von: Jidder am 17. October 2009, 21:23
Das war ja im prinzip Pseudocode ;)

Aber hier mal als ungetestes C-Schnipsel, und in den Kommentaren die Bezüge zum Pseudocode:
int atoi(const char *str)
{
    int x = 0; // der Wert // (1.)
    int d; // eine Ziffer

    while (*str) {
        d = *str - '0'; // (2.) + (3.)
        x = x * 10 + d; // (4.)
        str++;
    }

    return x; // (6.)
}
Der Punkt (5.) ist schwer in diesem Code unterzubringen, aber entspricht wohl am ehesten der while-Schleife.

Da fehlt jetzt natürlich die Verarbeitung von negativen Zahlen ;)
Titel: Re: char nach int umwandeln
Beitrag von: Cool-Andy am 17. October 2009, 22:11
OK,
vielen Dank. Könntest du mir auch noch sagen, wie man wieder von int nach char umwandelt. (Bitte nicht wundern, hab bis jetzt noch nie ints und chars umwandeln müssen.)
Titel: Re: char nach int umwandeln
Beitrag von: kevin am 17. October 2009, 22:17
Du teilst die Zahl immer wieder durch 10, der Rest gibt jeweils genau die letzte Ziffer. Folgender Pseudocode gibt die Zahl also rückwärts aus, das Umdrehen überlasse ich dir. ;)

while n > 0 do
  putc('0' + (n % 10));
  n := n / 10;
od
Titel: Re: char nach int umwandeln
Beitrag von: Cool-Andy am 17. October 2009, 22:22
OK, vielen Dank, werd ich gleich mal ausprobieren.
Titel: Re: char nach int umwandeln
Beitrag von: Cool-Andy am 18. October 2009, 08:16
Ich cheks net, entweder bei mir kommt nur Müll raus (Zeichen wie sowas: █), oder es kommt gar nix.
Könntest du bitte mal einen C-Code posten?
Ich denke, es wäre eine große Hilfe für mich.  :mrgreen:
Titel: Re: char nach int umwandeln
Beitrag von: erik.vikinger am 18. October 2009, 09:00
Hallo,


int itostr(char* const str, int zahl)
{
    if (zahl == 0)
      { *str = '0'; return 1; } //bei 0 nur "0" zurückgeben

    int i = 0; //String-Länge

    while (zahl > 0) { //Loop solange bis Zahl 0 ist
        const int rest = zahl % 10;
        zahl = zahl / 10;
        str[i++] = ((char)rest) + '0';
    }

    return i; //Länge des Strings zurückgeben
}
Da fehlt auch wieder die Behandlung negativer Zahlen aber ansonsten sollte das funktionieren.


Grüße
Erik
Titel: Re: char nach int umwandeln
Beitrag von: Cool-Andy am 18. October 2009, 10:18
Ok,
hab die Funktion übernommen, aber irgendwie funzts net.
Ich poste mal meinen Code:
string.c:
// ...
int atoi(const char *str)
{
    int x = 0; // der Wert // (1.)
    int d; // eine Ziffer

    while (*str) {
        d = *str - '0'; // (2.) + (3.)
        x = x * 10 + d; // (4.)
        str++;
    }

    return x; // (6.)
}

int itoa(int zahl)
{
    if (zahl == 0)
    {
key[0] = '0';
key[1] = '\0';
return 1;
} //bei 0 nur "0" zurückgeben

    int i = 0; //String-Länge

    while (zahl > 0) { //Loop solange bis Zahl 0 ist
        const int rest = zahl % 10;
        zahl = zahl / 10;
        key[i++] = ((char)rest) + '0';
    }

key[i] = '\0';

    return i; //Länge des Strings zurückgeben
}

und main.c:
// ...
i = 0;
printf ("\n");
printf ("1: ");
scanf ();
i = atoi(key);
itoa(i);
printf (key);
printf ("\n");
// ...

Wobei "key" eine 80-Zeichen lange char-Variable ist, und für den Austausch von Zeichen gedacht ist (und auch Zeichen von der Tastatur entgegen nimmt).

Erkennt ihr den Fehler? Ich bin echt ratlos!  :?
Titel: Re: char nach int umwandeln
Beitrag von: erik.vikinger am 18. October 2009, 10:31
Hallo,


Zitat
aber irgendwie funzts net
Kannst Du das etwas konkreter ausdrücken?
Baue den Code einfach mal in ein normales Programm auf deinem Entwicklungsrechner ein und nimm einen Debugger, vielleicht findest Du dann den Fehler.


Grüße
Erik
Titel: Re: char nach int umwandeln
Beitrag von: Cool-Andy am 18. October 2009, 10:49
Kannst Du das etwas konkreter ausdrücken?
Wenn eine Zahl unterhalb 4 eingegeben wird, erscheint überhaupt keine Ausgabe. Bei jeder anderen Zahl erscheint eine wirre Zahlenfolge.

Baue den Code einfach mal in ein normales Programm auf deinem Entwicklungsrechner ein und nimm einen Debugger, vielleicht findest Du dann den Fehler.
Ok, hab ich gemacht. Ich hab die Funktionen in ein Windows-Programm gepackt und siehe da funktionierts, was mich eigentlich noch ratloser macht!
Titel: Re: char nach int umwandeln
Beitrag von: erik.vikinger am 18. October 2009, 12:50
Hallo,


Zitat
Wenn eine Zahl unterhalb 4 eingegeben wird, erscheint überhaupt keine Ausgabe. Bei jeder anderen Zahl erscheint eine wirre Zahlenfolge.
Kann es vielleicht sein das etwas mit der Parameterübergabe beim Funktionsaufruf nicht passt? Ist nur so ne Idee.

Zitat
... was mich eigentlich noch ratloser macht!
Das ist sehr merkwürdig. Ich schätze da wirst Du nicht drumrum kommen das ganze in kleine Häppchen zu zerlegen und alles einzeln testen bis Du die schuldige Code-Stelle gefunden hast. Hast Du schon mal den Debugger von Bochs probiert? Als erstes solltest Du IMHO probieren das Int-2-String klappt, dafür nimmst Du am besten hartcodierte Int-Werte.

Probiere mal d = *str - '0';gegend = ((int)(*strr)) & 0x0F;undkey[i++] = ((char)rest) + '0';gegenkey[i++] = (char)(rest - 0x30);zu ersetzen, eventuell hast Du ein Problem mit dem Zeichensatz.
Ansonsten solltest Du eine Fehlermeldung einbauen wenn 'rest' nicht im Wertebereich 0...9 ist. So in der Art :if ( (rest < 0) || (rest > 9) ) { printf("Error!!"); }
Viel mehr fällt mir momentan auch nicht ein.


Viel Spaß :wink:
Erik
Titel: Re: char nach int umwandeln
Beitrag von: Cool-Andy am 18. October 2009, 17:29
Hmm, ich find den Fehler nicht!  :-(
Ich hab mich entschieden, die Funktion aufzuschieben, um an meinem OS weiterzukommen, vielleicht findet ja einer von euch noch den Fehler.
Vielen Dank jeden Falls.
Titel: Re: char nach int umwandeln
Beitrag von: Cjreek am 22. October 2009, 21:15
Naja an so etwas sollte man eigentlich nicht verzweifeln (müssen).

Zuerst den kompletten Code den du für diese Funktion geschrieben hast wegwerfen, damit du nicht beeinflusst wirst. Du fängst jetzt ganz von vorne an.

Guck mal. Nehmen wir mal die Zahl 12345.

durch 10 teilen:
1234 R 5
durch 10 teilen
123 R 4
durch 10 teilen
12 R 3
durch 10 teilen
1 R 2
durch 10 teilen
0 R 1

*) R = Rest

Wie du siehst ergeben die unterstrichenen Zahlen von unten nach oben gelesen deine ursprüngliche Zahl.

Was haben wir also gemacht?

1) Wir haben die Zahl genommen die wir umwandeln wollten und solange durch 10 geteilt bis das Ergebnis 0 war.
2) Wir haben jeweils den Rest jeder Division genommen und ihn in einen Char umgewandelt.

Wie macht man das? Nunja..

Die "0" hat den Ascii-Code 0x30
die "1" 0x31, die "2" 0x32 usw.

Wir können also einfach 0x30+R rechnen und haben dann den Ascii-Code der aktuellen Ziffer (R = der Rest der aktuellen Division)

den AsciiCode in einen Char umwandeln kannst du durch

(char)code
also in unserem Fall:

(char)(0x30+R)
3) Von hinten nach vorne gelesen ergeben diese Chars dann die gewünschte Zahl als String.

Wenn du dir das mal so durchgehst und evtl auch mal auf nem Blatt ausprobierst, dann schreibt sich der Code fast von alleine ;)

Lg
Cjreek
Titel: Re: char nach int umwandeln
Beitrag von: Cool-Andy am 23. October 2009, 06:44
Danke, dass du das Thema ausgegraben hast.
Könntest du bitte den Code posten, wie du es dir gedacht hast?
Weil, ich versuch es grad mit einer while-Schleife
...
while (zahl != 0)
{
...
und des funzt net.
Wäre wirklich sehr nett von dir!
 :-)
Titel: Re: char nach int umwandeln
Beitrag von: kevin am 23. October 2009, 09:59
Wenn genau derselbe Code unter Linux/Windows funktioniert und in deinem Kernel nicht, würde ich nicht an der Funktion zweifeln, sondern am Code drum herum, zum Beispiel der Ausgabe. Wenn du überhaupt nicht weiterkommst, lad halt nochmal irgendwo deinen kompletten Code hoch, damit es jemand selber ausprobieren kann.
Titel: Re: char nach int umwandeln
Beitrag von: Cool-Andy am 23. October 2009, 12:52
Wenn ich unter Windows debugge bricht die Anwendung in der Umwandlung von int nach char ab!
Titel: Re: char nach int umwandeln
Beitrag von: Cool-Andy am 23. October 2009, 13:38
OK, meine "int to char"-Funktion:
void itoc (int value)
{
    int rest = 0;
    char letter[1];
    char string[100];
    int i = 0;
    int z;
    while (value != 0)
    {
        rest = value%10;
        letter[0] = (char) (0x30+rest);
        string[i] = letter[0];
z = value/10;
        i++;
    }
    i++;
    string[i] = '\0';
    printf ("x: ");
    printf (string);
}

Wenn ich diese Funktion starte, bleibt der Bildschirm schwarz!  :?

EDIT:
Ich hab mein Fehler schon selber gefunden. Hier mal mein geupdateter Code:
void itoc (int value)
{
int rest = 0;
    char letter[1];
    char string[100];
    int i = 0;
int z;
    while (value != 0)
    {
        rest = value%10;
        letter[0] = (char) (0x30+rest);
        string[i] = letter[0];
z = value/10;
value = z;
        i++;
    }
    i++;
    string[i] = '\0';
printf ("x: ");
    printf (string);
}

Hat jemand jetzt noch ne Idee, wie ich den String umdrehen kann?  :-D
Titel: Re: char nach int umwandeln
Beitrag von: erik.vikinger am 23. October 2009, 14:09
Hallo,


void rotate_str(char* const text,const int length)
{
  //bei Länge 1 oder 0 nichts machen :
  if (length < 2) { return; }

  //Indices um von vorne und hinten bis zur Mitte zu arbeiten :
  int low = 0;
  int high = length - 1;

  while (low < high)
   {
     //Zeichen vertauschen :
     char ctemp = text[low]; text[low] = text[high]; text[high] = ctemp;
     //Indices weiterschieben :
     low++; high--;
   }
}
'length' natürlich ohne das 0-Byte am Text-Ende, wie immer alles ohne Gewähr :wink:
Sollte aber klappen.


Grüße
Erik
Titel: Re: char nach int umwandeln
Beitrag von: kevin am 23. October 2009, 14:20
void reverse_string(char* s)
{
    char* p;
    for (p = s + strlen(s) - 1; *s && p > s; *p ^= *s, *s ^= *p, *p-- ^= *s++);
}
Tut mir leid, ich konnte nicht anders. :-D
Titel: Re: char nach int umwandeln
Beitrag von: Cool-Andy am 23. October 2009, 14:44
Tut mir leid, ich konnte nicht anders. :-D
Was auch immer mir damit sagen wolltest, die Funktion von erik.vikinger hat funktioniert.

Vielen Dank!  :-D
Titel: Re: char nach int umwandeln
Beitrag von: kevin am 23. October 2009, 14:54
Meine funktioniert auch, aber ich würde sie aus dem offensichtlichen Grund der Nichtoffensichtlichkeit nirgends so einbauen. ;)
Titel: Re: char nach int umwandeln
Beitrag von: Cool-Andy am 23. October 2009, 15:06
Aja, OK!  :mrgreen:
Titel: Re: char nach int umwandeln
Beitrag von: erik.vikinger am 23. October 2009, 15:20
Hallo,


Zitat
Tut mir leid, ich konnte nicht anders. :-D
Dieses Gefühl kenne ich nur zu gut. Aber in diesem konkreten Fall hättest Du der Versuchung ruhig widerstehen dürfen. Sowas würde ich ja schon fast in die Kategorie "Human-Code-Obfuscator" einsortieren.

In meiner Variante würde ich noch zwei Korrekturen vornehmen:
 //bei Null-Pointer oder Länge 1 oder 0 nichts machen :
  if ( (text == NULL) || (length < 2) ) { return; }
    //Zeichen vertauschen :
     const char ctemp = text[low]; text[low] = text[high]; text[high] = ctemp;
Die erste Korrektur ist sicher offensichtlich (hat taljeth in seiner Variante auch drin) und die zweite sagt das 'ctemp' nicht verändert werden darf (alternativ kann man auch 'register' anstatt 'const' nehmen um etwas mehr Performance zu bekommen, ein guter Compiler sollte das aber selber sehen).
Achja, generell 'unsigned int' anstatt 'int' währe dem Problem angemessener da Strings üblicherweise keine negative Länge haben.

EDIT: den Funktions-Namen von taljeth finde ich besser.


Grüße
Erik
Titel: Re: char nach int umwandeln
Beitrag von: kevin am 23. October 2009, 15:30
Die erste Korrektur ist sicher offensichtlich (hat taljeth in seiner Variante auch drin)
Nein, wenn sie NULL kriegt, segfaultet meine Funktion, ganz im Sinne der klassischen C-Stringfunktionen. Schon bei der Initialisierung von p (im strlen), aber auch die for-Bedingung wäre dafür falschrum geschrieben.
Titel: Re: char nach int umwandeln
Beitrag von: erik.vikinger am 23. October 2009, 16:36
Hallo,


Zitat
aber auch die for-Bedingung wäre dafür falschrum geschrieben.
Stimmt, jetzt hab ichs gesehen.; *s && p > s;Mit dem '*s' prüfst Du ja das s nicht auf ein 0-Byte zeigt (und nicht das s kein Null-Pointer ist), was eigentlich nicht passieren dürfte da s ja nur bis zur Hälfte durch den String wandert und bei einem leeren String sollte 'p > s' für einen Schleifen-Abbruch sorgen.

Zitat
ganz im Sinne der klassischen C-Stringfunktionen
Aha, wusste ich nicht. Wenn eine C++ Library eine Exception wirft ist das ja in Ordnung, die Exception kann man fangen oder eben nicht, aber den ganzen Prozess vom OS killen zu lassen find ich nicht gut und ein Signal-Handler im User-Programm kann IMHO nicht so viel ausrichten da er kaum rauskriegt wo im Code das Problem entstand und erst recht nicht das Programm sinnvoll weiterlaufen lassen kann.

Zitat
wenn sie NULL kriegt, segfaultet meine Funktion
Woher kommt eigentlich "segfault"? Gab es mal ein UNIX das Segmentierung unterstützt hat? Da ja in Wirklichkeit ein Pagefault (die 0te Page lässt man ja extra dafür immer ungemappt) dahinter steckt find ich den Namen irgendwie unpassend.


@Cool-Andy : sorry für meine OT-Frage aber ich gehe davon aus das Dein eigentliches Problem von diesem Thread gelöst ist.


Grüße
Erik
Titel: Re: char nach int umwandeln
Beitrag von: kevin am 23. October 2009, 16:49
Mit dem '*s' prüfst Du ja das s nicht auf ein 0-Byte zeigt (und nicht das s kein Null-Pointer ist), was eigentlich nicht passieren dürfte da s ja nur bis zur Hälfte durch den String wandert und bei einem leeren String sollte 'p > s' für einen Schleifen-Abbruch sorgen.
Stimmt, das ist Blödsinn. Gedacht war es für den leeren String.

Zitat
Aha, wusste ich nicht. Wenn eine C++ Library eine Exception wirft ist das ja in Ordnung, die Exception kann man fangen oder eben nicht, aber den ganzen Prozess vom OS killen zu lassen find ich nicht gut und ein Signal-Handler im User-Programm kann IMHO nicht so viel ausrichten da er kaum rauskriegt wo im Code das Problem entstand und erst recht nicht das Programm sinnvoll weiterlaufen lassen kann.
Man übergibt den Stringfunktionen eben keine Nullpointer. ;)

Ich hab jetzt keine großartige Lust, damit rumzuspielen, aber theoretisch müsste der Signalhandler die Codestelle schon rauskriegen, das sollte ja seine eigene Rücksprungadresse sein. Ob man damit was sinnvolles anstellen kann, ist die andere Frage. Wahrscheinlich könnte man mit setjmp/longjmp eher ein Exceptionhandling aufbauen und bräuchte dann die Adresse vom Fault überhaupt nicht.

Zitat
Woher kommt eigentlich "segfault"? Gab es mal ein UNIX das Segmentierung unterstützt hat? Da ja in Wirklichkeit ein Pagefault (die 0te Page lässt man ja extra dafür immer ungemappt) dahinter steckt find ich den Namen irgendwie unpassend.
Wird wohl so sein, aber ich kann dir nicht sagen, welche Unixe das waren.

Wikipedia sagt: "Die englische Bezeichnung segmentation fault stammt aus einer Zeit, in der Speicherbereiche durch Segmentierung vor unerlaubtem Zugriff geschützt wurden. Heute werden andere Schutzmechanismen verwendet, insbesondere Paging; der Terminus segmentation fault hat sich aber unverändert erhalten."
Titel: Re: char nach int umwandeln
Beitrag von: erik.vikinger am 24. October 2009, 20:38
Hallo,


Zitat
Man übergibt den Stringfunktionen eben keine Nullpointer. :wink:
Ah ja, das ist natürlich richtig. Trotzdem könnte z.B. strlen() -1 zurückliefern, würde ich zumindest als nett einstufen.
Meine Frage ziehlte aber eher darauf ab ob das so definiert ist das die Standard-Funktionen eben nicht selber auf einen NULL-Pointer prüfen sollen. Es könnte ja auch eine Plattform geben wo NULL-Pointer nicht zu einer (CPU-)Exception führen.

Zitat
.... Ob man damit was sinnvolles anstellen kann, ist die andere Frage.
Es währe auf jeden Fall mit erheblicher Arbeit für den Programmierer verbunden, dann sollte man doch lieber zu C++ wechseln und diese Arbeit dem Compiler überlassen.

Zitat
".... der Terminus segmentation fault hat sich aber unverändert erhalten."
Na dann wird es ja Zeit das er auf meiner Plattform wieder zu altem Ruhm aufsteigt. :wink:
Jedenfalls hab ich extra dafür jedem Segment nicht nur ein Limit sondern auch ein Minimum angedacht, somit ist das Offset 0 (falls das OS die Segmente so einrichtet) nicht nutzbar und löst einen segfault aus. Den Selector 0 lehnt die CPU ebenfalls ab.
Das Minimum möchte ich nun aber auch benutzen um nicht Speicher am Anfang der Segmente zu verschwenden falls ich mal ASLR implementieren sollte.


Grüße
Erik
Titel: Re: char nach int umwandeln
Beitrag von: kevin am 24. October 2009, 21:07
Ah ja, das ist natürlich richtig. Trotzdem könnte z.B. strlen() -1 zurückliefern, würde ich zumindest als nett einstufen.
Um ein bisschen Erbsen zu zählen: strlen gibt einen size_t zurück, also kann es kein -1 liefern. Aber ja, natürlich hätte man das so definieren können, dass es irgendeine Form von Fehlerbehandlung macht (allerdings bringt der Test auf NULL auch nicht so viel, im Zweifelsfall steckt das Ding in einer struct und hat ein Offset von NULL) - hat man aber eben nicht.

Zitat
Meine Frage ziehlte aber eher darauf ab ob das so definiert ist das die Standard-Funktionen eben nicht selber auf einen NULL-Pointer prüfen sollen. Es könnte ja auch eine Plattform geben wo NULL-Pointer nicht zu einer (CPU-)Exception führen.
Es ist nicht so definiert, dass sie es nicht prüfen dürfen oder dass sie eine Exception werfen sollen. Für strlen selber ist überhaupt kein Fehlerfall definiert, das Dereferenzieren eines Nullpointers ist explizit undefiniert. Mit strlen(NULL) kann das jeweilige System also machen, was ihm gerade in den Kram passt.