Today I encountered a problem with scanf functions. Assume that you have a structure like the following example.
struct structA{
bool bVal;
int nVal;
}
If you run the following code
structA a;
a.nVal = 7;
...// Assume that we read a text file and the only text is "0"
fscanf(fp,"%d",&a.bVal);
printf("\n a.bVal=%d",a.bVal);
printf("\n a.nVal=%d",a.nVal);
It will print
a.bVal = 0
a.nVal = 0
The reason is that the fscanf function assumes a.bVal is an integer and overwrites the a.nVal first 3 bytes. This problem can be solved by the following dirty solution.
structA a;
a.nVal = 7;
...// Assume that we read a text file and the only text is "0"
int nBVAL;
fscanf(fp,"%d",&nBVAL);
a.bVal = nBVAL;
printf("\n a.bVal=%d",a.bVal);
printf("\n a.nVal=%d",a.nVal);
My question is that is there a cleaner and straightforward way of avoiding this problem beside the solution explained?
The solution you're proposing is the only portable one.
There is no conversion specifier for _Bool. There's also no guarantee about the storage size of a _Bool, except that it has at least CHAR_BIT bits. Even if you knew the size and tried something like %hhd, entering anything other than 1 or 0 would create a value that's invalid for a _Bool (scanf() would access the object through a char pointer, possibly writing the padding bits of the _Bool).
The only safe thing to do is to take input of a type you can handle and convert this to a _Bool where needed, as you're doing in your example.
Note there's no similar problem with printf(). A _Bool passed to printf() is promoted to int, so %d is fine.
Related
I want to print double to C string with sufficient precision to recover the original number, but with the minimal length of the output string.
I can try something like this which maintains the precision. But the output string is too long.
What is an efficient way (better than trial and error as in the discussion) to return the minimal length string?
#include <stdio.h>
int main() {
printf("%1.*e\n", __DBL_DECIMAL_DIG__ - 1, 1.); // print 1.0000000000000000e+00. I want just "1."
printf("%1.*e\n", __DBL_DECIMAL_DIG__ - 1, 1.00000001); // print 1.0000000099999999e+00. I want just "1.00000001"
return 0;
}
The string representation is not necessarily the same as the original double. The string has to be of the minimal length.
Only the printf's %g like string format is allowed. printf's %a is not what I am looking for.
Unnecessary digits must be removed as long as when it does not affect the converted double value. For example, For double x = 0.010, x converted to string must be .01. For double x = 1.0, x converted to string must be 1..
One simply implementation is this. But I'd expect something more efficient rather than trial and error.
#include <stdio.h>
#include <stdlib.h>
char *d2s(double x) {
char format[100];
static char buf[100];
double y;
int i = 0;
while(1) {
sprintf(format, "%%.%dg", i++);
sprintf(buf, format, x);
y = atof(buf);
if(x == y) {
return buf;
}
}
}
int main() {
double x = 11111.1111111;
printf("%s\n", d2s(x)); // print "11111.1111111" as wanted.
return 0;
}
Note that there are bugs in the above code. For example, 1. is printed as 1. Something better is needed.
You may check out the function dtoa_r in http://www.netlib.org/fp/dtoa.c. Be warned, the code is massively complex. If I were to roll out my own convertor, I'd use your example function. To ensure 1. is output with decimal point, insert # in the specifier (so it becomes %%#.%dg).
to recover the original number
C language is a language without reflection - it can't inspect it's own source code. What was in the source code is not visible in the executable - as in, you can't recover the source code of a program by inspecting the executable.
In the case of a floating-point constants, the value is converted to the internal representation when compiling the program (C11 6.4.4.2p5), so the value of a floating-point constant is rounded to the nearest representable value, smaller or larger, then the actual value (C11 J.3.6 How the nearest representable...). Most probably in your code on your platform 1.00000001 can't be represented exactly as double, so the value 1.00000001 never exists in the resulting executable and it's not possible to recover it from the executable in any way.
The only way to recover 1.00000001 is to inspect the source code of your own program - you can write your own build system for that and write your own parser for that. The other way you could use is to use processor # operator to stringify the argument and specify the constant twice:
#define STRING(x) #x
printf("%s is converted to %a\n", STRING(1.00000001), 1.00000001);
Why does this code below compiles and executes but doesn't print anything in output,
int i = 0;
printf(i = 0);
but this gives a runtime error,
int i = 0;
printf(i = 1);
int i = 0;
printf(i = 0);
The first argument to printf must be a char* value pointing to a format string. You gave it an int. That's the problem. The difference in behavior between printf(i = 0) and printf(i = 1) is largely irrelevant; both are equally wrong. (It's possible that the first passes a null pointer, and that printf detects and handles null pointers somehow, but that's a distraction from the real problem.)
If you wanted to print the value of i = 0, this is the correct way to do it:
printf("%d\n", i = 0);
You have a side effect in the argument (i = 0 is an assignment, not a comparison), which is legal but poor style.
If you have the required #include <stdio.h>, then your compiler must at least warn you about the type mismatch.
If you don't have #include <stdio.h>, then your compiler will almost certainly warn about calling printf without a declaration. (A C89/C90 compiler isn't strictly required to warn about this, but any decent compiler should, and a C99 or later compiler must.)
Your compiler probably gave you one or more warnings when you compiled your code. You failed to include those warnings in your question. You also failed to show us a complete self-contained program, so we can only guess whether you have the required #include <stdio.h> or not. And if your compiler didn't warn you about this error, you need to find out how to ask it for better diagnostics (we can't help with that without knowing which compiler you're using).
Expressions i = 0 and i = 1 in printf function will be evaluated to 0 and 1 (and i will be initialized to 0 and 1) respectively. So above printf statements after their expression evaluation will be equivalent to
printf(0); // To be clear, the `0` here is not a integer constant expression.
and
printf(1);
respectively.
0 and 1 both will be treated as address in printf statements and it will try to fetch string from these addresses. But, both 0 and 1 are unallocated memory addresses and accessing them will result in undefined behavior.
printf requires a const char * for input, whereas you're giving it an int
printf awaits a format string as its first argument. As strings (char*) are nothing else than pointers, you provide an address as the first parameter.
After an address and an integer are implicitly converted into each other,
printf(i = 0)
is (from the perspective of printf) the same as:
printf( 0 )
which is the same as
printf( NULL ) // no string given at all
If you provide 0 as parameter, printf will gracefully handle that case and don't do anything at all, because 0 is a reserved address meaning nothing at all.
But printf( 1 ) is different: printf now searches for a string at address 1, which is not a valid address for your program and so your program throws a segmentation fault.
[update]
The main reason why this works is a combination of several facts you need to know about how char arrays, pointers, assignments and printf itself work:
Pointers are implicitly convertible to int and vice versa, so the int value 17 for example gets converted to the memory address 0x00000011 (17) without any further notice. This is due to the fact that C is very close to the hardware and allows you to calculate with memory addresses. In fact, internally an int (or more specific: one special type of an integer) and a pointer are the same, just with a different syntax. This leads to a lot of problems when porting code from 32bit to 64bit-architecture, but this is another topic.
Assignments are different from comparations: i = 0 and i == 0 are totally different in meaning. i == 0 returns true when i contains the value 0 while i = 0 returns... 0. Why is that? You can concatenate for example the following variable assignments:
a = b = 3;
At first, b = 3 is executed, returning 3 again, which is then assigned to a. This comes in handy for cases like testing if there is more items in an array:
while( (data = get_Item()) )
This now leads to the next point:
NULL is the same as 0 (which also is the same as false). For the fact that integers and pointers can be converted into each other (or better: are physically the same thing, see my remarks above), there is a reserved value called NULL which means: pointing nowhere. This value is defined to be the virtual address 0x00000000 (32bit). So providing a 0 to a function that expects a pointer, you provide an empty pointer, if you like.
char* is a pointer. Same as char[] (there is a slight logical difference in the behaviour and in the allocation, but internally they are basically the same). printf expects a char*, but you provide an int. This is not a problem, as described above, int will get interpreted as an address. Nearly every (well written) function taking pointers as parameters will do a sanity check on these parameters. printf is no exclusion: If it detects an empty pointer, it will handle that case and return silently. However, when providing something different, there is no way to know if it is not really a valid address, so printf needs to do its job, getting interrupted by the kernel when trying to address the memory at 0x00000001 with a segmentation fault.
This was the long explanation.
And by the way: This only works for 32-bit pointers (so compiled as 32-bit binary). The same would be true for long int and pointers on 64-bit machines. However, this is a matter of the compiler, how it converts the expression you provide (normally, an int value of 0 is implicitly cast to a long int value of 0 and then used as a pointer address when assigned, but vice versa won't work without an explicit cast).
Why does this code below compiles and executes but doesn't print anything in output?
printf(i = 0);
The question embodies a false premise. On any modern C compiler, this clearly-erroneous code generates at least one error.
I've checked the questions that were already posted and couldn't quite find the solution to my problem...
I'm making a console program that inputs 2 variables: 1 is a byte and the other is a number of the bit I need to get from that byte using only masking and if statements.
int E1 () {
unsigned char a, b, c;
printf("Number (byte):");
scanf("%d", &a);
a= (unsigned char)a;
printf("\n Bit you want to output (between 0 and 7) :");
scanf("%d", &b);
b=(unsigned char)pow((float)2.0,b);
printf("Mask is: %d", b);
c= a & b; //<-- This returns 0
if (c>0) {
printf("\n\nThe bit is: 1");
}
else {
printf("\n\nThe bit is: 0");
}
return 0;
}
I've asked my teacher and he said that it should work fine. I've tried it and it doesn't work. He is using Visual Studio Express, the free version one can get from Microsoft website and I'm using Code::Blocks (in case this makes a difference in the results).I've added a comment to where I think the problem lies but not sure.
Can anybody please help me with this. Thanks in advance.
Use 1<<b as the mask. Not only is it idiomatic, it's also hugely more efficient than using floating-point calculations. So delete this line:
b=(unsigned char)pow((float)2.0,b);
And set c like this:
c = a & (1<<b)
Does that work any better?
Some testing tells me it's this part that's wrong:
scanf("%d", &a);
This is in fact undefined behavoir: it may or may not work, but you can't really rely on anything. This is because while a is only a 1-byte char, while %d expects a 4-byte integer, meaning that scanf writes four bytes of memory instead of one.
This has the unfortunate side effect that the second call (to scanf("%d", &b)) might use the memory where some other variables in your program are stored, in this case, a. This gets overwritten and set to 0, leading to the expression 0 & b which of course evaluates to 0.
The proper way to solve this problem is to use %hhd instead of %d, which makes scanf expect a char instead of an int, and only write 1 byte of memory.
Side notes about your code
The line a = (unsigned char) a; is useless, since a is already of type unsigned char.
As Graham noted in his answer, you should use b = (1 << b); when calculating powers of two, since this is much more pretty code and also much more efficient — many modern CPUs can do this in just one instruction.
printf("The bit is: %d", 1 & a>>b);
New to C, I've been trying to convert a hex input with this code. The input argv[1] I've been giving it is 0xabcd123. It has only given me 0 outputs. I have also tried using atoi as well as varying the types of outputs. Why does it only print 0? Here is the code, thanks
#include <stdio.h>
#include <stdlib.h>
typedef union{
double num;
float f;
} U;
int main(int argc, char*argv[])
{
U u;
u.num = strtod(argv[1], NULL);
printf("%e\n", u.f);
return 0;
}
result is platform dependent!
I believe its returning 0 on one system because of byte order. when you write to the value as a double but then read it as a float, you may be reading the top or bottom half of the double, depending on the architecture. on one system it's the empty top half of the double, on another its the bottom half which contains value.
either way, with a union, you should never expect to write any value as one type, and read back as another and get reliable results. as you have discovered :) unions aren't magic type converters, they simply allow you to save space when you know you have one type of value at a time.
num is declared as int. So printf("%d", u.num) or double num
First, please kindly reformat your code so that everyone can read it easily.
Second, the type of your u.num is double, so utilize %f or %lf instead of %d
Third, as shown in this codepad http://codepad.org/JSSJEKOn, your code is correct and it must obviously print the expected result. So I think that the error is not here but somewhere else in your source file. Please give us more information
I have been working on this code but I can't find out what is wrong.
This program does compile and run but it ends up having a fatal error.
The program reads a file and collect the numbers in order to calculate the total (after having converted them to float). Then it reads the file and display the one that has less than 10.00
I have a file called myFile.txt, with the following content :
James------ 07.50 Anthony--- 17.00
So the display should be
The total is 24.50
Here is the one with less than 10.00 :
James who has 07.50
And here is the code :
int main()
{
int n =2, valueTest=0,count=0;
FILE* file = NULL;
float temp= 00.00f, average= 00.00f, flTen = 10.00f;
float *totalNote = (float*)malloc(n*sizeof(float));
int position = 0;
char selectionNote[5+1], nameBuffer[10+1], noteBuffer[5+1];
file = fopen("c:\\myFile.txt","r");
fseek(file,10,SEEK_SET);
while(valueTest<2)
{
fscanf(file,"%5s",&selectionNote);
temp = atof(selectionNote);
totalNote[position]= temp;
position++;
valeurTest++;
}
for(int counter=0;counter<2;counter++)
{
average += totalNote[counter];
}
printf("The total is : %f \n",average);
rewind(file);
printf("here is the one with less than 10.00 :\n");
while(count<2)
{
fscanf(file,"%10s",&nameBuffer);
fseek(file,10,SEEK_SET);
fscanf(file,"%5s",¬eBuffer);
temp = atof(noteBuffer);
if(temp<flTen)
{
printf("%s who has %f\n",nameBuffer,temp);
}
fseek(file,1,SEEK_SET);
count++;
}
fclose(file);
}
I am pretty new to c and find it more difficult than c# or java. And I woud like to get some suggestions to help me to get better. I think this code could be simplier. Do you think the same ?
You don't mention what platform and compiler you're using. I'm going to guess MSVC and Windows, given that your filename uses a Windows-style path.
You say that the code compiles and runs but have you turned on the warnings from your compiler? That might give you more clues about potentially incorrect things you may be doing.
After fixing some of the typos and adding the standard include headers, I compiled your code in gcc which warned about mismatches between the fscanf format strings and the arguments. In particular, you are passing a pointer to the char arrays which is not what you mean. You may want to read up about arrays and pointers in C, e.g. in the C FAQ. The rest of the entries in that document are very enlightening as well.
Most likely, your fatal error is coming from the statement
fscanf(file,"%5s",&selectionNote);
Normally, an expression of array type like selectionNote will implicitly be converted to a pointer type (see note 1), so in this case the & is not necessary:
fscanf(file, "%5s", selectionNote);
You don't explain what the code is supposed to be doing, so I'm not exactly sure how to tell you how to restructure it.
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined. -- C Language Standard (draft n1256), section 6.3.2.1, paragraph 3.
Instead of using fscanf followed by atof, use a single fscanf with a suitable format string (%f):
fscanf(file, "%f", &totalNote[position]);
You can use the return value from fscanf for loop termination, instead of using the variable valueTest and the constant 2:
while(fscanf(file, "%f", &totalNote[position]) != 0)
...
The first loop that reads from file must scan both the names and the numbers, even though you need only numbers!
You can accumulate the numbers in the same loop that reads them. If you do that, you can remove the array totalNote (this "simplification" is not suitable if you think you will extend your code to do other things with the numbers, not just calculate the total)
The second loop that reads the file (the one after rewind) is better expressed with for than while:
for (count = 0; count < counter; count++)
...
In the same loop, you absolutely don't need to use fseek! It messes your code up, so it will only read "James" from the file, and never proceed to "Anthony"
You probably want to remove the "----" padding from the names before printing them; you can do it with strchr or strtok:
fscanf(file,"%10s",&nameBuffer);
strtok(nameBuffer, "-");