strtof() producing weird results in C - c

first of all, compiling with flags -Wall, -ansi, -pedantic. no warnings or errors. and no debugging is helping.
basically my code is working fine however returning very weird and unexpected results when I turn a token from a string to a float using strtof()
the section of code below is:
printf("token is %s\n", token);
newstockdata->unitPrice = strtof(token, NULL);
printf("price is %d\n", newstockdata->unitPrice);
newstockdata is allocated to the correct size: unitPrice is a float variable: the first printf statement prints "150.00": the second printf statement prints "0" but after a few iterations it returns a really long consistent number. any help please?

The problem is here, assuming that unitPrice is a float:
printf("price is %d\n", newstockdata->unitPrice);
To print a float you must use the %f specifier. Otherwise, it is undefined behaviour and anything could happen.
A possible explanation of the changing values you see might be that your system passes floats in a different register to ints. The printf receiving %d is looking in a register that is never set, so you are seeing whatever value was left over from some previous operation.
This is actually pretty common, here is an example - %esi is used for the int, and %xmm0 is used for the floating-point value.

You have to handle overflow cases. After calling strtof() check errno for overflow. If you think the values could be very long, you can use double or long double.

Related

Input hexadecimal floating point number using scanf() and conversion specifier "%a"

I'm testing conversion specifiers both for printf() and scanf() function. I hadn't problem with %a format specifier for floating point hexadecimal number used in printf() function. It displayed what I expected. But I encountered problem when I wanted to input hexadecimal float using
scanf("%a", &var);
I'm using the following code:
#include <stdio.h>
int main()
{
float var;
printf("Enter variable:\n");
scanf("%a", &var);
printf("var = %f\n", var);
printf("var = %e\n", var);
printf("var = %a\n", var);
return 0;
}
When I enter a sample value, e.g. 0x1.205b0cp-11 that is 5.5e-4 it gives me that result:
Enter variable: 0x1.205bc0p-11
var = 0.000000 var = 0.000000e+000 var = 0x0.000000p+0
Whatever number I enter it always gives me 0. What's the reason or solution for that problem. I have no idea what I'm making wrong.
That code works on my system(a), producing the expected result:
pax> ./prog
Enter variable: 0x1.205bc0p-11
var = 0.000550
var = 5.500000e-04
var = 0x1.205bcp-11
Keep in mind that hexadecimal floating point constants (and the %a conversion specifier) were introduced in C99, so you should make sure you're using a compiler that handles that. Most modern ones will, but some people may be locked in to a certain level if the vendor isn't keen on keeping up to date(b).
Keep in mind that the scanf family, conversion specifiers a, e, g, and f (and their upper-case variants) are all the same - they each handle every format that strtod handles. The (likely) reason that they all exist is to mirror the printf conversion specifiers where it makes a difference to how the value is output.
It's possibly worth testing with a variety of inputs less advanced than hex floating point, and work your way up to there. For example, the sequence { 0, 3, 3.1, 3.14159. 9e2, 6e-2, ... }. That would at least let you know where the input is failing.
Also, it's a good idea to test the conversion to ensure it works (this is true of all calls where failure can adversely affect future program behaviour). In other words, something like this in place of your scanf statement:
if (scanf("%a", &var) != 1) {
fprintf(stderr, "Something went horribly wrong!\n");
return 1;
}
(a) My system, by the way, is gcc 9.4.0 (from gcc --version) running on Ubuntu 20.04.2 (from cat /etc/lsb_release). It's often a good idea to include that sort of information in questions, it can help us figure out issues more quickly.
(b) Possibly a good reason to consider changing vendors though, of course, subject to normal cost/benefit analysis.
Try computing somehow like with printf("var = %e\n", var/7.0 + var *var);. Sometimes simple code without doing any math does not link in the math library needed by printf().

Does "is_linux" variable have special meaning?

