36

I want to convert a char array[] like:

char myarray[4] = {'-','1','2','3'}; //where the - means it is negative

So it should be the integer: -1234 using standard libaries in C. I could not find any elegant way to do that.

I can append the '\0' for sure.

Ivaylo Strandjev
  • 64,309
  • 15
  • 111
  • 164
SpcCode
  • 789
  • 2
  • 11
  • 24
  • 3
    1. you are missing `4` 2. do you have a null terminator for the array? – MByD Apr 18 '12 at 07:03
  • 2
    Does the possibility exist to append an extra `'\0'` to the end of the array? Then we'd be done in no time. – Mr Lister Apr 18 '12 at 07:04
  • 8
    That's because there isn't any. There are ways for nul-terminated strings though. `atoi` and `strtol` are two options. `char myarray[] = {'-','1','2','3','4',0}; int i = atoi(myarray);` – falstro Apr 18 '12 at 07:04
  • @roe you'd probably turn that last one into an answer then :) – Eregrith Apr 18 '12 at 07:07
  • 3
    Instead of explicitly appending the `'\0'`, just leave it to the compiler: `char myarray[] = "-1234";` – Jerry Coffin Apr 18 '12 at 07:11

5 Answers5

83

I personally don't like atoi function. I would suggest sscanf:

char myarray[5] = {'-', '1', '2', '3', '\0'};
int i;
sscanf(myarray, "%d", &i);

It's very standard, it's in the stdio.h library :)

And in my opinion, it allows you much more freedom than atoi, arbitrary formatting of your number-string, and probably also allows for non-number characters at the end.

EDIT I just found this wonderful question here on the site that explains and compares 3 different ways to do it - atoi, sscanf and strtol. Also, there is a nice more-detailed insight into sscanf (actually, the whole family of *scanf functions).

EDIT2 Looks like it's not just me personally disliking the atoi function. Here's a link to an answer explaining that the atoi function is deprecated and should not be used in newer code.

Community
  • 1
  • 1
penelope
  • 7,605
  • 5
  • 40
  • 82
  • 5
    degustibus... sscanf adds an entire overhead upon a trivial task (variable list arguments, format string parsing), and IMHO is more "error prone". For simple task I prefer to use simple functions (atoi is there for this reason) – BigMike Apr 18 '12 at 07:17
  • @BigMike When I was very little and just starting with `C`, somebody explained to me why using `atoi` is not preferable. Since then, I forgot the reasons, but I never liked using it much... Now I'm looking them up and I'm being reminded of them. I edited in a link to a question referring to the `atoi` problem, as well as one comparing it to other ways of converting a string to int. – penelope Apr 18 '12 at 07:25
  • 2
    the only reason to deprecate atoi is related to thread safe stuff, strtol is still preferreable over sscanf for trivial tasks. the point is not using atoi or int foo(char *) is to use a trivial function against a complex function. the rest is just a matter of taste. sscanf sure does its work, simply is wasted on such a trivial tasks. When I learned programming, sparing that 4/5 cycles of clock was a must. If more people just had keep on that, now application would run at speed of light. – BigMike Apr 18 '12 at 07:30
  • 12
    And __how do you think__ `sscanf` gets its `%d` parsed ? It calls `atoi`, so anyway that's bazooka for an ant... – Eregrith Apr 18 '12 at 08:00
  • @Eregrith So, I learn something new everyday :) On the other hand, I never actually had to do any code using heavy int to string conversion, I knew that `sscanf` is *safer* in some way so when using it once or twice during the application run, I didn't bother that much with the performance issues. – penelope Apr 18 '12 at 08:27
  • Very good, like "pit_t" types, sscanf is very good for me. atoi is not ok. – kangear May 20 '14 at 03:31
  • 3
    @BigMike: The reason to deprecate `atoi` is that it fails silently. There's no static buffer that would cause thread-safety issues, though. `strtol` is indeed the right function to use here. – Ben Voigt Jul 06 '14 at 19:55
12

Why not just use atoi? For example:

char myarray[4] = {'-','1','2','3'};

int i = atoi(myarray);

printf("%d\n", i);

Gives me, as expected:

-123

Update: why not - the character array is not null terminated. Doh!

Rich Drummond
  • 3,199
  • 13
  • 15
3

It isn't that hard to deal with the character array itself without converting the array to a string. Especially in the case where the length of the character array is know or can be easily found. With the character array, the length must be determined in the same scope as the array definition, e.g.:

size_t len sizeof myarray/sizeof *myarray;

For strings you, of course, have strlen available.

