sprintf c atoi atof

sprintf - Implementación de ATOI en C



itoa c (5)

Aquí está mi implementación (probada con éxito en casos que contienen y comienzan con letras, +, - y cero). Intenté realizar ingeniería inversa de la función atoi en Visual Studio . Si la cadena de entrada solo contenía caracteres numéricos, podría implementarse en un bucle. pero se complica porque debes cuidar - , + y las letras.

int atoi(char *s) { int c=1, a=0, sign, start, end, base=1; //Determine if the number is negative or positive if (s[0] == ''-'') sign = -1; else if (s[0] <= ''9'' && s[0] >= ''0'') sign = 1; else if (s[0] == ''+'') sign = 2; //No further processing if it starts with a letter else return 0; //Scanning the string to find the position of the last consecutive number while (s[c] != ''/n'' && s[c] <= ''9'' && s[c] >= ''0'') c++; //Index of the last consecutive number from beginning start = c - 1; //Based on sign, index of the 1st number is set if (sign==-1) end = 1; else if (sign==1) end = 0; //When it starts with +, it is actually positive but with a different index //for the 1st number else { end = 1; sign = 1; } //This the main loop of algorithm which generates the absolute value of the //number from consecutive numerical characters. for (int i = start; i >=end ; i--) { a += (s[i]-''0'') * base; base *= 10; } //The correct sign of generated absolute value is applied return sign*a; }

No puedo entender el siguiente código de implementación atoi , específicamente esta línea: k = (k<<3)+(k<<1)+(*p)-''0'';

El código:

int my_atoi(char *p) { int k = 0; while (*p) { k = (k<<3)+(k<<1)+(*p)-''0''; p++; } return k; }

Alguien puede explicar me lo ?

Otra pregunta: ¿cuál debería ser el algoritmo de implementación?


Curiosamente, la página del manual para atoi no indica la configuración de errno, por lo que si está hablando cualquier número> (2 ^ 31) -1, no tiene suerte y de manera similar para números menores a -2 ^ 31 (suponiendo 32 -bit int). Recibirás una respuesta pero no será lo que quieres. Aquí hay uno que podría tomar un rango de - ((2 ^ 31) -1) a (2 ^ 31) -1, y devolver INT_MIN (- (2 ^ 31)) si hay un error. errno podría entonces verificarse para ver si se desbordó.

#include <stdio.h> #include <errno.h> /* for errno */ #include <limits.h> /* for INT_MIN */ #include <string.h> /* for strerror */ extern int errno; int debug=0; int atoi(const char *c) { int previous_result=0, result=0; int multiplier=1; if (debug) printf("converting %s to integer/n",c?c:""); if (c && *c == ''-'') { multiplier = -1; c++; } else { multiplier = 1; } if (debug) printf("multiplier = %d/n",multiplier); while (*c) { if (*c < ''0'' || *c > ''9'') { return result * multiplier; } result *= 10; if (result < previous_result) { if (debug) printf("number overflowed - return INT_MIN, errno=%d/n",errno); errno = EOVERFLOW; return(INT_MIN); } else { previous_result *= 10; } if (debug) printf("%c/n",*c); result += *c - ''0''; if (result < previous_result) { if (debug) printf("number overflowed - return MIN_INT/n"); errno = EOVERFLOW; return(INT_MIN); } else { previous_result += *c - ''0''; } c++; } return(result * multiplier); } int main(int argc,char **argv) { int result; printf("INT_MIN=%d will be output when number too high or too low, and errno set/n",INT_MIN); printf("string=%s, int=%d/n","563",atoi("563")); printf("string=%s, int=%d/n","-563",atoi("-563")); printf("string=%s, int=%d/n","-5a3",atoi("-5a3")); if (argc > 1) { result=atoi(argv[1]); printf("atoi(%s)=%d %s",argv[1],result,(result==INT_MIN)?", errno=":"",errno,strerror(errno)); if (errno) printf("%d - %s/n",errno,strerror(errno)); else printf("/n"); } return(errno); }


<< es bit shift, (k<<3)+(k<<1) es k*10 , escrito por alguien que, aunque es más listo que un compilador (bueno, estaba equivocado ...)

(*p) - ''0'' es restar 0 del carácter señalado por p , convirtiendo efectivamente el carácter en un número.

Espero que puedas descubrir el resto ... solo recuerda cómo funciona el sistema decimal.

Tenga en cuenta que se trata de una implementación estándar de atoi . Lo siento por no citar el estándar, pero esto funcionará igual de bien (de: http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/ )

La función primero descarta tantos caracteres de espacio en blanco (como en espacio de emisión) según sea necesario hasta que se encuentre el primer carácter que no sea de espacio en blanco. Luego, a partir de este carácter, toma un signo de más o menos inicial opcional seguido de tantos dígitos de base-10 como sea posible, y los interpreta como un valor numérico.

La cadena puede contener caracteres adicionales después de los que forman el número integral, que se ignoran y no tienen ningún efecto en el comportamiento de esta función.

Si la primera secuencia de caracteres que no son espacios en blanco en str no es un número integral válido, o si no existe tal secuencia porque cualquiera de los str está vacío o contiene solo caracteres de espacios en blanco, no se realiza ninguna conversión y se devuelve cero.


#include <stdio.h> #include <errno.h> #include <limits.h> double atof(const char *string); int debug=1; int main(int argc, char **argv) { char *str1="3.14159",*str2="3",*str3="0.707106",*str4="-5.2"; double f1,f2,f3,f4; if (debug) printf("convert %s, %s, %s, %s/n",str1,str2,str3,str4); f1=atof(str1); f2=atof(str2); f3=atof(str3); f4=atof(str4); if (debug) printf("converted values=%f, %f, %f, %f/n",f1,f2,f3,f4); if (argc > 1) { printf("string %s is floating point %f/n",argv[1],atof(argv[1])); } } double atof(const char *string) { double result=0.0; double multiplier=1; double divisor=1.0; int integer_portion=0; if (!string) return result; integer_portion=atoi(string); result = (double)integer_portion; if (debug) printf("so far %s looks like %f/n",string,result); /* capture whether string is negative, don''t use "result" as it could be 0 */ if (*string == ''-'') { result *= -1; /* won''t care if it was 0 in integer portion */ multiplier = -1; } while (*string && (*string != ''.'')) { string++; } if (debug) printf("fractional part=%s/n",string); // if we haven''t hit end of string, go past the decimal point if (*string) { string++; if (debug) printf("first char after decimal=%c/n",*string); } while (*string) { if (*string < ''0'' || *string > ''9'') return result; divisor *= 10.0; result += (double)(*string - ''0'')/divisor; if (debug) printf("result so far=%f/n",result); string++; } return result*multiplier; }


k = (k << 3) + (k << 1);

medio

k = k * 2³ + k * 2¹ = k * 8 + k * 2 = k * 10

¿Eso ayuda?

El término *p - ''0'' agrega el valor del siguiente dígito; esto funciona porque C requiere que los caracteres de los dígitos tengan valores consecutivos, de modo que ''1'' == ''0'' + 1 , ''2'' == ''0'' + 2 , etc.

En cuanto a tu segunda pregunta ( atof ), esa debería ser su propia pregunta, y es el tema de una tesis, no algo simple de responder ...