String in Integer umwandeln und ausgeben ohne Library
-
okay, ich habe es nochmal versucht zu bearbeiten und langsam Dampft der Kopf
Stringendezeichen eingebaut. Erstmal gedauert, bis ich das verstanden habe.
char meinItoA(int num, char* str) { int i = 0; int teilen; for (i = 0; str[i] != '\0' ;i++){ teilen= num%10; num = num/10; str[i] = teilen+'0'; } return *str; }
unsigned short int meinAtoi(char *string)
return statement außerhalb der for-schleife gepackt. Erst später aufgefallen...
num steht für den Wert, der übergeben wird. Also die Addition der 2 Integerwerte aus der Main.
i steht dafür, damit ich den Array komplett durchlaufe. 0 ++ 1 ++ 2 ++3 ++4 Stelle usw.
Ich tu mich hier echt schwer, langsam nurnoch durchzublicken. C-Buch ist bestellt und hoffe, dass ich damit besser vorran komme.
Was ich einfach nicht verstehe, dass er nur das 2te Zeichen nimmt.
5+6 = 11 eigentlich,
er spuckt mir weiterhin nur 1 aus.
5+7 = 13
er spuckt mir 3 aus.copystring("Addition beider Zahlen ist:\n",string_2); appendstring(string_1, string_2);
wird weiterhin ignoriert.
-
verano123 schrieb:
Stringendezeichen eingebaut. Erstmal gedauert, bis ich das verstanden habe.
char meinItoA(int num, char* str) { int i = 0; int teilen; for (i = 0; str != '\0' ;i++){ teilen= num%10; num = num/10; str[i] = teilen+'0'; } return *str; }
*Nein, du hast das offensichtlich nicht verstanden.
Ein C-String ist ein Array, bei dem die Elemente die Zeichen enthalten.
Das Ende wird durch das Zeichen '\0' (mit dem Wert 0) gekennzeichnet.Wir haben hier Integer TO ASCII: Umwandlung eines Integerwertes in eine Darstellung von Zifferzeichen.
Wenn du einen String selber zusammenbauen willst, dann musst du auch dieses Zeichen selber setzen.
Bei dir wäre das nach der for-Schleife einstr[i] = '\0';
*Deine Umwandlung muss weitergehen, solange num noch einen Wert hat.
num ist der Wert, der umgewandelt werden soll. (es ist hier egal wo der Wert her kommt)
i ist der Index im Array, an dem die gerade berechnete Ziffer steht.
num wird durch das teilen immer kleiner, bis es 0 ist. i wird inkrementiert.
Deren Vergleich ist ziemlich sinnfrei.verano123 schrieb:
Was ich einfach nicht verstehe, dass er nur das 2te Zeichen nimmt.
5+6 = 11 eigentlich,
er spuckt mir weiterhin nur 1 aus.
5+7 = 13
er spuckt mir 3 aus.Das ist nicht das zweite Zeichen, sondern das Letzte.
Arbeite den Algorithmus mal auf einem Blatt Papier durch, dann siehst du, warum das erste Zeichen im String die Einer-Stelle ist.verano123 schrieb:
copystring("Addition beider Zahlen ist:\n",string_2); appendstring(string_1, string_2);
wird weiterhin ignoriert.
Welcher Paramter ist Quelle und welcher Ziel?
Da du ein Stringliteral nicht ändern darfst müsste copystring(Quelle, Ziel) sein.
Bei appendstring auch. D.h das Resultat steht in string_2.In deinem Programm steht aber
putstring (string_1);
.Aber solange meinItoA den string_1 nicht richtig befüllt, kannst du nicht beurteilen, ob das ignoriert wird.
-
putstring
getstring
copystring
appendstringWas sind denn das für Funktionen? Kenn ich nicht von Standard-C.
-
EOP schrieb:
putstring
getstring
copystring
appendstringWas sind denn das für Funktionen? Kenn ich nicht von Standard-C.
Das sind wahrscheinlich gut gemeinte (aber schlecht gemachte) Hilfsfunktionen, die der Lehrer seinen Schülern zur Verfügung gestellt hat. Weil die Standardfunktionen ja so kompliziert sind. Damit sie sich auch ja nicht dran gewöhnen, wie es richtig ginge, und später dann fleißig gets & Co. benutzen, weil es dem entspricht, was sie kennen.
-
So, ich bin nochmal ganz von vorne an die Aufgabe gegangen und habe alles umgeschrieben.
Man, was ein Akt...
Ich habe die itoa Funktion neugeschrieben und umgeändert.
void meinitoa(unsigned short int uwert, char* str) { unsigned short int startwert; unsigned short int i; startwert = uwert; str[0] = ' '; for (i=4; i>=1; i--) { //läuft rückwärts 0000 -> 0001->0002->0003->0004->0005> usw usw usw... //da max. 4 Stellen, kann ich es ab i=4 laufen lassen. // modulo rechnen und 48 bzw '0' von ascii wird addiert. str[i]=(startwert % 10) +'0'; startwert /= 10; } }
Ansich funktioniert der Code jetzt wunderbar. Klar, nicht schön.
12+5 = 0017
5+6 = 0011 usw usw.Nicht Ideal aber es klappt.
Wenn ich jetzt aber Werte über 4 Stellen ( siehe for schleife i=4 ) eingebe, übernimmt er diese. Ändere ich jetzt aber den Rücklaufwert für i auf z.b. 10, berechnet er es komplett ohne Fehler.
Das verstehe ich nicht ganz, wieso er das macht, da ich eigentlich über die beiden Methoden checklength und checknumbers eine Begrenzung drinnen habe.
wenn ich z.b. 10000 eingebe, bittet er mich um eine erneute Eingabe, innerhalb des Wertebereichs aber im Hintergrund übernimmt er die höhere Zahl.
-
Kompletter Code inkl.
`putstring
getstring
copystring
appendstring `
wär mal toll.
-
#ifdef V1_Aufgabe_1 // brauch ich doch nicht mehr, vorsichtshalber da lassen. int eigenestrlen(char *str) { int leng; int i; for (i=0; str[i] != 0; i++) { leng++; } return(leng); } int checknumbers (char* string) { int i; for (i = 0 ; string[i]!='\0';i++) { if (string[i] < '0' || string[i] > '9') { putstring("Bitte erneute eingabe der Zahl: nicht im Zahlenbereich:\n"); return -1; } } return 1; } int checklength (char* string) { int i; for (i = 0;string[i]!='\0';i++){ if (i > 3) { putstring("Bitte erneute eingabe der Zahl: nicht im Zahlenbereich:\n"); return -1; } } return 1; } unsigned short int meinAtoi(char *zahlenstrahl) { unsigned short int i = 0; while(*zahlenstrahl){ i = i*10+(*zahlenstrahl) - '0'; zahlenstrahl ++; } return i; } void meinitoa(unsigned short int uwert, char* str) { unsigned short int startwert; unsigned short int i; startwert = uwert; str[0] = ' '; for (i=4; i>=1; i--) { //läuft rückwärts 0000 -> 0001->0002->0003->0004->0005> usw usw usw... //da max. 4 Stellen, kann ich es ab i=4 laufen lassen. // modulo rechnen und 48 bzw '0' von ascii wird addiert. str[i]=(startwert % 10) +'0'; startwert /= 10; } } void emain() { unsigned short int zahl1; unsigned short int zahl2; unsigned short int result; char string_1[100]; char string_2[100]; INIT_BM_WITHOUT_REGISTER_UI; do { putstring("Bitte 1. Zahl eingeben:\n"); getstring(string_1); } while (checknumbers(string_1)== - 1 || checklength(string_1) == -1); zahl1=meinAtoi(string_1); do { putstring("Bitte 2. Zahl eingeben:\n"); getstring(string_1); } while (checknumbers(string_1)== -1 || checklength(string_1) == -1); zahl2=meinAtoi(string_1); result= zahl1 + zahl2; meinitoa(result,string_1); copystring("Addition beider Zahlen ist:\n",string_2); appendstring(string_1, string_2); putstring (string_2); END; } #endif // V1_Aufgabe_1
Ihr könnt mir glauben, dass die Aufgabe mich an meine nervliche Belastungsgrenze geführt hat ...
Habe zwar Java Vorkenntnisse aber wir fangen in der Uni jetzt mit Mikrocontroller programmierung an und ich versuche mich schonmal in die Aufgaben einzuarbeiten.
Programmiert wird über Qt-Creator mit einem externen .bat Programm, um dort alles einzugeben.
-
Swordfish schrieb:
inkl.
`putstring
getstring
copystring
appendstring`
verano123 schrieb:
void meinitoa(unsigned short int uwert, char* str) { unsigned short int startwert; unsigned short int i; startwert = uwert; str[0] = ' '; for (i=4; i>=1; i--) { //läuft rückwärts 0000 -> 0001->0002->0003->0004->0005> usw usw usw... //da max. 4 Stellen, kann ich es ab i=4 laufen lassen. // modulo rechnen und 48 bzw '0' von ascii wird addiert. str[i]=(startwert % 10) +'0'; startwert /= 10; } }
warum
str[0]=' ';
?
du setzt kein Zeichenkettenende ('\0'
)?
warum4 ... 1
und nicht3 ... 0
? (dann gehört anstr[4]
ein'\0'
)verano123 schrieb:
// ... copystring("Addition beider Zahlen ist:\n",string_2); appendstring(string_1, string_2); putstring (string_2); END; }
Wozu? Du hast doch schon die beiden Zahlen addiert und das Ergebnis steht in
result
(das Du dann permeinitoa(result,string_1);
in Zeile 111 als Zeichenkette instring_1
abgelegt hast), alsostring_1
ausgeben und gut iss?
-
Ich kann da nicht mehr mitlesen
Ich bin zwar kein C Profi, sondern eher Hobbyprogger und habe ein wenig rumgespielt:
#include <stdio.h> #include<string.h> #include<stdlib.h> #include <ctype.h> unsigned long int my_atoi (char *ergebnis) { unsigned long int r=0; int i = sizeof(ergebnis),j,k=1; for (j = i; j >= 0; j--) { r = ((ergebnis[j]-48) * k) + r; k = 10 * k; } return r; } int main(void) { char ergebnis[15]; // unsigned long int zahl; // sprintf (ergebnis,"%s", "987654321"); // Hier musste die Eingabe proggen // zahl = atoi(ergebnis); zahl = my_atoi(ergebnis); printf("%li\n",zahl); return 0; }
Diese Lösung scheint zu funzen..... Jetzt musste nur noch die Eingabe hinbekommen
-
Dein Programm hat mehrere Fehler/Schwächen:
-Fehlende const-correctness.
-Die Längenermittlung in Zeile 8 ist falsch. So geht das nicht in C. Noch einmal angucken, wie das mit den C-Strings und Arrays geht.
-Selbst wenn man die Länge korrekt ermitteln würde, wäre das komplett unnötig, wegen der Natur von C-Strings.
-Magic Numbers.
-Rechnung kann erheblich gekürzt werden und kann ohne Zwischenwerte auskommen.
-Merkwürdige Bezeichnerwahl.ergebnis
?
-
Um dem Elend mal ein Ende zu machen (ungetestet):
unsigned long my_atoi(const char* str) { // Man beachte: Laut Aufgabenstellung nur positive Zahlen ohne Vorzeichen unsigned long value = 0; while(*str) { value *= 10; value += *str++ - '0'; } return value; }
-
Danke.
Aber atoi war ja eigentlich gelöst und die (beiden letzten) Versionen vom TO sind besser als die von Hobbyprogger.
Das Elend ist bei itoa.
-
#include <stddef.h> #include <stdbool.h> bool itoa( char * dst, size_t dst_size, unsigned number ) { unsigned tmp = number; size_t i = 0; do ++i; while( tmp /= 10 ); if( i >= dst_size ) return false; dst[ i-- ] = '\0'; do dst[ i-- ] = '0' + ( number % 10 ); while( number /= 10 ); return true; }
?
// edit: die verf*****
0
!!
-
Bevor jetzt jemand Probleme beim compilieren/linken bekommt:
Mache Compiler liefern eine
itoa
Funktion mit.
Diese gehört aber nicht zum C-Standard (im K&R steht sie aber drin).
Zudem gibt es noch zwei verschiedene Versionen, einmal mit Angabe der Basis und einmal mit fester Basis 10.http://www.cplusplus.com/reference/cstdlib/itoa/
Diese Funktionen werden gerne auf Mikrocontrollern verwendet, wo ein
sprintf
zuviel Platz nimmt.
-
DirkB schrieb:
Zudem gibt es noch zwei verschiedene Versionen, einmal mit Angabe der Basis und einmal mit fester Basis 10.
itoa mit Basisvorgabe 2...16 und C99 konform:
https://www.c-plusplus.net/forum/p2485037#2485037
-
Ich bin beeindruckt von der Lösung von SeppJ. Ich habe das jetzt mal zusammengefasst und mir dann mit dem GCC mit Option -S das Ergebnis angeschaut. Hier der C Code:
#include <stdio.h> #include<string.h> #include<stdlib.h> #include <ctype.h> unsigned long my_atoi2(const char* str) { // Man beachte: Laut Aufgabenstellung nur positive Zahlen ohne Vorzeichen unsigned long value = 0; while(*str) { value *= 10; value += *str++ - '0'; } return value; } unsigned long int my_atoi (char *ergebnis) { unsigned long int r=0; size_t i = sizeof(ergebnis); int j,k=1; for (j = i; j >= 0; j--) { r = ((ergebnis[j]-48) * k) + r; k = 10 * k; } return r; } int main() { char ergebnis[15]; // unsigned long int zahl; // sprintf (ergebnis,"%s", "987654321"); // Hier musste die Eingabe proggen // zahl = atoi(ergebnis); zahl = my_atoi(ergebnis); printf("%li\n",zahl); zahl = my_atoi2(ergebnis); printf("%li\n",zahl); return 0; }
Hier der generierte ASM Code:
.file "c-forum2.c" .text .globl my_atoi2 .type my_atoi2, @function my_atoi2: .LFB2: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movq %rdi, -24(%rbp) movq $0, -8(%rbp) jmp .L2 .L3: movq -8(%rbp), %rdx movq %rdx, %rax salq $2, %rax addq %rdx, %rax addq %rax, %rax movq %rax, -8(%rbp) movq -24(%rbp), %rax leaq 1(%rax), %rdx movq %rdx, -24(%rbp) movzbl (%rax), %eax movsbl %al, %eax subl $48, %eax cltq addq %rax, -8(%rbp) .L2: movq -24(%rbp), %rax movzbl (%rax), %eax testb %al, %al jne .L3 movq -8(%rbp), %rax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE2: .size my_atoi2, .-my_atoi2 .globl my_atoi .type my_atoi, @function my_atoi: .LFB3: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movq %rdi, -40(%rbp) movq $0, -16(%rbp) movq $8, -8(%rbp) movl $1, -20(%rbp) movq -8(%rbp), %rax movl %eax, -24(%rbp) jmp .L6 .L7: movl -24(%rbp), %eax movslq %eax, %rdx movq -40(%rbp), %rax addq %rdx, %rax movzbl (%rax), %eax movsbl %al, %eax subl $48, %eax imull -20(%rbp), %eax cltq addq %rax, -16(%rbp) movl -20(%rbp), %edx movl %edx, %eax sall $2, %eax addl %edx, %eax addl %eax, %eax movl %eax, -20(%rbp) subl $1, -24(%rbp) .L6: cmpl $0, -24(%rbp) jns .L7 movq -16(%rbp), %rax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE3: .size my_atoi, .-my_atoi .section .rodata .LC0: .string "%li\n" .text .globl main .type main, @function main: .LFB4: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $48, %rsp movq %fs:40, %rax movq %rax, -8(%rbp) xorl %eax, %eax leaq -32(%rbp), %rax movabsq $3617292328856139833, %rdx movq %rdx, (%rax) movw $49, 8(%rax) leaq -32(%rbp), %rax movq %rax, %rdi call my_atoi movq %rax, -40(%rbp) movq -40(%rbp), %rax movq %rax, %rsi movl $.LC0, %edi movl $0, %eax call printf leaq -32(%rbp), %rax movq %rax, %rdi call my_atoi2 movq %rax, -40(%rbp) movq -40(%rbp), %rax movq %rax, %rsi movl $.LC0, %edi movl $0, %eax call printf movl $0, %eax movq -8(%rbp), %rcx xorq %fs:40, %rcx je .L11 call __stack_chk_fail .L11: leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE4: .size main, .-main .ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2" .section .note.GNU-stack,"",@progbits
Ich gehe mal davon aus, dass hier Experten sind, die u.U. auch an der Uni lehren und hier mit ihren Stundenten diskutieren und möchte daher jetzt nicht "Klugscheissen" - aber wenn ich den ASM Code von my_atoi und my_atoy2 anschaue, sehe ich da keinen grossen Unterschied... Oder übersehe ich da was?
-
Klar kann der Compiler optimieren, aber trotzdem ist dein
my_atoi
falsch.
Und multipliziern mit 10, subtrahieren der '0' machen beide Funktionen, das wars dann aber auch.Das Reultat vom
sizeof
ist für diesen Zweck völlig ungeeignet.Und probier das Ganze mal mit anderen Werten. Vor allem mit mehr oder weniger als 8 Stellen.
-
DirkB schrieb:
So wie die aufgerufen werden, geht das heutzutage gar nicht mehr, weilsie einen Bufferoverflow generieren können
Ich mag das. Macht mir einen Heidenspaß den Leuten ihre Programme um die Ohren zu hauen. Man hat ja sonst kein Hobby.
-
Hobbyprogger schrieb:
aber wenn ich den ASM Code von my_atoi und my_atoy2 anschaue, sehe ich da keinen grossen Unterschied... Oder übersehe ich da was?
C ist keine wirkliche Hochsprache und schon gar keine Lernsprache.
C-Codes haben naturgemäß die Eigenschaft, sehr umfangreich (viele loc) zu sein, es kommt darauf an, für Verständlichkeit+Wartbarkeit die Übersicht zu behalten und dafür sind kurze Codes von Vorteil (natürlich im normalen Rahmen und nicht obfuscated).Hobbyprogger schrieb:
Ich gehe mal davon aus, dass hier Experten sind, die u.U. auch an der Uni lehren
lol
"Experte" + "an der Uni" schließen sich gegenseitig aus.
-
EOP schrieb:
DirkB schrieb:
So wie die aufgerufen werden, geht das heutzutage gar nicht mehr, weilsie einen Bufferoverflow generieren können
Ich mag das. Macht mir einen Heidenspaß den Leuten ihre Programme um die Ohren zu hauen. Man hat ja sonst kein Hobby.
Die von mir bemängelten Funktionen wurden dem TO vorgegeben.
Der Teil ist also nicht sein Programm, sondern der vom Professor/Tutor/Lehrer.Wutz schrieb:
"Experte" + "an der Uni" schließen sich gegenseitig aus.