Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

printf char* pointer which points to long and float

I am doing some exercises from book "Understanding pointers in C". The book gives you a piece of code and asks you for what you get in output.

One of them is the following:

#include <stdio.h>

int main(int argc, char* argv[])
{
    char c, *cc;
    int i;
    long l;
    float f;

    c = 'Z';
    i = 15;
    l = 77777;
    f = 3.14;
    cc = &c;
    printf("c=%c cc=%u\n", *cc, cc);
    cc = &i;
    printf("i=%d cc=%u\n",*cc,cc);
    cc=&l;
    printf("l=%ld cc=%u\n",*cc,cc);
    cc=&f;
    printf("f=%f cc=%u\n",*cc,cc);
    return 0;
}

and the output is:

c=Z cc=1946293623
i=15 cc=1946293616
l=4294967249 cc=1946293608
f=0.000000 cc=4294967235

I don't understand why l and f are not printed as 77777 and 3.14?

I checked the book The C Programming Language to see if the if the printf's control chars are correct, and they are.

like image 623
Germano Massullo Avatar asked Jun 13 '26 01:06

Germano Massullo


2 Answers

As Bryan's answer says, the types of the arguments passed to printf need to match the types specified by the format string.

The format to print a pointer value is "%p" -- and it expects a void* argument; a pointer of another type should be explicitly cast to void*.

Your program has undefined behavior because of the type mismatches. It also has constraint violations because it attempts to assign incompatible pointer types without a cast; cc = &i; is illegal (but a compiler can merely warn about it if it chooses). You should have gotten several warnings from your compiler.

I hope the intent of that program is to demonstrate what not to do. Let's consider just the last two lines before the return statement:

cc=&f;
printf("f=%f cc=%u\n",*cc,cc);

cc = &f; violates a constraint and requires a diagnostic (IMHO a good compiler should give you a fatal error and reject the program). &f is of type float*, and cc is of type char*; those types are not assignment-compatible.

Most compilers that accept that statement assume it implies an implicit conversion, making it equivalent to the legal but tricky:

cc = (char*)&f;

This causes cc to point to the first byte of the float object f.

printf("f=%f cc=%u\n",*cc,cc);

This claims to print the value of f, but it doesn't; it prints the value of the char object that cc points to, which happens to be the first byte of f. And it uses a %f format for that char object, which has undefined behavior. The result is garbage.

I was going to write a "corrected" version of that program, but it has so many problems, I couldn't figure out just what it's intended to do.

I checked the book The C programming language to see if the if the printf's control chars are correct, and they are.

No, they aren't. "%f" is correct for printing a float or double argument (float is promoted to double in this context), but you're passing a char argument.

This would be correct:

printf("*cc = %d, cc = %p\n", *cc, (void*)cc);

but it doesn't do the same thing; it prints the char pointed to by cc as an int (you could use %c to print it as a character, but it's likely to be unprintable), and then prints the value of cc as a pointer.

It would be interesting to see what the book says about this program.

like image 184
Keith Thompson Avatar answered Jun 15 '26 16:06

Keith Thompson


The format specifiers of printf (and worse so scanf) have to match the types passed as parameters. If you are using GCC then use the -Wall option and it will also give warnings about this. Your code should look like this:

printf("c=%c cc=%u\n", *cc, (unsigned int)cc);
cc = &i;

Taking the address of i into a char* interpretation doesn't make sense anymore and neither does it for the others below. By assigning pointers, you enforce a wrong interpretation of the same bit representation.

like image 24
Bryan Olivier Avatar answered Jun 15 '26 15:06

Bryan Olivier



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!