Hoe converteer je een string naar een geheel getal in C?

Ik probeer erachter te komen of er een alternatieve manier is om string naar integer in C te converteren.

Ik gebruik regelmatig het volgende in mijn code.

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

Dus, is er een betere of een andere manier?


Antwoord 1, autoriteit 100%

Er is strtoldie beter IMO. Ik heb ook een voorkeur gekregen voor strtonum, dus gebruik het als je het hebt (maar onthoud dat het niet draagbaar is):

long long
     strtonum(const char *nptr, long long minval, long long maxval,
     const char **errstr);

Misschien ben je ook geïnteresseerd in strtoumaxen strtoimaxdie standaardfuncties zijn in C99. Je zou bijvoorbeeld kunnen zeggen:

uintmax_t num = strtoumax(s, NULL, 10);
if (num == UINTMAX_MAX && errno == ERANGE)
    /* Could not convert. */

Hoe dan ook, blijf uit de buurt van atoi:

De aanroep atoi(str) zal gelijk zijn aan:

(int) strtol(str, (char **)NULL, 10)

behalve dat de afhandeling van fouten kan verschillen. Als de waarde niet kan zijn
weergegeven, is het gedrag niet gedefinieerd
.


Antwoord 2, autoriteit 16%

Robuuste C89 strtol-gebaseerde oplossing

Met:

  • geen ongedefinieerd gedrag (zoals bij de atoi-familie)
  • een striktere definitie van integer dan strtol(bijv. geen voorloopspaties of prullenbaktekens achteraan)
  • classificatie van het foutgeval (bijv. om gebruikers nuttige foutmeldingen te geven)
  • een “testsuite”
#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;
}

GitHub stroomopwaarts.

Gebaseerd op: https://stackoverflow.com/a/6154614/895245


Antwoord 3, autoriteit 13%

Gebruik geen functies uit de ato...groep. Deze zijn kapot en vrijwel nutteloos. Een iets betere oplossing zou zijn om sscanfte gebruiken, hoewel het ook niet perfect is.

Om tekenreeks naar geheel getal te converteren, moeten functies uit de groep strto...worden gebruikt. In jouw specifieke geval zou het de functie strtolzijn.


Antwoord 4, autoriteit 3%

Je kunt atoi()voor de lol coderen:

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

Je kunt het ook recursief maken, wat in 3 regels kan worden gevouwen.


Antwoord 5

Ik wilde ook een oplossing delen voor lang niet-ondertekend.

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

Antwoord 6

int atoi(const char* str){
    int num = 0;
    int i = 0;
    bool isNegetive = false;
    if(str[i] == '-'){
        isNegetive = true;
        i++;
    }
    while (str[i] && (str[i] >= '0' && str[i] <= '9')){
        num = num * 10 + (str[i] - '0');
        i++;
    }
    if(isNegetive) num = -1 * num;
    return num;
}

Antwoord 7

Ok, ik had hetzelfde probleem. Ik kwam met deze oplossing. Het werkte voor mij het beste. Ik heb atoi() geprobeerd, maar werkte niet goed voor mij. Dus hier is mijn oplossing:

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

Antwoord 8

Je kunt altijd je eigen rollen!

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

Dit doet wat je wilt zonder rommel.


Antwoord 9

Deze functie zal u helpen

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


Antwoord 10

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

Antwoord 11

In C++ kun je een dergelijke functie gebruiken:

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

Dit kan je helpen om elke string naar elk type te converteren, zoals float, int, double…


Antwoord 12

Ja, u kunt het gehele getal direct opslaan:

int num = 45;

Als je een string moet ontleden, zal atoiof strolde wedstrijd “shortest number of code” winnen.

Other episodes