¿Cómo convertir una cadena a un entero en C?

Estoy tratando de averiguar si hay una forma alternativa de convertir cadena a entero en C.

Regularmente diseño lo siguiente en mi código.

char s[] = "45"; int num = atoi(s); 

Entonces, ¿hay una mejor manera u otra manera?

Hay strtol que es mejor IMO. También me ha gustado en 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 podría estar interesado en 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 .

Solución robusta C89 basada en strtol

Con:

  • ningún comportamiento indefinido (como podría tenerse con la familia atoi )
  • una definición más estricta de entero que strtol (p. ej., sin espacios en blanco iniciales ni caracteres de basura al final)
  • clasificación del caso de error (por ejemplo, para dar mensajes de error útiles a los usuarios)
  • una “suite de pruebas”
 #include  #include  #include  #include  #include  #include  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; } 

GitHub aguas arriba .

Basado en: https://stackoverflow.com/a/6154614/895245

No use funciones de un ato... grupo. Estos están rotos y son 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 de strto... group. En su caso específico, sería la función strtol .

Puede 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 =)

Solo quería compartir una solución para unsigned long también.

 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; } 

¡Siempre puedes hacer tu propio!

 #include  #include  #include  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.

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

Ok, tuve el mismo problema. Se me ocurrió esta solución. Me funcionó de la mejor manera. Intenté 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; } 
 //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; } 

Sí, puedes almacenar el número entero directamente:

 int num = 45; 

Si debe analizar una cadena, atoi o strol va a ganar el concurso de “cantidad más corta de código”.

En C ++, puede usar una de estas funciones:

 template  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 …