Divide int and store back into original variable - c

I have a function that does some stuff (that portion is irrelevant) then it sets a value called num, then prints that value. My issue is as a final step of my function before printing the value it must divide by 4. That is where I am hitting a snag... See below:
int *num = 0;
.
. //num is determined here...
.
num = num/4; // <-- My issue
printf("%d\n", num);
The error I get is:
error: invalid operands to binary / (have 'int *' and 'int')
Which, from so searching means I need to deference it like so:
num = (*num)/4;
Though this also does not work correctly (it doesn't give any errors, it actually puts my code into an infinite loop and Windows stops it). What I am trying to do is take the value stored at num (the address) and divide it by for and then set num value to that new value. But I see to be struggling with getting this work correctly.

num is of type pointer. So num = num /4 ; is a very unlikely thing to do. It is not even allowed.
As per standard 6.5.5Each of the operands shall have arithmetic type.(Multiplicative expression)
Compiler also tells you that thing error: invalid operands to binary / (have 'int *' and 'int').
/ takes two arguments. But compiler is looking at the operands and it sees that they are of type *. So it complains because it not allowed as oer standard.
num =*num/4; is basically assigning an integer result to a pointer variable. Which even though may not lead to desired behavior but allowed. (We also do int *p =NULL)

This statement below declares a pointer
int *num = 0;
meaning points to some memory where value is there;
This statement below is very interesting
.
. //num is determined here...
.
when you say num is determined here there are couple of ways to interpret this
is there an assignment to value as below in which case RHS must be value
*num = some value;
or assignment to pointer as below in which case RHS must be an address or pointer.
num = some address;
Finally when you do this, you are operating on pointer because num represents a pointer where as *num represents value and below statement is invalid for pointers as Multiplication or Division of a pointer is not allowed in C
num = num/4; // <-- My issue
also when you are printing here, you are basically printing the address of num than printing the value.
printf("%d\n", num);

Related

What is the purpose of requiring a data type specification of the returned value in a function definition or prototype? Type casting?

Consider the following snippet of code:
#include<stdio.h>
int demo_function(float a);
int main(void)
{
int b;
float fraction_number = 3.15f;
b = demo_function(fraction_number);
printf("The number returned is %d", b);
return 0;
}
int demo_function(float a)
{
float c;
c = a;
printf("The number passed is %.2f \n", c);
return c;
}
The output is:
The number passed is 3.15
The number returned is 3
From this little test code, it seems like actual purpose of writing int as the data type of demo_function's returned value is to type cast.
Firstly, is that the correct interpretation of what is going on?
Secondly, why does the compiler actually need this information? (Or perhaps a better question is, "How does the compiler use this information?"). Specifically, if the compiler sees that variable b is declared as an int, why does it need to explicitly know that the returned value is of type int?
If we end up storing the returned value of variable c into b, what issues would arise if the compiler did NOT require the explicit mention that the returned value is of type int? Would there be information loss as the float c variable tries to get squished into the smaller memory allocated int b variable?
Thanks!
As a practical matter, the compiler needs to know what type a function returns because it needs to know how to interpret the bits a function returns and it needs to know where those bits are.
Suppose that when a function returns, the register used for the return value contains 0x80. If the function is supposed to return an 8-bit unsigned char, then the return value is 128. If the function is supposed to return an 8-bit two’s complement signed char, then the return value is −128. Knowing the type is necessary to know the interpretation of the bits.
In many systems, a function that returns an integer is supposed to put the bits in a certain general register of the processor, but a function that returns a floating-point value is supposed to put the bits in a certain floating-point register. In this case, the caller needs to know the return type of the function in order to know where the bits of the return value are.
At a more abstract level, the compiler needs to know the return type of the function so that it can interpret the expression the function call appears in. Consider that, in C, the expression 5 / 4 performs integer division with truncation and produces 1, but the expression 5. / 4 performs floating-point division and produces 1.25. So, in the expression f(x) / 4, the compiler needs to know what type f returns so that it knows whether to perform integer division of floating-point division.
For another example, suppose f returns a pointer, and the program uses y = *f(x). To execute this code, the compiler has to take the value returned by f and use it as an address to fetch something from memory. But what does it fetch? Does the address point to a one-byte char, an eight-byte double, or a 100-byte structure? The compiler needs to know the type of the pointer returned by f so that it knows what type of object it points to.
From this little test code, it seems like actual purpose of writing int as the data type of demo_function's returned value is to type cast.
The primary purpose is as described above. The fact that the value in a return statement is converted to the return type of the function is a secondary effect; it is merely a convenience of the language, not a necessary effect. (The implicit conversion is not necessary because we could effect the conversion by specifying it explicitly.)
Also note that a cast is an explicit operator. It is not the operation. For example, + and * are operators; they are things that appear in source code that say we want to do certain operations. The actual operations are addition and multiplication. Similarly, a cast is a type name in parentheses; it is some text that appears in source code that specifies we want to perform a conversion.

Difference b/w getting an address of variable using %p and %d

Here is an example
#include <stdio.h>
int main()
{
int a;
printf("%d\n",&a);
printf("%p\n",&a);
return 0;
}
======Output=======
-2054871028
0x7ffd8585280c
Do these two address point to same address in RAM ?
And how can i get the value by using each one of them, especially the second one.
%d format specifier is used to output a signed decimal integer.
From C Standard#7.21.6.1p8
d,i
The int argument is converted to signed decimal in the style [-]dddd. The precision specifies the minimum number of digits to appear; if the value being converted can be represented in fewer digits, it is expanded with leading zeros. The default precision is 1. The result of converting a zero value with a precision of zero is no characters.
%p prints the pointer.
From C Standard#7.21.6.1p8
p
The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner. [emphasis mine]
This statement
printf("%d\n",&a);
lead to undefined behavior because %d is not valid for printing a pointer.
From C Standard#7.21.6.1p9
If a conversion specification is invalid, the behavior is undefined.282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
When you take the address of the variable a by writing &a, what you're really doing is generating a pointer to a.
%p is designed for printing pointers. You should use %p to print pointers.
%d is not designed for printing pointers. It tries to print their values as signed decimal, which can be confusing (as you've seen), and it may not print the entire value, on a machine where pointers are bigger than integers. (For example, if you try to print pointers with %d in most "64 bit" environments, you can get even stranger results -- and that might be part of what happened here.)
This is an easy mistake to make. Good compilers should warn you about it. Mine says "warning: format specifies type 'int' but the argument has type 'int *'".
But yes, both 0x7ffd8585280c and -2054871028 do "point to the same address in RAM", because they're both the same number, the same address. (Well, they're trying to be the same address. See footnote below.)
I'm not sure what you mean by "And how can I get the value". Are you trying to get the value of the pointer, or the value of what the pointer points to?
You've already got the value of the pointer -- it's the address 0x7ffd8585280c. And since we know it points to the variable a, we know the value it points to, too. Things will be a bit more clear if we do it like this:
int a = 5;
int *ip = &a;
printf("value of pointer: %p\n", ip);
printf("pointed-to value: %d\n", *ip);
Without the explicit pointer variable ip, we could write
int a = 5;
printf("value of pointer: %p\n", &a);
printf("pointed-to value: %d\n", *&a);
But that's pretty silly, because the last line is equivalent to the much more straightforward
printf("pointed-to value: %d\n", a);
(Taking the address of a variable with & and then grabbing the contents of the pointer using * is a no-op: it's a lot like like writing a + 1 - 1.)
Footnote: I said that 0x7ffd8585280c and -2054871028 were the same number, but they're not, they're just trying to be. 0x7ffd8585280c is really -140748133160948, and -2054871028 is really 0x8585280c, which is the lower-order 8 digits of 0x7ffd8585280c. It looks like %p on your machine is printing pointers as 48-bit values by default. I was about to be surprised by that, but then I realized my Mac does the same thing. Somehow I'd never noticed that.

How does sizeof operator behaves in below code snippet?

Please explain the OP for below code snippet :
int *a="";
char *b=NULL;
float *c='\0' ;
printf(" %d",sizeof(a[1])); // prints 4
printf(" %d",sizeof(b[1])); // prints 1
printf(" %d",sizeof(c[1])); // prints 4
Compiler interprets a[1] as *(a+1) , so a has some address , now it steps 4 bytes ahead , then it will have some garbage value there so how is the OP 4 bytes , even if I do a[0] , still it prints 4 , although it is an empty string , so how come its size is 4 bytes ?
Here we are finding out the size of the variable the pointer is pointing to , so if I say size of a[1] , it means size of *(a+1), Now a has the address of a string constant which is an empty string , after I do +1 to that address it moves 4 bytes ahead , now its at some new address , now how do we know the size of this value , it can be an integer , a character or a float , anything , so how to reach to a conclusion for this ?
The sizeof operator does not evaluate its operand except one case.
From the C Standard (6.5.3.4 The sizeof and alignof operators)
2 The sizeof operator yields the size (in bytes) of its operand, which
may be an expression or the parenthesized name of a type. The size is
determined from the type of the operand. The result is an integer.
If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the
result is an integer constant.
In this code snippet
int *a="";
char *b=NULL;
float *c='\0' ;
printf(" %d",sizeof(a[1])); // prints 4
printf(" %d",sizeof(b[1])); // prints 1
printf(" %d",sizeof(c[1])); // prints 4
the type of the expression a[1] is int, the type of the expression b[1] is char and the type of the expression c[1] is float.
So the printf calls output correspondingly 4, 1, 4.
However the format specifiers in the calls are specified incorrectly. Instead of "%d" there must be "%zu" because the type of the value returned by the sizeof operator is size_t.
From the same section of the C Standard
5 The value of the result of both operators is implementation-defined,
and its type (an unsigned integer type) is size_t, defined in
<stddef.h> (and other headers).
This is all done statically, i.e. no dereferencing is happening at runtime. This is how the sizeof operator works, unless you use variable-length arrays (VLAs), then it must do work at runtime.
Which is why you can get away with sizeof:ing through a NULL pointer, and other things.
You should still be getting trouble for
int *a = "";
which makes no sense. I really dislike the c initializer too, but at least that makes sense.
sizeof operator happens at compilation (except for VLA's). It is looking at the type of an expression, not the actual data so even something like this will work:
sizeof(((float *)NULL)[1])
and give you the size of a float. Which on your system is 4 bytes.
Live example
Even though this looks super bad, it is all well defined, since no dereference ever actually occurs. This is all operations on type information at compile time.
sizeof() is based on the data type, so whilst it's getting the sizes outside the bounds of memory allocated to your variables, it doesn't matter as it's worked out at compile time rather than run time.

Storage of variables and dereferencing them

Based on the following snippet in C
int c1,c2;
printf("%d ",&c1-&c2);
Output : -1
Why does this code not return a warning saying the format %d expects of type int but it's getting a (void *) instead.
Why does it return -1 as an answer(and not 1)? Even if it's subtracting addresses it should be -4 and not -1. When I change the printf statement to printf("%d ",&c2 - &c1) I get 1 and not any random value! Why?
If I change the printf statement as printf("%d ",(int)&c1 - (int)&c2) am I typecasting an address to an integer value? Does that mean the value of the address stored as hexadecimal is now converted to int and then subtracted?
1) It's getting an int. Pointer-to-something minus pointer-to-something is an integer value (type ptrdiff_t). It tells you how many elements away are two pointers pointing into the same array.
2) As the two pointer do not point into the same array, the difference is undefined. Any value can be obtained.
3) Yes. But the "hexadecimal" part is incorrect. Addresses are stored in bits/binary (as are integers). What changes is the interpretation by your program. This is independent of the representation (hex/dec/oct/...).
There are multiple cases of undefined behavior here.
If we go to the draft C99 standard section 6.5.6 Additive operators it says (emphasis mine):
When two pointers are subtracted, both shall point to elements of the
same array object, or one past the last element of the array object;
the result is the difference of the subscripts of the two array
elements. The size of the result is implementation-defined, and its
type (a signed integer type) is ptrdiff_t defined in the
header. If the result is not representable in an object of that type,
the behavior is undefined.
Although, what you have is undefined behavior since the pointers do not point to elements of the same array.
The correct format specifier when using printf for ptrdiff_t would be %td which gives us a second case of undefined behavior since you are specifying the incorrect format specifier.
1) A void* is nothing but an adress. An adress is an number (a long). There, the adress is implicitly cast to an int.
2) In memory, your variable aren't store in the same order than in
your code ;). Furthemore, for the same reason :
int a[2];
a[0] = 3;
*(a + 1) = 5; // same that "a[1] = 5;"
This code will put a "5" in the second case. Cause it will actually do :
*(a + 1 *sizeof(*a)) = 5;
3) Hexadecimal is a number representation. It can be store in a int ! Example :
int a = 0xFF;
printf("%d\n", a); // print 255
I hope that i have answered your questions.
1) Some compilers do issue warnings for malformed printf arguments, but as a variadic function, the run-time has no way of checking that the arguments are of the type specified by the format string. Any mismatch will issue undefined behaviour as the function attempts to cast such an argument to an incorrect type.
2) You say the result should be -4 but that's not correct. Only arrays are guaranteed to have their pointers aligned contiguously. You cannot assume that c2 is at (&c1 + 1).
3) (int)&c1 is converting the address of c1 to an int. That's again, in general, undefined behaviour since you don't know that int is big enough to hold the pointer address value. (int might be 32 bits on a 64 bit chipset). You should use intptr_t in place of the int.

