p4nzer96
p4nzer96

Reputation: 825

Result Decremented by 1 during a conversion between string to integer (and only with specific values of string length)

I'm writing a program in C that converts a string of n characters into an integer only if this string's first character is the minus symbol. The program is the following:

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

int StringToInt(char *string){
    int i=0;
    int integer=0;
    int length = strlen(string);
    if (string[0]=='-'){
        for (i=1; i<length; i++){
        integer += (string[i]-48)*pow(10, (length-1-i));
        }return (integer*(-1));
    }else{
        return 0;
    }
}

My program works fine when I call the function above with a string with an odd value of string length, while otherwise it returns the right value but decremented by one. Now I'll make it clearer with an example: suppose I create a string called "Number" and I assign to this the number "-234". If we put this string in the function above, the string's length will be calculated as 4. The function in this case won't return -234, but -233. If, instead of -234, I had assigned to the string a number like "-1456", the function would have returned the correct number.

Upvotes: 1

Views: 50

Answers (2)

chema989
chema989

Reputation: 4182

I suggest the next code, it's based in the recommendations made in comments:

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


int StringToInt(const char* string){
    int lenght = strlen(string);
    if (lenght && string[0] == '-'){
        int integer = 0;
        for (int i = 1; i < lenght; ++i) {
            // Check if it is not a character valid.
            if (string[i] < '0' || string[i] > '9') {
                // Returns the integer processed so far.
                return -integer;
            }
            integer = 10 * integer + string[i] - '0'; // Like John Bollinger suggests
        }
        return -integer;
    } else {
        return 0;
    }
}


int main(int argc, char **argv) {
    fprintf(stderr, "%d\n", StringToInt(""));
    fprintf(stderr, "%d\n", StringToInt("-123"));
    fprintf(stderr, "%d\n", StringToInt("-1736734"));
    fprintf(stderr, "%d\n", StringToInt("-1999"));
    fprintf(stderr, "%d\n", StringToInt("-123"));
    fprintf(stderr, "%d\n", StringToInt("-234"));
    fprintf(stderr, "%d\n", StringToInt("-180."));
    fprintf(stderr, "%d\n", StringToInt("-200.99"));
    fprintf(stderr, "%d\n", StringToInt("-aaa"));

    const char* msg = "-301";
    fprintf(stderr, "%d\n", StringToInt(msg));
    return 0;
}

I suggest check if the character is not valid (i.e: it is not between '0' and '9'):

if (string[i] < '0' || string[i] > '9') {
    // Returns the integer processed so far.
    return -integer;
}

Once you find a character not valid, return the integer processed so far.

Output:

0
-123
-1736734
-1999
-123
-234
-180
-200
0
-301

Upvotes: 1

Austin Mullins
Austin Mullins

Reputation: 7437

I'm pretty sure it's just rounding errors. When you cast 0.999999 as an int you get 0. Thus, any floating point error that results in a number like 2047.999999 will be interpreted as 2047 instead of the more accurate 2048, which will look like it's decremented by 1.

As John Bollinger suggested in a comment, just add each character to 10 times the current value:

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

int string_to_int(char *string) {
  int i=0;
  int integer=0;
  int length = strlen(string);
  if (string[0] == '-') {
    for (i=1; i<length; i++) {
      integer = 10 * integer + string[i]-'0';
    }

    return -integer;
  } else {
    return 0;
  }
}

int main(int argc, char **argv) {
  if (argc < 2)
    return 1;

  printf("Result: %d\n", string_to_int(argv[1]));
  return 0;
}

I prefer to say '0' rather than 48 since it clarifies your intent (converting a character to the digit it represents).

Upvotes: 2

Related Questions