Converting strings to numbers is a fundamental task in C — every value read from scanf, fgets, or command-line arguments arrives as a string and must be explicitly converted. The standard library in <stdlib.h> provides three simple conversion functions: atoi() (string to int), atol() (string to long), and atof() (string to double/float). For robust error detection, strtod() and strtol() are the preferred alternatives.
The original post used gets() — a function removed from the C11 standard because it cannot limit input size, making buffer overflow impossible to prevent. This rewrite replaces it with fgets(), which takes a maximum length argument.
String-to-Number Functions Quick Reference
| Function | Header | Returns | Detects errors? |
|---|---|---|---|
atoi(s) |
stdlib.h |
int |
No — returns 0 for invalid input |
atol(s) |
stdlib.h |
long |
No — returns 0 for invalid input |
atof(s) |
stdlib.h |
double |
No — returns 0.0 for invalid input |
strtol(s, &end, base) |
stdlib.h |
long |
Yes — sets end pointer, errno |
strtod(s, &end) |
stdlib.h |
double |
Yes — sets end pointer, errno |
C Program: atof, atoi, strtod, and fgets
/* String-to-number conversion in C: atoi, atol, atof, strtod
* Demonstrates fgets() as safe replacement for gets()
* Compile: gcc -ansi -Wall -Wextra atof_demo.c -o atof_demo */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char buf[80];
double a, b, result;
char *endptr;
/* --- atof: ASCII to float (double) --- */
printf("atof() examples:\n");
printf(" atof(\"3.14\") = %.6f\n", atof("3.14"));
printf(" atof(\"-0.5\") = %.6f\n", atof("-0.5"));
printf(" atof(\"1.5e2\") = %.6f\n", atof("1.5e2"));
printf(" atof(\"abc\") = %.6f (non-numeric: returns 0.0)\n", atof("abc"));
printf(" atof(\"12abc\") = %.6f (stops at first non-digit)\n\n", atof("12abc"));
/* --- atoi: ASCII to int --- */
printf("atoi() examples:\n");
printf(" atoi(\"42\") = %d\n", atoi("42"));
printf(" atoi(\"-7\") = %d\n", atoi("-7"));
printf(" atoi(\"abc\") = %d (non-numeric: returns 0)\n\n", atoi("abc"));
/* --- strtod: better than atof --- reports conversion errors --- */
printf("strtod() with error detection:\n");
strtod("3.14xyz", &endptr);
printf(" strtod(\"3.14xyz\"): value=3.14, remainder=\"%s\"\n\n", endptr);
/* --- interactive: multiply two floats with fgets (safe, not gets) --- */
printf("Enter first number: ");
if (fgets(buf, sizeof(buf), stdin) == NULL) return 1;
buf[strcspn(buf, "\n")] = '\0'; /* strip trailing newline */
a = atof(buf);
printf("Enter second number: ");
if (fgets(buf, sizeof(buf), stdin) == NULL) return 1;
buf[strcspn(buf, "\n")] = '\0';
b = atof(buf);
result = a * b;
printf("%.6f * %.6f = %.6f\n", a, b, result);
return 0;
}
How to Compile and Run
gcc -ansi -Wall -Wextra atof_demo.c -o atof_demo
./atof_demo
Sample Output
atof() examples:
atof("3.14") = 3.140000
atof("-0.5") = -0.500000
atof("1.5e2") = 150.000000
atof("abc") = 0.000000 (non-numeric: returns 0.0)
atof("12abc") = 12.000000 (stops at first non-digit)
atoi() examples:
atoi("42") = 42
atoi("-7") = -7
atoi("abc") = 0 (non-numeric: returns 0)
strtod() with error detection:
strtod("3.14xyz"): value=3.14, remainder="xyz"
Enter first number: 3.14
Enter second number: 2.0
3.140000 * 2.000000 = 6.280000
Code Explanation
- atof() parses as far as it can —
atof("12abc")returns 12.0; it stops at ‘a’ because ‘a’ is not a valid float character.atof("abc")cannot parse any digit, so it returns 0.0. There is no way to distinguish “the string was 0” from “the conversion failed” using atof alone. - strtod() sets an end pointer — the second argument receives a pointer to the first character that was NOT converted. If
endptr == original_stringafter the call, nothing was converted (error). If*endptr != '\0', the string had a valid number prefix followed by junk. This is the correct way to validate numeric string input. - fgets() vs gets() —
fgets(buf, sizeof(buf), stdin)reads at mostsizeof(buf) - 1characters.gets()has no length argument and will write past the end of the buffer if the user types too many characters — a classic buffer overflow.gets()was deprecated in C99 and removed in C11. Never use it. - Stripping the newline —
fgets()includes the ‘\n’ in the buffer if it fits.buf[strcspn(buf, "\n")] = '\0'finds the first newline and replaces it with a null terminator, giving you a clean string without a trailing newline. - atof returns double, not float — despite the name (“ASCII to float”),
atof()is declared as returningdouble. For float precision, cast the result:(float)atof("3.14").
What This Program Teaches
- All external input is strings — command-line arguments, file contents, and user input via fgets all arrive as strings. Explicit conversion with atoi/atof/strtol is always required.
scanf("%d")does the conversion internally but is less flexible. - atof/atoi do not detect errors — for validated input (form fields, config files, command-line flags), use strtol/strtod and check the end pointer. For throwaway scripts where invalid input is not a concern, atoi/atof are fine.
- Scientific notation — atof parses “1.5e2” as 150.0 (1.5 × 10²). This is standard C floating-point string format.
- The fgets + strcspn pattern — this is the canonical way to read a line in C safely. Memorize it:
fgets(buf, n, stdin); buf[strcspn(buf, "\n")] = '\0';
Related Programs
- Command Line Arguments in C
- sscanf in C
- sprintf in C
- ctype.h Character Classification in C
- sizeof Data Types in C
Recommended book:
The C Programming Language — Kernighan & Ritchie (India) |
(US)
|
C Programming: A Modern Approach — K.N. King (India) |
(US)
Practice what you learned: C Aptitude Questions — or try our C Programming Quiz App on Android.