With the length known, regardless of whether it is a character array or a string, you can convert the character values to a number with a short function similar to the following:

/* convert character array to integer */
int char2int (char *array, size_t n)
{    
    int number = 0;
    int mult = 1;

    n = (int)n < 0 ? -n : n;       /* quick absolute value check  */

    /* for each character in array */
    while (n--)
    {
        /* if not digit or '-', check if number > 0, break or continue */
        if ((array[n] < '0' || array[n] > '9') && array[n] != '-') {
            if (number)
                break;
            else
                continue;
        }

        if (array[n] == '-') {      /* if '-' if number, negate, break */
            if (number) {
                number = -number;
                break;
            }
        }
        else {                      /* convert digit to numeric value   */
            number += (array[n] - '0') * mult;
            mult *= 10;
        }
    }

    return number;
}

Above is simply the standard char to int conversion approach with a few additional conditionals included. To handle stray characters, in addition to the digits and '-', the only trick is making smart choices about when to start collecting digits and when to stop.

If you start collecting digits for conversion when you encounter the first digit, then the conversion ends when you encounter the first '-' or non-digit. This makes the conversion much more convenient when interested in indexes such as (e.g. file_0127.txt).

A short example of its use:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int char2int (char *array, size_t n);

int main (void) {

    char myarray[4] = {'-','1','2','3'}; 
    char *string = "some-goofy-string-with-123-inside";
    char *fname = "file-0123.txt";

    size_t mlen = sizeof myarray/sizeof *myarray;
    size_t slen = strlen (string);
    size_t flen = strlen (fname);

    printf ("\n myarray[4] = {'-','1','2','3'};\n\n");
    printf ("   char2int (myarray, mlen):  %d\n\n", char2int (myarray, mlen));

    printf (" string = \"some-goofy-string-with-123-inside\";\n\n");
    printf ("   char2int (string, slen) :  %d\n\n", char2int (string, slen));

    printf (" fname = \"file-0123.txt\";\n\n");
    printf ("   char2int (fname, flen)  :  %d\n\n", char2int (fname, flen));

    return 0;
}

Note: when faced with '-' delimited file indexes (or the like), it is up to you to negate the result. (e.g. file-0123.txt compared to file_0123.txt where the first would return -123 while the second 123).

Example Output

$ ./bin/atoic_array

 myarray[4] = {'-','1','2','3'};

   char2int (myarray, mlen):  -123

 string = "some-goofy-string-with-123-inside";

   char2int (string, slen) :  -123

 fname = "file-0123.txt";

   char2int (fname, flen)  :  -123

Note: there are always corner cases, etc. that can cause problems. This isn't intended to be 100% bulletproof in all character sets, etc., but instead work an overwhelming majority of the time and provide additional conversion flexibility without the initial parsing or conversion to string required by atoi or strtol, etc.

David C. Rankin
  • 69,681
  • 6
  • 44
  • 72
2

So, the idea is to convert character numbers (in single quotes, e.g. '8') to integer expression. For instance char c = '8'; int i = c - '0' //would yield integer 8; And sum up all the converted numbers by the principle that 908=9*100+0*10+8, which is done in a loop.

char t[5] = {'-', '9', '0', '8', '\0'}; //Should be terminated properly.

int s = 1;
int i = -1;
int res = 0;

if (c[0] == '-') {
  s = -1;
  i = 0;
}

while (c[++i] != '\0') { //iterate until the array end
  res = res*10 + (c[i] - '0'); //generating the integer according to read parsed numbers.
}

res = res*s; //answer: -908
  • If you bother to add the `'\0'`, it'd really be better to use standard library (see other answers). This approach would be useful, if you couldn't have the terminating NUL byte (with loop condition changed). – hyde May 23 '15 at 19:58
  • Yea, I came up with the one without using library. – Otar Magaldadze May 24 '15 at 14:39
  • i use standard library when i feel lazy, i always adopt this approach when it comes to integers. – milevyo Oct 29 '15 at 01:32
  • assuming there is no other chars than {'-','+','0-9',\0}; – milevyo Oct 29 '15 at 01:34
0

It's not what the question asks but I used @Rich Drummond 's answer for a char array read in from stdin which is null terminated.

char *buff;
size_t buff_size = 100;
int choice;
do{
    buff = (char *)malloc(buff_size *sizeof(char));
    getline(&buff, &buff_size, stdin);
    choice = atoi(buff);
    free(buff);
                    
}while((choice<1)&&(choice>9));
mLstudent33
  • 669
  • 2
  • 7
  • 17