letras - ¿Cómo convertir una cadena a entero en C?
funcion itoa en c (11)
Estoy tratando de averiguar si hay una forma alternativa de convertir una cadena en un entero en C.
Regularmente patrón el siguiente en mi código.
char s[] = "45";
int num = atoi(s);
Entonces, ¿hay una manera mejor o otra manera?
¡Siempre puedes rodar el tuyo!
#include <stdio.h>
#include <string.h>
#include <math.h>
int my_atoi(const char* snum)
{
int idx, strIdx = 0, accum = 0, numIsNeg = 0;
const unsigned int NUMLEN = (int)strlen(snum);
/* Check if negative number and flag it. */
if(snum[0] == 0x2d)
numIsNeg = 1;
for(idx = NUMLEN - 1; idx >= 0; idx--)
{
/* Only process numbers from 0 through 9. */
if(snum[strIdx] >= 0x30 && snum[strIdx] <= 0x39)
accum += (snum[strIdx] - 0x30) * pow(10, idx);
strIdx++;
}
/* Check flag to see if originally passed -ve number and convert result if so. */
if(!numIsNeg)
return accum;
else
return accum * -1;
}
int main()
{
/* Tests... */
printf("Returned number is: %d/n", my_atoi("34574"));
printf("Returned number is: %d/n", my_atoi("-23"));
return 0;
}
Esto hará lo que quieras sin desorden.
En C ++, puede utilizar una función de este tipo:
template <typename T>
T to(const std::string & s)
{
std::istringstream stm(s);
T result;
stm >> result;
if(stm.tellg() != s.size())
throw error;
return result;
}
Esto puede ayudarte a convertir cualquier cadena a cualquier tipo, como float, int, double ...
Esta función te ayudará
int strtoint_n(char* str, int n)
{
int sign = 1;
int place = 1;
int ret = 0;
int i;
for (i = n-1; i >= 0; i--, place *= 10)
{
int c = str[i];
switch (c)
{
case ''-'':
if (i == 0) sign = -1;
else return -1;
break;
default:
if (c >= ''0'' && c <= ''9'') ret += (c - ''0'') * place;
else return -1;
}
}
return sign * ret;
}
int strtoint(char* str)
{
char* temp = str;
int n = 0;
while (*temp != ''/0'')
{
n++;
temp++;
}
return strtoint_n(str, n);
}
Ref: http://amscata.blogspot.com/2013/09/strnumstr-version-2.html
Hay strtol
que es mejor IMO. También me ha gustado el strtonum
, así que strtonum
si lo tienes (pero recuerda que no es portátil):
long long
strtonum(const char *nptr, long long minval, long long maxval,
const char **errstr);
EDITAR
También puede interesarle strtoumax
y strtoimax
que son funciones estándar en C99. Por ejemplo, podrías decir:
uintmax_t num = strtoumax(s, NULL, 10);
if (num == UINTMAX_MAX && errno == ERANGE)
/* Could not convert. */
De todos modos, mantente alejado de atoi
:
La llamada atoi (str) será equivalente a:
(int) strtol(str, (char **)NULL, 10)
excepto que el manejo de errores puede diferir. Si el valor no se puede representar, el comportamiento no está definido .
No use funciones de un grupo ato...
Estos están rotos y prácticamente inútiles. Una solución moderadamente mejor sería usar sscanf
, aunque tampoco es perfecto.
Para convertir una cadena en un entero, se deben usar las funciones del grupo strto...
En su caso específico sería la función strtol
.
Ok, tuve el mismo problema. Se me ocurrió esta solución. Funcionó para mí de la mejor manera. Probé atoi () pero no funcionó bien para mí. Así que aquí está mi solución:
void splitInput(int arr[], int sizeArr, char num[])
{
for(int i = 0; i < sizeArr; i++)
// We are subtracting 48 because the numbers in ASCII starts at 48.
arr[i] = (int)num[i] - 48;
}
Puedes codificar un poco atoi () por diversión:
int my_getnbr(char *str)
{
int result;
int puiss;
result = 0;
puiss = 1;
while ((''-'' == (*str)) || ((*str) == ''+''))
{
if (*str == ''-'')
puiss = puiss * -1;
str++;
}
while ((*str >= ''0'') && (*str <= ''9''))
{
result = (result * 10) + ((*str) - ''0'');
str++;
}
return (result * puiss);
}
También puede hacerlo recursivo que puede ser antiguo en 3 líneas =)
Sí, puedes almacenar el entero directamente:
int num = 45;
Si debes analizar una cadena, atoi
o strol
va a ganar el concurso de "cantidad de código más corta".
Solo quería compartir una solución para un largo tiempo sin firmar.
unsigned long ToUInt(char* str)
{
unsigned long mult = 1;
unsigned long re = 0;
int len = strlen(str);
for(int i = len -1 ; i >= 0 ; i--)
{
re = re + ((int)str[i] -48)*mult;
mult = mult*10;
}
return re;
}
Solución robusta basada en strtol
C89
Con:
- sin comportamiento indefinido (como se podría tener con la familia
atoi
) - una definición más estricta de enteros que
strtol
(por ejemplo, sin espacios en blanco iniciales ni caracteres de basura finales) - clasificación del caso de error (por ejemplo, para dar mensajes de error útiles a los usuarios)
- un "testuite"
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
typedef enum {
STR2INT_SUCCESS,
STR2INT_OVERFLOW,
STR2INT_UNDERFLOW,
STR2INT_INCONVERTIBLE
} str2int_errno;
/* Convert string s to int out.
*
* @param[out] out The converted int. Cannot be NULL.
*
* @param[in] s Input string to be converted.
*
* The format is the same as strtol,
* except that the following are inconvertible:
*
* - empty string
* - leading whitespace
* - any trailing characters that are not part of the number
*
* Cannot be NULL.
*
* @param[in] base Base to interpret string in. Same range as strtol (2 to 36).
*
* @return Indicates if the operation succeeded, or why it failed.
*/
str2int_errno str2int(int *out, char *s, int base) {
char *end;
if (s[0] == ''/0'' || isspace(s[0]))
return STR2INT_INCONVERTIBLE;
errno = 0;
long l = strtol(s, &end, base);
/* Both checks are needed because INT_MAX == LONG_MAX is possible. */
if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX))
return STR2INT_OVERFLOW;
if (l < INT_MIN || (errno == ERANGE && l == LONG_MIN))
return STR2INT_UNDERFLOW;
if (*end != ''/0'')
return STR2INT_INCONVERTIBLE;
*out = l;
return STR2INT_SUCCESS;
}
int main(void) {
int i;
/* Lazy to calculate this size properly. */
char s[256];
/* Simple case. */
assert(str2int(&i, "11", 10) == STR2INT_SUCCESS);
assert(i == 11);
/* Negative number . */
assert(str2int(&i, "-11", 10) == STR2INT_SUCCESS);
assert(i == -11);
/* Different base. */
assert(str2int(&i, "11", 16) == STR2INT_SUCCESS);
assert(i == 17);
/* 0 */
assert(str2int(&i, "0", 10) == STR2INT_SUCCESS);
assert(i == 0);
/* INT_MAX. */
sprintf(s, "%d", INT_MAX);
assert(str2int(&i, s, 10) == STR2INT_SUCCESS);
assert(i == INT_MAX);
/* INT_MIN. */
sprintf(s, "%d", INT_MIN);
assert(str2int(&i, s, 10) == STR2INT_SUCCESS);
assert(i == INT_MIN);
/* Leading and trailing space. */
assert(str2int(&i, " 1", 10) == STR2INT_INCONVERTIBLE);
assert(str2int(&i, "1 ", 10) == STR2INT_INCONVERTIBLE);
/* Trash characters. */
assert(str2int(&i, "a10", 10) == STR2INT_INCONVERTIBLE);
assert(str2int(&i, "10a", 10) == STR2INT_INCONVERTIBLE);
/* int overflow.
*
* `if` needed to avoid undefined behaviour
* on `INT_MAX + 1` if INT_MAX == LONG_MAX.
*/
if (INT_MAX < LONG_MAX) {
sprintf(s, "%ld", (long int)INT_MAX + 1L);
assert(str2int(&i, s, 10) == STR2INT_OVERFLOW);
}
/* int underflow */
if (LONG_MIN < INT_MIN) {
sprintf(s, "%ld", (long int)INT_MIN - 1L);
assert(str2int(&i, s, 10) == STR2INT_UNDERFLOW);
}
/* long overflow */
sprintf(s, "%ld0", LONG_MAX);
assert(str2int(&i, s, 10) == STR2INT_OVERFLOW);
/* long underflow */
sprintf(s, "%ld0", LONG_MIN);
assert(str2int(&i, s, 10) == STR2INT_UNDERFLOW);
return EXIT_SUCCESS;
}
Basado en: https://.com/a/6154614/895245
//I think this way we could go :
int my_atoi(const char* snum)
{
int nInt(0);
int index(0);
while(snum[index])
{
if(!nInt)
nInt= ( (int) snum[index]) - 48;
else
{
nInt = (nInt *= 10) + ((int) snum[index] - 48);
}
index++;
}
return(nInt);
}
int main()
{
printf("Returned number is: %d/n", my_atoi("676987"));
return 0;
}