I don't understand why the result of the if statement below is always incorrect:
unsigned long is_linux;
printf("plz. enter a digit : ");
gets(str);
sscanf(str,"%d",&is_linux);
printf("the value of is_linux = %d \n",is_linux);
if(is_linux==1)
printf("Here is 1 ! \n");
else
printf("There is 0 ! \n");
I can only get "There is 0 !" statement, even if I entered "1". Furthermore, printf() statement displays the value of is_linux (1) correctly:
plz. enter a digit : 1
the value of is_linux = 1
There is 0 !
It works well if I change the variable to another name, for instance,test. Is there any reason for not using is_linux variable ? I've compiled above source code using gcc at x86_64-redhat-linux.
In your code
sscanf(str,"%d",&is_linux);
causes undefined behavior.
is_linux is of type unsigned long, it demands the conversion specifier to be lu.
Passing wrong (mismatched) type of argument to any conversion specifier causes undefined behavior.
No. You should be able to use the variable name. is_linux is not reserved and it's not a keyword. Worst-case scenario, it could (but shouldn't) be a macro (linux commonly is, unfortunately). Preemptively, or if you get compilation errors because it is a macro on your platform, you could #undef it first.
(Make sure the rest of your code is correct.)
The datatype you are assigning to is_linux is not compatible. You set it as a long, but giving it an int so when you check with your if statement you are checking for a long value, not int.
Thank you so much, there.
All comments were very helpful to me for finding root cause.
Actually, it was very simple reason, data type.
Simply, I changed %d to %lu in both of sscanf and printf and got correct answer.
My machine was 64bit lunux system and it treated unsigned long as 8-byte unit.
And also, I misunderstood %d could cover all the integer data types.
Anyway, I'm very appreciate all you guy's comments. Thank you :)

Functions and arguments giving error

