How to convert a string to integer in C?

CStringAtoi

C Problem Overview


I am trying to find out if there is an alternative way of converting string to integer in C.

I regularly pattern the following in my code.

char s[] = "45";

int num = atoi(s);

So, is there a better way or another way?

C Solutions


Solution 1 - C

There is strtol which is better IMO. Also I have taken a liking in strtonum, so use it if you have it (but remember it's not portable):

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

You might also be interested in strtoumax and strtoimax which are standard functions in C99. For example you could say:

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

Anyway, stay away from atoi:

> The call atoi(str) shall be equivalent to: > > (int) strtol(str, (char **)NULL, 10) > > except that the handling of errors may differ. If the value cannot be > represented, the behavior is undefined.

Solution 2 - C

Robust C89 strtol-based solution

With:

  • no undefined behavior (as could be had with the atoi family)
  • a stricter definition of integer than strtol (e.g. no leading whitespace nor trailing trash chars)
  • classification of the error case (e.g. to give useful error messages to users)
  • a "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 upstream.

Based on: https://stackoverflow.com/a/6154614/895245

Solution 3 - C

Don't use functions from ato... group. These are broken and virtually useless. A moderately better solution would be to use sscanf, although it is not perfect either.

To convert string to integer, functions from strto... group should be used. In your specific case it would be strtol function.

Solution 4 - C

You can code atoi() for fun:

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

You can also make it recursive, which can fold in 3 lines.

Solution 5 - C

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

Solution 6 - C

Just wanted to share a solution for unsigned long aswell.

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

Solution 7 - C

As already mentioned, the atoi family of functions should never be used in any C program, since they don't have any error handling.

The the strtol family of functions is 100% equivalent, but with extended functionality: it has error handling and it also supports other bases than decimal, such as hex or binary. Therefore the correct answer is: use strtol (family).

If you for some reason insist on rolling out this function yourself manually, you should try to do something similar to strtol in case there are other symbols present other than the optional sign and digits. It's quite common that we want to convert numbers that are part of larger string, for example.

A naive version with error handling support might look like the example below. This code is for decimal base 10 numbers only, but otherwise behaves like strtol with an optional pointer set to point at the first invalid symbol encountered (if any). Also note that this code doesn't handle overflows.

#include <ctype.h>

long my_strtol (char* restrict src, char** endptr)
{
  long result=0;
  long sign=1;

  if(endptr != NULL) 
  {
    /* if input is ok and endptr is provided, 
       it will point at the beginning of the string */
    *endptr = src;
  }

  if(*src=='-')
  {
    sign = -1;
    src++;
  }

  for(; *src!='\0'; src++)
  {
    if(!isdigit(*src)) // error handling
    {
      if(endptr != NULL)
      {
        *endptr = src;
      }
      break;
    }
    result = result*10 + *src - '0';
  }

  return result * sign;
}

To handle overflows, one can for example add code counting the characters and check that they never go past 10, assuming 32 bit long which can be max 2147483647, 10 digits.

Solution 8 - C

Ok, I had the same problem.I came up with this solution.It worked for me the best.I did try atoi() but didn't work well for me.So here is my solution:

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

Solution 9 - C

Here is a code that does the job, using Horner's rule:

#include <stdio.h>
int main(void)
{
   char num[7], *p;
   int valn = 0, sign=-1;
   scanf("%s", num);
   sign = num[0]=='-'? -1:+1;
   p=num+(sign==-1);
   while(*p) valn=valn*10+(*p++-'0'); /* Horner */
   printf("%d\n", valn*sign);
   return 0;
}


% gcc str_to_int.c
% ./a.out
32
32
% ./a.out
-32
-32

The code is minimalist; it does not check the bounds.

The main point in this solution is that a number of k digits A0A1 ... Ak is a polynomial and the value of a polynomial can be computed using the rule of Horner. The value of the number in base N can be written as A0*Nk+A1*Nk-1+...+Ak*N0. This is what this line does:

while(*p) valn=valn*10+(*p++-'0');

Solution 10 - C

This function will help you

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

Solution 11 - C

You can always roll your own!

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

This will do what you want without clutter.

Solution 12 - C

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

Solution 13 - C

In C++, you can use a such function:

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

This can help you to convert any string to any type such as float, int, double...

Solution 14 - C

Yes, you can store the integer directly:

int num = 45;

If you must parse a string, atoi or strol is going to win the "shortest amount of code" contest.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser618677View Question on Stackoverflow
Solution 1 - CcnicutarView Answer on Stackoverflow
Solution 2 - CCiro Santilli Путлер Капут 六四事View Answer on Stackoverflow
Solution 3 - CAnTView Answer on Stackoverflow
Solution 4 - CGrandMarquisView Answer on Stackoverflow
Solution 5 - CBiswajit KarmakarView Answer on Stackoverflow
Solution 6 - CJacobView Answer on Stackoverflow
Solution 7 - CLundinView Answer on Stackoverflow
Solution 8 - CKhaled MohammadView Answer on Stackoverflow
Solution 9 - CalinsoarView Answer on Stackoverflow
Solution 10 - CAmith ChinthakaView Answer on Stackoverflow
Solution 11 - CButchDeanView Answer on Stackoverflow
Solution 12 - CAditya KumarView Answer on Stackoverflow
Solution 13 - CneodelphiView Answer on Stackoverflow
Solution 14 - CYann RaminView Answer on Stackoverflow