Just for background, I’m trying to write a scientific calculator in C for this here school project. We have to convert an equation taken from an input file into postfix, and then go on and do whatever to it. We’re provided with a file that includes nextToken(FILE*), which takes the next “token” from the file, be it a number, operator, parenthesis or what have you. The problem is that it only returns it as a char*, and we have to figure out what exactly it is before we put it into the result.
I figure the best way is to see if it’s a number first. I’m trying this with strtod(), and seeing if the end pointer set by it is different from the pointer to the token string, which should mean that something was converted, and thus that a number was found. (We can also use PI and E in our equations, so that’s what’s going on with those.)
double operand = 0.0;
char *token;
token = (char*) malloc(20);
while (token = (char*) nextToken(fp)) {
char *pp = 0;
if (!strcmp(token, "PI"))
operand = M_PI;
else if (!strcmp(token, "E"))
operand = M_E;
else
operand = strtod(token, &pp);
if (**pp != token**) {
/* do crap */
}
}
My problem is the bolded code: it makes a segmentation fault happen. Commenting that part out makes the whole thing work, and printf()ing pp and token with %p will even show the right addresses, depending on what I know is going into token. Judging from a combination of my own learning and Google searches, it should work. It just doesn’t. Am I confused about pointers again?
(I even tried comparing the strlen() of pp and token, thinking that they would be the same if no conversion happened. No dice, but hey, it was worth a shot.)
The only way that “if (pp != token)” could possibly cause a segmentation fault is if something smashed the stack so that the addresses of either pp or token were off in never-never land.
Note that some debuggers will point to the NEXT statement AFTER the one that crashed when indicating a segment fault. You sure it’s not the “operand = strtod(token, &pp);” statement that’s crashing? (If worse comes to worst, try compiling with optimizations turned off. Optimization bugs are known to exist here and there.)
I’m seeing a problem with the malloc() call. You need to check and make sure the pointer returned by malloc() is not NULL. malloc() returns such if it is unable to allocate the requested memory. If you’re getting a null pointer back, and using it anyway, all sorts of weird stuff can happen. Other than that, it looks like it should work.
Like tracer, I can’t see how a simple comparison statement can cause a crash under normal circumstances. Even if the pointers are pointing to strange memory locations, simply looking (not using) at the pointer’s value shouldn’t cause a crash, unless stuff was screwed up before that.
I notice that you malloc some memory and promptly discard it. This is a memory leak. While this (probably) isn’t the cause of your seg fault, you will want to do something about it.
I also don’t see any way for the comparison itself to cause a segfault. But note that if the input token is E or PI then pp is still 0 at the bolded line. Since token!=0, the /do crap/ will be executed. If you try to use *pp then you will get a segfault.
I disagree. The second argument he passes to strtod() is &pp, not pp. Since &pp is not null, strtod should fill pp with the address of the unconverted suffix.
Your problem may be that the while loop doesn’t work properly (usually it would involve “while (x == whatever)”). That while loop might go on forever due to whatever boolean value the thing after the while evaluates to. nextToken(fp) might cause pp to go past the memory that’s allocated to itself. Just a wild guess.
You could do this:
Insert “token = (char*) nextToken(fp);” before the while loop, and right at the end of the while loop. Then make the while loop say “while (token != NULL)” or maybe “while (token)”. Just a guess.
My first point about the while loop is that your loop is in the form “while (x = y)” but it should be “while (x == y)” (or a similar conditional statement, e.g. involving >, <, or != )
Also, “token = (char*) nextToken(fp)” might cause token to go past the memory that’s allocated to itself.
The first problem is: is nextToken returning a (char *) to a static buffer that it owns? (If so, you’ll want to strncopy to your newly malloc’d 20 byte buffer, but CHECK that malloc didn’t return null). Or is it malloc’ing on your behalf (in which case (a) your initial malloc is redundant, and you’ll forever lose the address the first time it’s overwritten by nextToken and (b) you’ll want to free it at the end of the loop.
operand = strtod(token, &pp);
if (pp != token) {
There’s generally more than one way to skin a cat; Like the other responders, I don’t know why pp!=token is generating a segfault, but you should be able to check whether operand is a valid double by checking the length of pp (i.e. strlen(pp)); It’s guaranteed to contain a) any unrecognised/unparsed characters then b) the original strings terminating null (so strlen shouldn’t ride off into the sunset.
If all that doesn’t help, maybe try looking at sscanf, which returns the number of correctly parsed elements (the args are different to strtod, so you’ll have to look it up). Anyhow, hope some of this helps…
[QUOTE=panamajack]
As for the seg fault, is it true that you can do equality/inequality with non-NULL pointers not in the same array? Perhaps this is the problem.
QUOTE]
In C and C++ you can do whatever you within a test, and it will count as “true” if the code inside the test returns non-zero, and “false” if the code inside the test evaluates to zero. Other languages may be more strongly typed.
Assignment operators “return” the value being assigned to the variable. So in your case you have
token = (char*) nextToken(fp)
If nextToken(fp) returns anything that is non-zero, it evaluates as true. And since the zero value of a char* is the same as “null”, the while loop will continue until the next token of fp is null.
Now this will be a problem if fp isn’t terminated properly, since the while loop will merrily traipse through memory until it finds a null.
Of course, using the assignment operator (’=’) inside a test is generally considered a bad style choice. People have a hard enough time remembering to use the double equals for comparisons (I’ve had single equals cause me quite a few problems with loops) without introducing situations where a single equals is the desired functionality.
Without knowing what compiler is being used, and without seeing the input file, my guess would be that Omphaloskeptic has nailed this one. pp should be initialized to token, and not to 0. The way the code is now, if the token is PI or E, the “if (pp!=token)” branch will be taken, and whatever is in there is causing the segfault. Obviously, if you comment out that whole if-then block, the segfault will vanish, but so will your functionality.
On another note, you might want to let people use “pi” or “e” instead of only their upper-case equivalents, and for source code clarity test the return value explicitly. In other words, turn “if (!strcmp(token,“PI”))” into “if (stricmp(token,“PI”)!=0)” Do it for the “E” test, as well.
Sorry, I was referring to the (pp != token) part (the apparent cause of the crash).
I know that >, <, etc. are undefined for pointers not in the same array, and I know that you can always compare to NULL, I just wasn’t sure about != or == (although now I think about it I’m pretty sure that you can). This would be easy to test with your compiler at any rate (possibly some optimization is converting != to another relational operator).
For this exact purpose it’s probably better to use something like memcmp, though I still think there’s better ways to do it.