The result of this code down below should be 30, however when compiled and run this is giving me the following result
the result of 2358968 and 0 is 4200271, a , b , result
I
don't understand when I have no variables of that value how could the result be like that?
#include<stdio.h>
#include<conio.h>
void add( int , int );
int main(){
add(10,20);
getch();
return 0 ;
}
void add(int a, int b){
int result = a + b;
printf("the result of the %d and %d is %d, a, b, result");
}
In your code,
printf("the result of the %d and %d is %d, a, b, result");
should be
printf("the result of the %d and %d is %d\n", a, b, result);
^
|
//format string ends here
// arguments for format specifiers are meant to be
// supplied as different arguments to `printf()`, not as a part of <format> string itself
From the man page of printf()
int printf(const char *format, ...);
and
The functions in the printf() family produce output according to a format ....
So basically your code should be
printf("<format>", var1, var2,....);
The supplied variables are not part of the format.
The problem in your code were missing variables (arguments) for supplied format specifiers. As per the C11 standard , chapter 7.21.6.1, paragraph 2
[...] If there are insufficient arguments for the format, the behavior is
undefined. [...]
So, your code produces undefined behaviour printning out some junk value.
Moral of the Story : If you had enabled compiler warnings, you compiler should warn you about missing (mismatch) agruments in printf(). So, always enable warnings.
You have closed the " at the end of the line. and in the printf function you have specified the %d So the %d will not have the variable to point and fetch the value.
You will get the warning message that %d expects a matching int
It will have the garbage value in that position, So it is printing some value.
Sourav Ghosh answered to most of your questions; he rightly suggested to enable all warnings when compiling. If your compiler is (notably on Linux) some recent GCC or Clang/LLVM pass -Wall -Wextra -g to the gcc or clang command (to get nearly all warnings, some extra ones, and debug information). Others compiler options (-fsanitize=address etc etc...) and other tools (the gdb debugger, the valgrind tool, strace, ...) might be useful too!
I dont understand when I have no variables of that value how could the
result be like that?
Because you have encountered undefined behavior. Read much more about it (in particular Lattner's blog on What Every C Programmer should know about Undefined Behavior), and work hard to always avoid it in all cases. Be aware that with UB, your (or any other) program might seems to work while in fact it has some undefined behavior.
The particular garbage (or apparently random) values that are printed : might not be reproducible, and can be explained only by diving into every implementation details, including looking into the machine code generated by your particular compiler and inspecting some machine state (register values); concretely the printf implementation on your system is probably using some stdarg(3) things and fetching some values from uninitialized memory or register which happens to have some previous "garbage" value (at the machine level).
See also this answer (and many others) about undefined behavior. Work hard to always avoid it.
Remember that when coding (even in C) you are ultimately coding for some virtual or abstract machine which is not the real computer. Even if writing all the software levels from the operating system kernel included - that would take you many dozens of years at least -, you are coding for some specified abstraction and you have to ignore some misbehavior of your computer (e.g. if it breaks, get some cosmic rays, etc etc...) outside of these abstractions. The C99 or C11 programming language standard specification (a technical document of several hundred pages in English), with the POSIX 2008 operating system specification, are useful abstractions to code software for.
printf statement is the reason for undesired output,
printf("the result of the %d and %d is %d, a, b, result");
There is no arguments specified for format specifier, the position of " has to be changed.
the statement should be like this
printf("the result of the %d and %d is %d", a, b, result);
In your printf statement it was taking garbage value since no arguments were specified there for %d.
printf("the result of the %d and %d is %d, a, b, result");
it has to be
printf("the result of the %d and %d is %d", a, b, result);
it will read and assign the %d value from left to write.
printf returns number of characters

Why and how does printf pick out matching arguments?

Someone has asked me, why this code produces a random number:
double a = 75.0;
printf("%d\n", a);
I thought the reason was that 4 bytes of the double are interpreted as an integer, but the printed value was different each time the program was run. So i started to try some more things and found that this:
printf("%d\n", 75.0, 6);
actually prints out number 6. So i thought that the compiler is trying to fix the arguments so that they match the format string, but then i tried this:
const char *formats[] = { "%d %.1f\n", "%.1f %d\n" };
int whichFormat = 0;
scanf("%d", &whichFormat);
printf(formats[whichFormat&1], 2.5, 7, 1.2);
The formatting string now isn't even known at compile time, but it still somehow manages to match the argument types to the formatting string, printing either 7 2.5 or 2.5 7 depending on the input. The last value (1.2) was not printed.
All of this can be reproduced at compileonline.com which claims to be using GNU GCC 4.8.1.
What is going on here?
Undefined behavior is going on.
Such behavior is undefined, so it's very hard to reason about, and also somewhat pointless to do experiments, since there's no guarantee that the behavior stays the same (i.e. well-defined) for the same input. The behavior is, after all, undefined.
The first example, for instance, might read an expected integer argument from one register, while the actual floating-point argument is in another. I'm not saying this is what happens on any known machine, but it could be like that.

C function printf() limited in length?

Upon calling the sprintf function to format a string, something unexpected was printed
printf("%d;%s;%s;%d;%d;\n", ptr->programmaType, ptr->titel, ptr->zender, ptr->start, ptr->einde);
prints "0;Stargate;scifi;0;0;" while
printf("%d;", ptr->einde);
prints "42", which is the value of ptr->einde. I've also tried
printf("%d;%s;%s;%d;%d;", 0, "Stargate", "scifi", 0, 42);
which prints correctly, so I'm guessing the problem is related to the variables. Last thing I tried was
int bug = ptr->einde;
printf("%d;%s;%s;%d;%d;\n", ptr->programmaType, ptr->titel, ptr->zender, ptr->start, bug);
which also failed to print correctly... I have no idea what the hell is happening.
Note: ptr->start and ptr->einde are defined als time_t types, but seeing as printf works with a single argument I doubt that's a problem.
You said that ptr->start and ptr->einde are time_t type. This type is not not fully portable and can be any "integer or real-floating type", so it's possible that they are not being handled correctly on your system when you try to print them as int types.
Try casting it to something known and then printing:
printf("%d;%s;%s;%ld;%ld;\n", ptr->programmaType, ptr->titel,
ptr->zender, (long)ptr->start, (long)ptr->einde);
I guess your definition of ptr->einde is not of type int.
And you are using "%d" in the printf specifier which expects an int value.
Use the correct specifier for the correct type and printf behaves.
No printf is not limited in length, except in embedded implementations where it must be able to print at least 4095 chars.
time_t is probably a 64 bit integer value. The solution is to cast your variable to (uint64_t) and using PRIu64 format specifier.
printf("%d;%s;%s;%"PRIu64";%"PRIu64";\n",
ptr->programmaType,
ptr->titel, ptr->zender,
(uint64_t)ptr->start,
(uint64_t)ptr->einde);

Resources