atol - ¿Cómo funciona atoi() en C++?
string to int c++ (6)
Entonces ... Sé que la función atoi en la biblioteca estándar de C ++ se supone que convierte una cadena en un entero ... ¿Cómo funciona? ... (Estoy tratando de aprender cosas y me estaba preguntando). ... si pudiera mostrarme el código o hacer uno propio que hiciera la misma tarea, sería muy apreciado ... gracias de antemano.
Algo como esto:
int atoi( const char *c ) {
int value = 0;
int sign = 1;
if( *c == ''+'' || *c == ''-'' ) {
if( *c == ''-'' ) sign = -1;
c++;
}
while ( isdigit( *c ) ) {
value *= 10;
value += (int) (*c-''0'');
c++;
}
return value * sign;
}
Recorre los caracteres de la cadena en tanto que sean dígitos. Para cada uno, agregue al contador que mantiene: el valor a agregar es el valor entero del carácter. Esto se hace restando el valor ascii de ''0'' del valor ascii del dígito en cuestión.
Tenga en cuenta que este código no controla el desbordamiento. Si pasa "887452834572834928347578423485273" (que no cabe en un int
), el resultado no está definido.
Aquí hay una implementación que también comprueba las condiciones de error y funciona para cualquier tipo de entero.
#include <limits>
#include <string>
#include <cctype>
#include <cassert>
#include <type_traits>
template<typename TChar, typename TNumber> bool my_atoi(const std::basic_string<TChar>& str, TNumber& result)
{
typedef std::make_unsigned<TNumber>::type TNumberUnsigned;
// check if result type is integer
assert(std::numeric_limits<TNumber>::is_integer);
auto currChar = str.cbegin();
// use corresponding unsigned type to accumulate number to avoid overflows for numbers such as -128
TNumberUnsigned number = 0;
bool isNegative = *currChar == ''-'';
if (isNegative) {
// negative numebers can only be parsed into signed types
if (!std::numeric_limits<TNumber>::is_signed)
return false;
++currChar;
}
// empty string or string containing just - sign are not valid integers
if (currChar == str.cend())
return false;
while (currChar != str.cend()) {
auto digit = *currChar - ''0'';
// check that the next digit is valid
if (digit < 0 || digit > 9)
return false;
// check for overflow
if (number > std::numeric_limits<TNumberUnsigned>::max() / 10)
return false;
number *= 10;
// check for overflow
if (number > std::numeric_limits<TNumberUnsigned>::max() - digit)
return false;
number += digit;
++currChar;
}
if (isNegative) {
// correctly check for negative overflow (-128)
if (number > static_cast<TNumberUnsigned>(std::numeric_limits<TNumber>::max()) + 1)
return false;
result = static_cast<TNumber>(-1 * number);
}
else {
if (number > static_cast<TNumberUnsigned>(std::numeric_limits<TNumber>::max()))
return false;
result = static_cast<TNumber>(number);
}
return true;
}
Básicamente, restando el ASCII cero (''0'') y verificando si es un dígito o no . Necesitas saber la posición:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int atoi( const char* nptr )
{
int result = 0;
int position = 1;
const char* p = nptr;
while( *p )
{
++p;
}
for( --p; p >= nptr; p-- )
{
if( *p < 0x30 || *p > 0x39 )
{
break;
}
else
{
result += (position) * (*p - 0x30);
position *= 10;
}
}
result = ((nptr[0] == ''-'')? -result : result);
return result;
}
int main()
{
char buffer[BUFSIZ] = {0};
printf( "Enter an integer: " );
fgets( buffer, BUFSIZ, stdin );
buffer[strlen(buffer)-1] = 0;
printf( "You entered %d/n", atoi( buffer ) );
return 0;
}
Dígito a dígito:
Un char *
, estrictamente hablando, es un puntero a un char
. Un puntero es solo una dirección a algún lugar en la memoria. En C / C ++ (y Java), las cadenas se componen de caracteres que, individualmente, pueden tratarse como números enteros (generalmente un byte), gracias a ASCII .
En C (y C ++), un puntero a un elemento de algún tipo es lo mismo que un puntero a una matriz de elementos de ese tipo. Las cadenas en C pura son solo matrices de caracteres, con un ''/0''
(NUL) al final para que sepa cuándo ha tocado el final de una cadena sin tener que pasar su longitud en todas partes (solo un puntero es una dirección, no sabe nada de lo que apunta).
Ignorar las palabras clave const
por ahora.
La versión C de atoi
recorre cada carácter de la cadena. El *str++
hace varias cosas (es importante entender cómo funciona, pero es una forma horrible de escribir C). Es equivalente a *(str++)
. El str++
devuelve el valor de str
(un puntero) y luego lo incrementa en uno (¡pero devuelve el valor anterior!). Las *
"desreferencias" del puntero, básicamente, leen en una char
de memoria. Este char
se almacena en digit
y luego se compara con NUL
. Los caracteres se almacenan en ASCII, que representa los dígitos de manera contigua, por lo que solo podemos verificar que el digit
esté entre 0 y 9. Sabemos ahora que estamos leyendo en un nuevo dígito, así que multiplicamos el valor anterior por 10 para "desplazar" el valor sobre y luego agregar en el dígito.
Versión de Pure C:
int atoi(const char* str) {
int num = 0;
char digit;
while ((digit = *str++) != ''/0'') {
if (digit < ''0'' || digit > ''9'') {
return num; /* No valid conversion possible */
}
num *= 10;
num += c - ''0'';
}
return num;
}
Una cadena C ++ es un objeto para facilitar el manejo de cadenas. Puede obtener un char *
desde una cadena de C ++ con .c_str()
.
Versión de C ++ (más probablemente una llamada en línea a la versión char * con "return atoi (str.c_str ());"):
int atoi(const std::string& str) {
int n = 0;
for (int i = 0; i < str.size(); i += 1) {
char digit = str.at(i); /* Could probably use iterator here,
* but this is more explicit. */
if (digit < ''0'' || digit > ''9'') {
return n; /* No valid conversion possible. */
}
n *= 10;
n += digit - ''0'';
}
return n;
}
Edición: se solucionó el problema donde <> no se mostraba correctamente.
Edición: se agregó la versión de cadena de C ++
Edición: Se 123a
para que devuelva 123 en el caso 123a
.
Edición: Se modificó la numeración extraviada de n en la versión C ++
Da la vuelta a la pregunta: ¿cómo lo haces? Cuando vea "31" escrito, ¿cómo entiende la cantidad de X que necesita contar para igualar eso?
1 * the value in the leftmost column
+ 10 * the value in the next column to the right
+ 100 * the value in the next column to the right
...
Bueno, puedes codificar eso.
En realidad, a menudo se implementa desde la mayoría de los caracteres correctos para facilitar su uso con flujos. ¿Cómo puedes hacer eso?
La lógica es simplemente procesar cada carácter en su valor entero (ajustando la posición dentro de la cadena).
Así Here''s como lo hice en C #. La misma idea general.