4

I have this code to convert an ASCII string to and int, float, or double. However, it prints "42" for all of them. Where did I go wrong? The syntax looks correct, no warnings.

#include <stdlib.h>
int main(void)
{
     char *buf1 = "42";
     char buf2[] = "69.00";
     int i;
     double d;
     long l;
     i = atoi(buf1);
     l = atol(buf1);
     d = atof(buf2);
     printf("%d\t%d\t%d\n", i, l, d);
     return 0;
}
user3897320
  • 87
  • 1
  • 2
  • 7

3 Answers3

5

First, you should avoid use of the ato* functions (ie: atoi, atof, etc), because there are cases where the conversion failed, and it just returns zero, so you have no way to know if the input was really a string representing zero, or if it was due to a processing error. If you modify the example below, for example, and change buf2 to "z16", you will get a warning you can handle. atoi would not let you know about that error.

Second, your format specifiers are incorrect in your printf call. Your compiler should have generated warnings about this.

Please refer to the example below for a working version that includes conversion error handling. Not that the explicit casting of strtol to (int) in my example does allow for a potential integer overflow. Try making buf1 a large number, and see what happens.

Good luck!

Code Listing


#include <stdio.h>   /* printf */
#include <stdlib.h>  /* strtox */
#include <errno.h>   /* error numbers */

#define BASE         (10)  /* use decimal */

int main(void) {
   char* errCheck;
   char *buf1   = "42";
   char *buf2   = "16";
   char  buf3[] = "69.00";
   int i;
   double d;
   long l;

   /* Handle conversions and handle errors */
   i = (int)strtol(buf1, &errCheck, BASE);
   if(errCheck == buf1) {
      printf("Conversion error:%s\n",buf1);
      return EIO;
   }
   l = strtol(buf2, &errCheck, BASE);
   if(errCheck == buf2) {
      printf("Conversion error:%s\n",buf2);
      return EIO;
   }
   d = strtod(buf3, &errCheck);
   if(errCheck == buf3) {
      printf("Conversion error:%s\n",buf3);
      return EIO;
   }

   printf("%d\t%ld\t%lf\n", i, l, d);
   return 0;
}
Cloud
  • 18,753
  • 15
  • 79
  • 153
  • 1
    Although using `strtox()` is better than `atox()`, code here also fails to detect overflow and potential garbage at the end of `bufn`, much like `atox()`. – chux - Reinstate Monica Aug 01 '14 at 18:14
  • Fair enough. He could test against LONG_MAX, etc. http://stackoverflow.com/questions/5493235/strtol-returns-an-incorrect-value Also, a quick `isalpha` loop would handle trailing garbage. The general point I was making was to avoid `atox` functions. – Cloud Aug 01 '14 at 18:27
  • This answer implies that `atoi` returns 0 on error, which is false. The behavior on errors is unspecified, and the behavior if the value overflows is *undefined*. This is much more serious and makes it basically impossible to use `atoi` unless you know the input is valid and in-range. – R.. GitHub STOP HELPING ICE Aug 01 '14 at 19:04
  • @R.. I stand corrected. It seems it returns zero only if the first character is non-integral. http://stackoverflow.com/questions/8871711/atoi-how-to-identify-the-difference-between-zero-and-error – Cloud Aug 01 '14 at 19:20
  • @Dogbert: Even that doesn't seem to be specified. – R.. GitHub STOP HELPING ICE Aug 01 '14 at 19:38
  • @R.. *If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed and zero is returned.* http://www.cplusplus.com/reference/cstdlib/atoi/ – Cloud Aug 01 '14 at 20:32
  • 1
    Parenthesizing a positive numeric literal like 10 is a sign of too much paranoia. Rule of thumb: parenthesize if there's an operator in the replacement text. Everything else is a sign of someone not grokking C :-) – Jens Aug 02 '14 at 10:47
  • 1
    @Jens It is not a sign of paranoia. It is there to appease static code analysis tools (MISRA chk, LINT) etc, so you can sign off on compliance with certain standards legally. Old habits die hard. – Cloud Aug 03 '14 at 13:56
  • @Dogbert Which MISRA checker warns for unparenthezied numeric literals? The ones I use (flexelint, polyspace) want the *parameters, if any* parenthesized, and expressions with operators. They don't require the replacement text parenthesized if it is a single numeric token. (Programmers beware: -1 is an expression which needs to be parenthesized). – Jens Aug 03 '14 at 14:22
  • 1
    @Jens I think you just answered your own question. `(-1)` evaluates as a signed integer literal, just like `(1)` evaluates to a literal. Wind River Workbench. This also enforces consistency throughout the code. A decent example would be using a type of globally-accessible offset encoded as a signed integer. If it changes from say, `(2)` to `(-1)`, it's silly that the definition should change based on range. Depending on your master rule override file, your static code analysis tools might also do this to, but the option could be disabled. – Cloud Aug 03 '14 at 21:55
2

Change

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

to

printf("%d\t%ld\t%f\n", i, l, d);
Raghu Srikanth Reddy
  • 2,703
  • 33
  • 29
  • 42
1

Please don't use ato* functions as ato* functions has been deprecated by strto* and should not be used in new code.

The problem with ato* is, if the converted value is out of range it causes undefined behavior.

For more information check here.

ani627
  • 5,578
  • 8
  • 39
  • 45