Capture the input as a string.
Use strtod to convert to floating-point form.
Use the ability strtod gives you to identify the position of the first
character that could not be used in the conversion.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Richard Heathfield כתב:
Oh, I see. Well, in that case I suggest you capture the data as a string,
use strtod to convert to floating-point form, and use the ability strtod
Another way would be to capture the data as a string, use strtol to convert
to integer-form, and use the ability strtol gives you to identify the
position of the first character that could not be used in the conversion.
--
Andrew Poelstra <http://www.wpsoftware.net/projects>
To reach me by email, use `apoelstra' at the above domain.
"Do BOTH ends of the cable need to be plugged in?" -Anon.
<snip>
>
> Another way would be to capture the data as a string, use strtol to
> convert to integer-form, and use the ability strtol gives you to identify
> the position of the first character that could not be used in the
> conversion.
That wouldn't help him a lot with floating-point, which he specifically
mentioned he was using.
Oh; by `char' did he mean character? I was thinking tiny integer, and
figured that if strtol() said that a '.' was the first invalid character
(and the character after that was a digit), he could consider it floating
point.
> On 2006-08-05, Richard Heathfield <inv...@invalid.invalid> wrote:
>> Andrew Poelstra said:
>>
>><snip>
>>>
>>> Another way would be to capture the data as a string, use strtol to
>>> convert to integer-form, and use the ability strtol gives you to
>>> identify the position of the first character that could not be used in
>>> the conversion.
>>
>> That wouldn't help him a lot with floating-point, which he specifically
>> mentioned he was using.
>>
>
> Oh; by `char' did he mean character?
I think what he meant was that he was expecting:
3.14159
and was worried that he might get
THREE POINT ONE FOUR ONE FIVE NINE
or
ELEPHANT
instead.
> I was thinking tiny integer, and
> figured that if strtol() said that a '.' was the first invalid character
> (and the character after that was a digit), he could consider it floating
> point.
When you are asking the user for, say, the width of a square, it is not
unreasonable for the user to be able to enter a value without a decimal
point, or with one, and still expect the program to be able to calculate
that square's area. So the presence or absence of '.' is not a good test.
You should be able to write a simple fuzzer that hits your arguments
to make sure your program is properly checking inputs. Actually,
I would take this time to write a fuzzer to just learn how they are
built.
Ruby or Perl would both be good command line choices.
Here's an implementation of what the guys above are talking about:
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char **argv) {
char **endptr;
double output;
if(argc < 2) {
(void)printf("usage: strtof <digit>\n");
exit(1);
}
output = strtod(argv[1], endptr);
if (output == 0) {
perror("string to double conversion failed");
exit(1);
}
(void)printf("%f\n", output);
exit(0);
}
<snip>
>
> Here's an implementation of what the guys above are talking about:
>
> #include <stdio.h>
> #include <stdlib.h>
>
> int
> main(int argc, char **argv) {
>
> char **endptr;
Huh?
<snip>
> output = strtod(argv[1], endptr);
Wrong.
> > output = strtod(argv[1], endptr);
>
> Wrong.
Why is this wrong? If all he is doing is testing to see whether the
input is valid, then all he needs to know is if strtod can convert. If
you fuzz the input with anything but numbers, the conversion will fail.
$ gdb strtof
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and
you are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "amd64-unknown-openbsd4.0"...
(gdb) break main
Breakpoint 1 at 0x40089f: file strtof.c, line 12.
(gdb) run aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Starting program: /anime/strtof
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Breakpoint 1, main (argc=2, argv=0x7f7ffffd4870) at strtof.c:12
12 if(argc < 2) {
(gdb) step
17 output = strtod(argv[1], endptr);
(gdb) info locals
endptr = (char **) 0x7f7ffffd4860
output = 6.9261942529720109e-310
(gdb) until
18 if (output == 0) {
(gdb) info locals
endptr = (char **) 0x7f7ffffd4860
output = 0
(gdb) p *endptr
$1 = 0x7f7ffffd4d26 'a' <repeats 46 times>
Please explain why this is a bad approach.
>> > output = strtod(argv[1], endptr);
>>
>> Wrong.
>
> Why is this wrong?
Because you're evaluating an indeterminate value - to wit, endptr.
It should be:
output = strtod(argv[1], &endptr), and endptr
should be declared as char *.
But I don't understand why you will consider
it a failure if the user enters "0"--that seems like a valid
input. It might be more appropriate to check
for *endptr == argv[1], or perhaps **endptr == '\0'.
> It might be more appropriate to check
> for *endptr == argv[1], or perhaps **endptr == '\0'.
Now, I do agree with that approach. That's a far better way
to check the value. You would also check for ERANGE
and limits within HUGE_VAL.
This approach is documented in strtol(3).
Brian
<snip>
> It might be more appropriate to check
> for *endptr == argv[1], or perhaps **endptr == '\0'.
No, because once you define endptr properly as char *, *endptr will be a
char, not a char *.
But you're right in that finding out where the conversion stopped happening
is your first step in validating the data.
> Andrew Poelstra said:
>
> <snip>
>>
>> Another way would be to capture the data as a string, use strtol to
>> convert to integer-form, and use the ability strtol gives you to
>> identify the position of the first character that could not be used in
>> the conversion.
>
> That wouldn't help him a lot with floating-point, which he specifically
> mentioned he was using.
Using strtol is possible, but it must be used thoughtfully:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
/*
* Validates numbers of the form n{0,6}[.[n{0,6}]]
*/
float
validate_float(const char *data)
{
long whole, fractional;
static long powers [] = {1, 10, 100, 1000, 10000, 100000, 1000000};
#define MAXFRACT (sizeof(powers)/sizeof(powers[0])-1)
char *decptr, *endptr;
int decimals;
float number;
/* Nip out empty strings and naked decimal. NOTE: Adjust to locale. */
if (!strlen(data) || !strcmp(data, ".")) return -1;
/* Get whole part */
whole = strtol(data, &decptr, 10);
/* Verify that whole part is in range */
if (whole < 0 || whole == LONG_MAX) return -1;
/* Return whole number here. */
if (!*decptr) return whole;
/* Demand decimal point. NOTE: Adjust to locale. */
if (*decptr != '.') return -1;
/* Get fractional part if any */
fractional = strtol(decptr+1, &endptr, 10);
/* Check fractional part for bad characters */
if (*endptr) return -1;
/* Verify that fractional part is in range. */
if (fractional < 0 || endptr - (decptr+1) > MAXFRACT) return -1;
/* Make fractional adjustment */
decimals = strlen(decptr+1);
if (decimals > MAXFRACT) decimals = MAXFRACT;
/* Calculate number */
number = whole + (double)fractional/powers[decimals];
return number;
}
int
main(int argc, char *argv[])
{
double converted;
#define DOSTRING(STRING) do { \
converted = validate_float(STRING); \
if (converted < 0) printf("invalid '"STRING"'\n"); \
else printf(STRING" -> %f\n", converted); \
} while(0)
/* Invalid */
DOSTRING("");
DOSTRING(".");
DOSTRING("0.x");
DOSTRING("0.0x");
DOSTRING("123456.1234567");
DOSTRING("-1");
/* Valid */
DOSTRING("0");
DOSTRING(".0");
DOSTRING("0.");
DOSTRING("0.0");
DOSTRING("1");
DOSTRING(".1");
DOSTRING("1.");
DOSTRING("1.1");
DOSTRING("123456");
DOSTRING(".123456");
DOSTRING("1.123456");
return 0;
}
invalid ''
invalid '.'
invalid '0.x'
invalid '0.0x'
invalid '123456.1234567'
invalid '-1'
0 -> 0.000000
.0 -> 0.000000
0. -> 0.000000
0.0 -> 0.000000
1 -> 1.000000
.1 -> 0.100000
1. -> 1.000000
1.1 -> 1.100000
123456 -> 123456.000000
.123456 -> 0.123456
1.123456 -> 1.123456
Gratuitously,
Martin
--
Martin Golding | You don't need computers to screw things up,
DoD #236 BMWMOA #55952 | but it does make the work go faster. (Ed)
fog...@comcast.net Vancouver, WA
<snip>
> invalid '123456.1234567'
> invalid '-1'
On what grounds do you reject these? And why does your code reject 1e-6 ?
>
> But I don't understand why you will consider
> it a failure if the user enters "0"--that seems like a valid
> input. It might be more appropriate to check
> for *endptr == argv[1], or perhaps **endptr == '\0'.
I changed endptr to a char *. I don't think it really matters as I
would be de-referencing that variable anyway. I would like to hear why
you prefer that approach. Is it code readability?
Here's a working version:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
int
main(int argc, char **argv) {
char *endptr;
char *input;
double output;
input = argv[1];
if(argc < 2) {
(void)printf("usage: strtof <digit>\n");
exit(1);
}
output = strtod(input, &endptr);
if (input[0] == '\0' || *endptr != '\0') {
perror("string to double conversion failed");
exit(1);
}
(void)printf("%f\n", (float)output);
exit(0);
}
Here are some debugging results:
$ gdb strtof
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and
you are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "amd64-unknown-openbsd4.0"...
(gdb) break main
Breakpoint 1 at 0x40089f: file strtof.c, line 13.
(gdb) run 0a1b2c
Starting program: /anime/strtof 0a1b2c
Breakpoint 1, main (argc=2, argv=0x7f7ffffec080) at strtof.c:13
13 input = argv[1];
(gdb) info locals
endptr = 0x7f7ffffec070 ""
input = 0x7f7ffffec528 "/anime/strtof"
output = 4.1461860541929491e-317
(gdb) step
14 if(argc < 2) {
(gdb) step
19 output = strtod(input, &endptr);
(gdb) until
20 if (input[0] == '\0' || *endptr != '\0') {
(gdb) info locals
endptr = 0x7f7ffffec537 "a1b2c"
input = 0x7f7ffffec536 "0a1b2c"
output = 0
(gdb) p *endptr
$1 = 97 'a'
(gdb) p input[0]
$2 = 48 '0'
(gdb) step
21 perror("string to double conversion failed");
(gdb)
and here are some results to show that I can now enter a 0 as a valid
entry:
$ gdb strtof
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and
you are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "amd64-unknown-openbsd4.0"...
(gdb) break main
Breakpoint 1 at 0x40089f: file strtof.c, line 13.
(gdb) run 0
Starting program: /anime/strtof 0
Breakpoint 1, main (argc=2, argv=0x7f7fffff5d18) at strtof.c:13
13 input = argv[1];
(gdb) info locals
endptr = 0x7f7fffff5d00 ""
input = 0x7f7fffff61c0 "/anime/strtof"
output = 4.1461860541929491e-317
(gdb) step
14 if(argc < 2) {
(gdb) step
19 output = strtod(input, &endptr);
(gdb) until
20 if (input[0] == '\0' || *endptr != '\0') {
(gdb) info locals
endptr = 0x7f7fffff61cf ""
input = 0x7f7fffff61ce "0"
output = 0
(gdb) p input[0]
$1 = 48 '0'
(gdb) p *endptr
$2 = 0 '\0'
(gdb) step
24 (void)printf("%f\n", (float)output);
(gdb) info locals
endptr = 0x7f7fffff61cf ""
input = 0x7f7fffff61ce "0"
output = 0
(gdb)
>
> Bill Pursell wrote:
>
>>
>> But I don't understand why you will consider
>> it a failure if the user enters "0"--that seems like a valid
>> input. It might be more appropriate to check
>> for *endptr == argv[1], or perhaps **endptr == '\0'.
>
> I changed endptr to a char *. I don't think it really matters as I
> would be de-referencing that variable anyway.
It matters very much, because strtod expects the /address/ of an object that
has type char *. You do it like this:
char *endptr;
double d = strtod(s, &endptr);
if(endptr == s)
{
no characters were converted, so you know that the input was not a valid
text representation of a double.
> It matters very much, because strtod expects the /address/ of an object that
> has type char *. You do it like this:
>
> char *endptr;
> double d = strtod(s, &endptr);
>
I follow you. However, strtod expects a parameter of type char **. I
can pass the address of a pointer, or I can just pass a variable of
type char **. Either way, the only thing that changes is how I
dereference the pointer when the function returns.
Here's the same program with endptr declared as char **:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
int
main(int argc, char **argv) {
char **endptr;
char *input;
double output;
input = argv[1];
if(argc < 2) {
(void)printf("usage: strtof <digit>\n");
exit(1);
}
output = strtod(input, endptr);
if (**endptr != '\0') { /* dereference of pointer changes */
perror("string to double conversion failed");
exit(1);
}
(void)printf("%f\n", (float)output);
exit(0);
}
The above passes gcc -Wall -pedantic without warning.
> if(endptr == s)
> {
> no characters were converted, so you know that the input was not a valid
> text representation of a double.
> }
Now, if I entered:
12......222.....222
strtod() would convert the first two digits in your example and dump
them to output. If you really wanted to be particular, you could also
check for NOP sleds as well. Of course, this would reduce the
portability of your code.
>
> Richard Heathfield wrote:
>
>> It matters very much, because strtod expects the /address/ of an object
>> that has type char *. You do it like this:
>>
>> char *endptr;
>> double d = strtod(s, &endptr);
>>
>
>
> I follow you. However, strtod expects a parameter of type char **. I
> can pass the address of a pointer, or I can just pass a variable of
> type char **.
Yes, that will /compile/, but it won't /work/.
> Either way, the only thing that changes is how I
> dereference the pointer when the function returns.
No. What changes is that, if you do this wrong, it won't work. Think about
*why* strtod needs a char **, and maybe enlightenment will occur, although
frankly I'm beginning to doubt that it will.
> Yes, that will /compile/, but it won't /work/.
Here's a debugging session that shows that it doesn't matter what
approach you take:
with invalid input:
$ gdb strtof
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and
you ar
welcome to change it and/or distribute copies of it under certain
condition
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "amd64-unknown-openbsd4.0"...
(gdb) break main
Breakpoint 1 at 0x40089f: file strtof.c, line 13.
(gdb) run 1a1a1a1a1a
Starting program: /anime/strtof 1a1a1a1a1a
Breakpoint 1, main (argc=2, argv=0x7f7ffffc98a8) at strtof.c:13
13 input = argv[1];
(gdb) info locals
endptr = (char **) 0x7f7ffffc9890
input = 0x7f7ffffc9d50 "/anime/strtof"
output = 4.1461860541929491e-317
(gdb) step
15 if(argc < 2) {
(gdb) info locals
endptr = (char **) 0x7f7ffffc9890
input = 0x7f7ffffc9d5e "1a1a1a1a1a"
output = 4.1461860541929491e-317
(gdb) step
21 output = strtod(input, endptr);
(gdb) until
22 if (**endptr != '\0') {
(gdb) info locals
endptr = (char **) 0x7f7ffffc9890
input = 0x7f7ffffc9d5e "1a1a1a1a1a"
output = 1
(gdb) p **endptr
$1 = 97 'a'
(gdb) step
23 perror("string to double conversion failed");
(gdb)
with valid input:
$ gdb strtof
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and
you a
e
welcome to change it and/or distribute copies of it under certain
conditio
s.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details
This GDB was configured as "amd64-unknown-openbsd4.0"...
(gdb) break main
Breakpoint 1 at 0x40089f: file strtof.c, line 13.
(gdb) run 12.2
Starting program: /anime/strtof 12.2
Breakpoint 1, main (argc=2, argv=0x7f7ffffc8ca8) at strtof.c:13
13 input = argv[1];
(gdb) info locals
endptr = (char **) 0x7f7ffffc8c90
input = 0x7f7ffffc9150 "/anime/strtof"
output = 4.1461860541929491e-317
(gdb) step
15 if(argc < 2) {
(gdb) info locals
endptr = (char **) 0x7f7ffffc8c90
input = 0x7f7ffffc915e "12.2"
output = 4.1461860541929491e-317
(gdb) step
21 output = strtod(input, endptr);
(gdb) until
22 if (**endptr != '\0') {
(gdb) info locals
endptr = (char **) 0x7f7ffffc8c90
input = 0x7f7ffffc915e "12.2"
output = 12.199999999999999
(gdb) p **endptr
$1 = 0 '\0'
(gdb) step
26 (void)printf("%f\n", (float)output);
(gdb) until
12.200000
27 exit(0);
(gdb)
I have no problem being wrong. Please show me that the above does not
/work/.
I do agree that checking for output == 0 was wrong.
It shows no such thing. At best, it shows that it can *appear* to
work.
The second argument to strtod() is char **endptr. You pass a
pointer-to-pointer-to-char so that the function can *store* a
pointer-to-char value in the location you specify.
If you call it like this:
char **endptr; /* uninitialized */
... strtod("123", endptr) ...
you are passing the value of an uninitialized variable to the
function. An uninitialized pointer points to some arbitrary location
in memory; you're asking strtody() to write to that arbitrary
location. If it happens, by random chance, that that arbitrary
location is one that you're able to write to, the code will appear to
work -- but it's likely to clobber some other variable.
Don't do that.
By contrast, if you do this:
char *end;
... strtod("123", &end) ...
then "end" is uninitialized, but you're passing its *value*, not its
*address*, so that's ok. You're still passing a value of type char**
to strtod(), but now the value specifies the address of the char*
variable that you've declared. You're now asking strtod() to write a
value to "end" -- which is exactly what you want.
--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
<snip>
> I have no problem being wrong. Please show me that the above does not
> /work/.
> I do agree that checking for output == 0 was wrong.
The standard states that it invokes undefined behaviour. Therefore it
invokes undefined behaviour. One possible result of undefined behaviour
is it doing what you expect. Another possible result is your program
crashing. A third result is your computer being fried. A forth possible
result is your computer growing arms and legs, tying you up, putting you
in the boot of the car, and driving the car off a cliff killing you.
Richard Heathfield is a highly respected member of this group and
acknowledged around here as knowing a few things about C. You are just
learning. Think about who is more likely to be wrong and reread the
messages explaining why you are wrong.
--
Flash Gordon
Only about 11 years experience in C but over 20 years in programming.
A relative newbie for this group.
<snip>
>
> By contrast, if you do this:
>
> char *end;
> ... strtod("123", &end) ...
>
> then "end" is uninitialized, but you're passing its *value*, not its
> *address*, so that's ok.
Er, actually you're passing the value of its address. The expression is okay
because &end doesn't evaluate end. It yields the address of end. That
address's value is what strtod gets.
>
> Richard Heathfield wrote:
>
>> Yes, that will /compile/, but it won't /work/.
>
> Here's a debugging session that shows that it doesn't matter what
> approach you take:
No, it's a debugging session that shows that you don't understand that
debugging sessions do not define the C language.
<snip>
> I have no problem being wrong.
Evidently.
> Please show me that the above does not /work/.
"If the subject sequence is empty or does not have the expected
form, no conversion is performed; the value of nptr is stored in the
object pointed to by endptr, provided that endptr is not a null
pointer."
If endptr does not point to an object (and is not NULL) then the behaviour
is necessarily undefined.
> I do agree that checking for output == 0 was wrong.
This isn't a matter of debate. The C language definition says the way you're
doing it is wrong, and therefore the way you're doing it is wrong.
Sorry, my fingers have betrayed me again.
What I meant, of course, was:
then "end" is uninitialized, but you're passing its *address*, not
its *value*, so that's ok.
As always, thanks for keeping me on my toes.
Upthread, Richard advised you to *think* about why strtod() takes a
char** arguments. That was excellent advice; following it would have
saved you some time. Rather than thinking about it you experimented
and got some meaningless results.
bwa...@yahoo.com <bwa...@yahoo.com> wrote:
>I follow you. However, strtod expects a parameter of type char **. I
>can pass the address of a pointer, or I can just pass a variable of
>type char **.
Not exactly: you can pass the *value* of a variable of type
"char **". (You never pass "a variable" in C, only "a value".)
>Here's the same program with endptr declared as char **:
>
>#include <stdio.h>
>#include <stdlib.h>
>#include <errno.h>
>#include <math.h>
>
>int
>main(int argc, char **argv) {
>
> char **endptr;
> char *input;
> double output;
>
> input = argv[1];
>
> if(argc < 2) {
> (void)printf("usage: strtof <digit>\n");
> exit(1);
> }
>
>
> output = strtod(input, endptr);
> if (**endptr != '\0') { /* dereference of pointer changes */
> perror("string to double conversion failed");
> exit(1);
> }
> (void)printf("%f\n", (float)output);
> exit(0);
>}
>
>The above passes gcc -Wall -pedantic without warning.
You should add "-O" (and -ansi, but in this case it is the -O that
is important):
% gcc -O -Wall -ansi -pedantic -o t t.c
t.c: In function `main':
t.c:9: warning: `endptr' might be used uninitialized in this function
The reason you need -O to get this warning is that gcc only runs
the dataflow analysis phase when optimizing, and it is the dataflow
analysis phase that discovers use of uninitialized variables.
If I move "char **endptr" down to the third variable, and compile
it on BSD/OS with shlicc (which uses gcc), without -O, and run the
resulting binary, I get:
% shlicc -o t t.c
% ./t 123.456
Segmentation fault (core dumped)
Turning on optimization makes it run, as does using "cc" (which
uses the dynamic linker instead of static shared libraries). Both
of these are "mere luck" (*bad* luck :-) ) -- with -O, gcc moves
the variables around, and when using the dynamic linker, the place
"endptr" lives on the stack happens to get some value stored in it
that points to some other valid address within the process. The
static shared library ("shlicc") version is much more efficient,
though, so that the stack is still "mostly clean" and endptr happens
to be NULL (as long as it is the third variable, not the first).
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
> Er, actually you're passing the value of its address. The expression is okay
> because &end doesn't evaluate end. It yields the address of end. That
> address's value is what strtod gets.
I am going to spin this discussion off into another thread. I never
distinguished a difference between the two methods above of passing a
parameter.
> The reason you need -O to get this warning is that gcc only runs
> the dataflow analysis phase when optimizing, and it is the dataflow
> analysis phase that discovers use of uninitialized variables.
>
This helps a lot since I tend to use debugging sessions to find errors.
And I am wrong.
Thanks!
strtod writes to the pointer you pass it. This debug trace shows
that your system allowed you to write to a random memory
address (ie. 7f7fffc9890) without any bad effects, in this case.
I'm sure many people will tell you that writing to a random
memory address can, in general, cause a segfault, or even
worse, the ability for violation of security privileges (and they
would be right).
Tip: If you ever apply for a C programming job, don't tell
the interviewer that you like to write code that writes to
random memory addresses.
> strtod writes to the pointer you pass it. This debug trace shows
> that your system allowed you to write to a random memory
> address (ie. 7f7fffc9890) without any bad effects, in this case.
>
> I'm sure many people will tell you that writing to a random
> memory address can, in general, cause a segfault, or even
> worse, the ability for violation of security privileges (and they
> would be right).
>
> Tip: If you ever apply for a C programming job, don't tell
> the interviewer that you like to write code that writes to
> random memory addresses.
I think I follow you. It's because I never initialized char *endptr
since I declared it as char **endptr. So when I passed it as a
parameter,
the compiler randomly assigned the location of char *endptr.
And you don't have to worry about me applying for any C programming
job. I have worked in finance for the last 6 years.
I posted to this thread because I am writing a httpd server (off topic
and OS specific), and I need to practice parsing out the request
strings (not quite C strings). I figured this would give me a good
refresher on data validation. (I have never used strtod until
yesterday.) The good thing is that I learned something new by posting
code that wasn't quite right. I will keep posting code if it means I
will receive good responses.
Thanks!
>>Richard Heathfield wrote:
> In article <1154888765.3...@h48g2000cwc.googlegroups.com>
Chris: No, I didn't.
<snip>
why don't change above in:
char **endptr=0;
for me it has to segfault
the right definition should be
char *endptr=0;