C program : help about variable definition sequence

void main()
{
float x = 8.2;
int r = 6;
printf ( "%f" , r/4);
}
It is clearly odd that i am not explicitly typecasting the r ( of int type ) in the printf func to float. However if i change the sequence of declaring x and r and declare r first and then x i get different results(in this case it is a garbage value). Again i am not using x
in the program anywhere.. These are the things i meant to be wrong... i want to keep them the way they are. But when i excute the first piece of code i get 157286.375011 as result ( a garbage value ).
void main()
{
int r = 6;
float x = 8.2;
printf ( "%f" , r/4);
}
and if i execute the code above i get 0.000000 as result. i know results can go wrong because i am using %f in the printf when it should have been %d... the results may be wrong... but my question is why the results change when i change sequence of variable definitions. Should not it be the same whether right or wrong???
Why is this happening?
printf does not have any type checking. It relies on you to do that checking yourself, verifying that all of the types match the formatting specifiers.
If you don't do that, you enter into the realm of undefined behavior, where anything can happen. The printf function is trying to interpret the specified value in terms of the format specifier you used. And if they don't match, boom.
It's nonsense to specify %f for an int, but you already knew that...
f conversion specifier takes a double argument but you are passing an int argument. Passing an int argument to f conversion specifier is undefined behavior.
In this expression:
r / 4
both operands are of type int and the result is also of type int.
Here is what you want:
printf ("%f", r / 4.0);
When printf grabs the optional variables (i.e. the variables after the char * that tells it what to print), it has to get them off the stack. double is usually 64 bits (8 bytes) whereas int is 32 bits (4 bytes).
Moreover, floating point numbers have an odd internal structure as compared to integers.
Since you're passing an int in place of a double, printf is trying to get 8 bytes off the stack instead of four, and it's trying to interpret the bytes of a int as the bytes of a double.
So not only are you getting 4 bytes of memory containing no one knows what, but you're also interpreting that memory -- that's 4 bytes of int and 4 bytes of random stuff from nowhere -- as if it were a double.
So yeah, weird things are going to happen. When you re-compile (or even times re-run) a program that just wantonly picks things out of memory where it hasn't malloc'd and it hasn't stored, you're going to get unpredictable and wildly-changing values.
Don't do it.

Resources