Which statement will change value of x to 60 in C programing? - c

int *p;
int x;
int k;
x = 30;
k = x;
p = &x;
After these statements, which of the following statements will the value of x to 60? My answer is 1. But I'm not sure if I am correct, because seem like other answer is correct too. Please gives some explanation.
1. k = 60;
2. *k = 60;
3. p = 60;
4. *p = 60;

Here is an explanation:
int *p; //declares a pointer to an integer
int x; //declares an integer called x
int k; //declares an integer called k
//at this point all values are uninitialized and could contain anything
x = 30; //the numerical value 30 is assigned to x
k = x; //the contents of x(30) is assigned to k
p = &x; //the address of int x is stored in p
//now all values have valid and reliable values
Now let me explain what each line you described does:
k = 60; //assigns value 60 to variable k
*k = 60; //attempts to dereference k which is a non pointer type (compile time error)
p = 60; //attempts to assign the value 60 to a pointer p this is NOT what you want
*p = 60; //dereferences pointer p(which points to x) and sets the value 60 to it
the last line has the same effect as x=60; so it is the correct answer.
k=60; will not affect the content of x, because x and k are different variables they each have their own separate memory. k=x; will simply copy the contents of x into k, it will not make the variables aliases of each other.

You can simply compile it and run it in a debugger via single step to see how it works.

The answer is not 1. You're close, answers 2 and 3 don't make sense.
p = &x
p points to the memory address of x so setting
p = 60
would be setting its address to 60 which is not what you want.
k = x;
Changing k will not change x because k doesn't store the memory of x, it has instead copied the value of x.
*p = 60
The value that p is pointing to equals 60, in this case p is pointing to the address of x
So when ever the value at the address of x changes, *p changes or vice versa.
The key point is *p is pointing the value at the memory address of x, so changing *p changes x
The answer is 4.

Related

Why do the following C expressions involving pointers not evaluate to an error?

I have been reviewing material regarding C for the upcoming semester, and stumbled across some topics involving pointers and memory. I did not write the code, but I am trying to understand all of it. The expressions are as follows (for conciseness I removed int main()):
int x = 5;
int y;
int *p = NULL;
p = &x;
y = *p + 2; /* y is assigned 7 */
y += *p; /* y is assigned 12 */
*p = y; /* x is assigned 12 */
(*p)++; /* x is incremented to 13 */
I do not understand the 7th statement, because it isn't consistent with the way the 5th statement is evaluated. As far as I was concerned, *p is used to access the value p points to, being x, which is 5. In the 5th statement, we set y = *p + 2, which evaluates to y = 5 + 2 = 7. So, why in the 7th statement is *p used as a pointer to x, and not the value 5? (ie. why doesn't the expression evaluate to 5 = 12 and give an error?).
Thanks for any of the help, appreciate it.
*p = y; sets *p to the value of y and does not set 5 to the value of y for the same reason that x = y; sets x to the value of y and does not set 5 to the value of y.
Specifically, in most places, when there is expression that refers to an object, like x or *p or y, it is automatically converted to the value stored in that object. This is why, in x = y;, the y is converted to 12. This conversion occurs due to C 2018 6.3.2.1, which says:
… an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue)…
But the full sentence lists exceptions:
Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue)…
In x = y; or *p = y;, the x or *p is the left operand of an assignment operator. So these are not converted to values. Each remains an lvalue. An lvalue is a reference to an object; it designates the object itself, not its value.
So x = y; puts the value of y into the object referred to by x, and *p = y; puts the value of y into the object referred to by *p.
why doesn't the expression evaluate to 5 = 12
It's possible to write to the memory pointed to by a pointer.
Similarly, x = y; is valid because you can read from the variable y and you can write to x. Same thing with pointers: *p = *p + 1;, for example, will read from p, add one to that value and write the result back to p.

C multiple variable assignment

I'm first year student in Software Engineering and in my last task I used (chain assignment) multiple assignment of values.
The lecturer claims that it is illegal to assign values in this way.
X = Y = Z;
(The three variables are declared in the beginning of the function).
I would be happy if you can explain to me if the assign is right action and if what the teacher claims is right.
It depends on whether all of the objects were correctly declared and Z was initialized or assigned with an appropriate value before this statement or not.
You can even assign values of objects of different types due to implicit casting, but the object which is getting assigned needs to be capable of holding the value of the object which is assigned to this one.
If Z was initialized or assigned before and all objects were correct declared, then:
X = Y = Z;
is completely correct and legal as it assigns the value held in Z to Y and X - the assignment takes place from right to left.
For example:
int X,Y,Z; // All objects are declared.
Z = 24; // `Z` is assigned with the integer value 24.
X = Y = Z; // `X` and `Y` get assigned by 24 which is the value in `Z`.
Else if Z has an indeterminate value (f.e. if it was not declared with the extern or static keyword or declared at global scope) and you would assign this value to Y and X with that statement.
Although the assignment itself would be even then not illegal, if you would use one of the assigned objects the program would give undefined results/output.
Speaking for the multiple assignments only, there is nothing illegal about it, you could even use:
O = P = Q = R = S = T = U = V = W = X = Y = Z;
if all objects used were correctly declared before and Z has an determined value.
The lecturer claims that it is illegal to assign values in this way.
If it is possible, I would ask her/him or your teacher, what s/he meant with that. Maybe there is something specific to your course you should care about.
Almost every expression has a value.
An assignment is an expression with value.
The value of the expression i = 42 is 42.
Assignment associates right to left, so the expression a = b = c is the same as a = (b = c).
So
int i;
double d;
char c;
c = i = d = 42;
Converts 42 to double and assigns to d. The value of this assignment is 42.0.
Then this value is converted to int and assigned to i. Value of this assignment is 42.
Lastly the int value is converted to char and assigned to c.
c = (i = (d = 42));
It's legal, for example:
float x;
int y;
float z = 3.5;
x = y = z;
it's similar to y = z; x = y;. So in this case, z = 3.5, y = 3 and x = 3;
But it will give the warning if you did not initialize the value of z.
int x,y, z;
x = 0;
y = 1;
//z = 2;
x = y = z;
Together with right-associativity of evaluation, and assuming non-volatile a, b, and c, it means that a = b = c is equivalent to a = (b = c), and again equivalent to b = c; a = b
Assigning values to multiple variables in a single line is perfectly alright and is allowed by C programming language.
However, the use of this style is usually discouraged because it may cause undesirable side-effects in some cases.
The expectation of Mathematical equation X = Y = Z may be:
Y = Z and X = Z (I.E., Assign the value of Z to both X and Y)
But C language treats the multiple assignments like a chain, like this:
In C, "X = Y = Z" means that the value of Z must be first assigned to Y, and then the value of Y must be assigned to X.
Here is a sample program to see how the multiple assignments in single line work:
#include <stdio.h>
int main() {
int n;
int X, Y, Z;
printf("Enter an integer: ");
scanf("%d", &n);
printf("You entered: %d\n", n);
printf("Performing multiple assignments:\n X = Y = Z = n++ \n");
X = Y = Z = n++;
printf("n = %d\n", n);
printf("X = %d \n", X);
printf("Y = %d \n", Y);
printf("Z = %d \n", Z);
return 0;
}
Output:
Enter an integer: 100
You entered: 100
Performing multiple assignments:
X = Y = Z = n++
n = 101
X = 100
Y = 100
Z = 100
Points to note in the above example:
The line X = Y = Z = n++ got processed like this:
Step 1: Assign the value of n (100) to Z
Step 2: Increment the value of n (n becomes 101)
Step 3: Assign the value of Z to Y (Y becomes 100)
Step 4: Assign the value of Y to X (X becomes 100)
Conclusion:
'Multiple assignments in single line' is a supported style. It has its benefits.
However, if the programmer is not aware of the sequence of operations involved in the multiple assignments statement, then it can lead to inconsistency between the expectation of the person who reads the program and the actual result of the execution.
To avoid this scenario, the multiple assignments are discouraged.
There's nothing illegal about it, provided each variable is only modified once. For example, the following all have well-defined behavior:
x = y = z;
x = y = z = x + 1;
x = y++ + --z;
x += (y = (z += 1)) - 6;
But the following have undefined behavior, and should be avoided:
x = y = x = z;
x = x++;
x = y++ + y++
x = func(y++, y++);

C code, pointers and their content. Exam question [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have this code from an old exam.
The first print generates 5a9b1740.
And the question is what does the second print generate.
x: unknown since we do not know what *k holds.
y: 35.
z: ffff ffff. WHY?
p: 5c9b1748. WHY?
{
int x = 4;
int y = 15;
int *k = &x;
int z;
int *p;
*k = *k * (*k + 1);
y = x + y;
k = &z;
int a[] = {7,9,3,8};
p = a;
printf("%x\n",(unsigned int)p);
x = *k + 1;
p = p + 2;
z = *p - 4;
printf("%d %d %x %x\n",x,y,z,(unsigned int)p);
}
Edit: Sorry for causing confusion, the first print is 5a9b1740 and second 5c9b1748. Not 5a9b1740,5c961748. Question is edited on that regard.
x: unknown since we do not know what *k holds.
Technically, the value of *k when x = *k + 1; was executed is indeterminate since it points to z and z was uninitialized at that time. This means the value is either unspecified (i.e. it can have any value) or a trap representation (i.e. it doesn't represent a valid value and can trigger a fault if read). If the value happens to be a trap representation then reading invokes undefined behavior.
In some cases reading an uninitialized variable can still be undefined even if it is not a trap representation, however that is not the case here because z had its address taken.
y: 35.
At this point:
*k = *k * (*k + 1);
y = x + y;
k points to x and 4 has the value 4, so the first line is the same as x = 4 * (4 + 1). This sets x to 20, then adding that to the current value of y (15) gives 35.
z: ffff ffff. WHY?
p: 5c9b1748. WHY?
Looking at these lines:
p = a;
p = p + 2;
z = *p - 4;
This first points p to the first element of a, and that pointer has value 5a9b1740 as in the first printf. The next line then points it to 2 elements after that one. Assuming an int is 4 bytes on your system, that means the raw value of the pointer p increased 2 * 4 = 8. So the value of p is now 5a9b1740 + 8 = 5a9b1748.
With p now pointing to the third element of a which has the value 3, the following line sets z to -1. This value is then printed with the %x format specifier which interprets the value as an unsigned int and prints it in hex. Assuming two's complement representation of negative numbers an (again) a 4 byte int, this value has the representation ffffffff. When read as an unsigned int is is this that is printed.
p.s. no 3:
It comes out that, the addresses given in the question are not the actual outcome of a program execution but example values given with the assignment text. So, there is a possible typo: either both addresses would start with 5c9b... or both w/ 5a9b....
p.s. no 2:
Please refer to the comments as well. Just checking the last 2 ~ 4 digits of the addresses, I overlooked the weird address gap b/w the 1st & 2nd results of the print lines.
Let's go line by line:
Line 1:
int x = 4; // x is defined and set to value 4
Line 2:
int y = 15; // y is defined and set to value 15
Line 3:
int *k = &x; // pointer k is set to point x
Line 4:
int z; // z is defined but uninitialized
Line 5:
int *p; // pointer p is defined but uninitialized
Line 7:
*k = *k * (*k + 1);
// k was set to point x (above)
// so, *k = x
// and x = x * (x + 1) => x = 4 * 5 = 20
Line 8:
y = x + y
// y = 20 + 15 = 35
Line 9:
k = &z;
// k is set to point z (but z is still uninitialized)
Line 11:
int a[] = {7, 9, 3, 8};
// array 'a' is defined
Line 12:
p = a;
// p is set to point the first int element of array 'a'
Line 13:
printf("%x\n", (unsigned int)p);
// printing the memory address of p
// same as printing the memory address of array 'a'
Line 14:
x = *k + 1;
// k was set to point z
// but z is still uninitialized
// so, x = z + 1 is unpredictable so far
// x is, whatever the value z plus 1
Line 15:
p = p + 2;
// p was set to point first integer element of array 'a'
// so, after p = p + 2, p = address of 'a' + 2 * sizeof(int)
// since sizeof(int) = 4 bytes, p is now address(a) + 8
// p is now pointing to the third element of array 'a'
// that is, p is pointing to '3'; *p = 3
Line 16:
z = *p - 4;
// p was set to point third element of array 'a'
// *p was '3'
// so, z = *p - 4 means z = 3 - 4 = -1
Line 17:
printf("%d %d %x %x\n", x, y, z, (unsigned int)p);
// x is, what ever the value of z plus 1
// y is 35
// z is -1; its hex representation if ffff ffff
// p is address of array a plus 2; p = &a[0] + 2
// that is; p is now, address of array 'a' + 2 * sizeof(int)
p.s. Yes, I had nothing else to do today.
{
int x = 4;
int y = 15;
int *k = &x;
int z;
int *p;
*k = *k * (*k + 1); /* x = x * (x+1) i.e. 20 */
y = x + y; /* y = 20 + 15 i.e. 35 */
k = &z; /* fine, though the content is not initialised */
int a[] = {7,9,3,8};
p = a;
printf("%x\n",(unsigned int)p);
x = *k + 1; /* x = z +1 which is unknown because content of z still not initialised */
p = p + 2; /* pointing to 3 now */
z = *p - 4; /* z= 3 - 4 ; i.e. -1 */
printf("%d %d %x %x\n",x,y,z,(unsigned int)p);
}
The result prints a signed integer (z) as unsigned, which in this case results in the representation of -1 in the twos-complement hex representation, but shown as unsigned, i.e. "ffff ffff" in 32bit.
I initially was confused by z not being intialised, but it turns out to be irrelevant.
It seems to me that the value of p would not really have been predictable.
Judging from the first print being "5a9b1740", the value should be bigger by the size of two ints, i.e. "5a9b1748" on most systems. But that does not match the output you show (before or after your edit to the question; please note 5c9b1748-5a9b1740=2000008 and 5c961748-5a9b1740=1FB 0008. Neither can be explained with the shown code. For some reason people fail to see the large difference and focus only on the few least significant nibbles...)
If those two values come from different runs of the program, then it could explain the difference with intentional randomisation. (Thanks to Gerhardh for making me look for an explanation.)
This is blatantly undefined behavior. The compiler is allowed to lay out variables in any order it likes, even leave variables without backing store (it just keeps the value in a register, sees it isn't ever used, or can deduce it's value each time it is used and doesn't require storing it, ever. You can not legally point outside the referenced object by adding to the pointer. For a rather dumb compiler (or no optimization whatsoever) the above might be right. Or it might not.
For examples of the above, compile some program with e.g. gcc -O2 -g and debug it. When single-stepping the debugger will often jump around seemingly at random in the source, skip some statements altogether, tell you some variables have been optimized out, and others.

When subtracting two pointers in C

I was playing with pointers in order to fully get the concept and then wanted to subtract two pointers expecting the distance between these two addresses or something, but apparently I was wrong, so here is my code.
int x = 5, y = 7;
int *p = &y;
int *q = &x;
printf("p is %d\nq is %d\np - q is %d", p, q, (p - q));
Why does the program output p - q is 1? Thank you.
It is undefined behavior. According to the standard (N1570):
6.5.6 Additive operators
....
9 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.
Note that when allowed, the result is the subscripts difference. So if pointers point to two sequential elements of the same type, the subtraction gives 1, regardless of the size of the type. (This is perhaps the reason why you get 1 in your concrete case.)
Your particular case is cause for undefined behavior since p and q point to unrelated objects.
You can make sense of p-q only if p and q point to the same array/one past the last element of the same array.
int array[10];
int* p = &array[0];
int* q = &array[5];
ptrdiff_t diff1 = q - p; // Valid. diff1 is 5
ptrdiff_t diff2 = p - q; // Valid. diff2 is -5
q - p is 5 in this case since they point to elements of the array that are 5 elements apart.
Put another way, p+5 is equal to q. If you start from p and step over 5 elements of the array, you will point to the same element of the array that q points to.
As an aside, don't use the format specifier %d for printing pointers. Use %p. Use %td for ptrdiff_t.
printf(" p is %p\n q is %p\n p-q is :%td", p, q, p-q);`
// ^^ ^^
See http://en.cppreference.com/w/c/io/fprintf for the valid format specifiers for the different types.
Pointer arithmetic works like that. It doesn't give you differences between two addresses. Instead it will show difference between two variables as if they are stored in an array. so, no matter if your variables (of same type ) are 4 bytes, 8 bytes or 1 byte, if stored in adjacent memory location their pointer subtraction will always result in 1 or -1.
The subtraction of 2 pointers give the distance in between the 2 variables.
For eg.
//let the address of a is 1000 then of a+1 will be 1004
int a[]={1,2,3};
int *p1=a;
int *p2=a+1;
printf("%u",p2-p1);
The result of this will be 1 not 4.
Same here in your case the the location of x and y are consecutive that is why the ans. is 1.
The formula used by pointer substraction is:
( p2 - p1 ) == ( addr( p2 ) - addr( p1 ) ) / sizeof( T )
with T being the type of both p1 and p2.
int array[10];
int* p1 = array + 2;
int* p2 = array + 5;
int* a = p2 - p1; // == 3
int* b = p1 - p2; // == -3
int a=5,b=6;
int *ptr=&a,*diff;
diff=ptr;
printf("%p\n",diff);
ptr++;ptr++;ptr++;ptr++;ptr++;ptr++;ptr++;ptr++;ptr++;ptr++;
printf("%p\n",ptr);
printf("diff==%td\n",(ptr-diff)*sizeof(int));
(diff-ptr) will provide the distance between two variables, but will not provide the memory gap between two pointers.
Important: only the same type of pointer can be subtracted.
The subtraction of two pointers in array will give the distance between the two elements.
Let the address of first element i.e., is 1000 then address of second element a+1 will be 1004. Hence p1 = 1000 and p2 =1004.
p2-p1 = (1004- 1000) /size of int = (1004-1000)/4 =4/4 =1

difference between *y++ and ++*y?

I'm confused in how this code will get executed. Suppose we have
int x=30,*y,*z;
y=&x;
what is the difference between *y++ and ++*y? and also what will be the output of this program?
#include<stdio.h>
int main(){
int x=30,*y,*z;
y=&x;
z=y;
*y++=*z++;
x++;
printf("%d %d %d ",x,y,z);
return 0;
}
The expression x = *y++ is in effects same as:
x = *y;
y = y + 1;
And if expression is just *y++; (without assignment) then its nothing but same as y++;, that is y start pointing to next location after increment.
Second expression ++*y means to increment the value pointed by y that same as: *y = *y + 1; (pointer not incremented)
It will be better clear with answer to your first question:
Suppose your code is:
int x = 30, *y;
int temp;
y = &x;
temp = *y++; //this is same as: temp = *y; y = y + 1;
First *y will be assigned to temp variable; hence temp assigned 30, then value of y increments by one and it start point to next location after location of x (where really no variable is present).
Next case: Suppose your code is:
int x = 30, *y;
int temp;
y = &x;
temp = ++*y; //this is same as *y = *y + 1; temp = *y;
First value of *y increments from 30 to 31 and then 31 is assigned to temp (note: x is now 31).
next part of your question (read comments):
int x = 30, *y, *z;
y = &x; // y ---> x , y points to x
z = y; // z ---> x , z points to x
*y++ = *z++; // *y = *z, y++, z++ , that is
// x = x, y++, z++
x++; // increment x to 31
what is the difference between *y++ and ++*y?
The meaning of an expression in C is characterized by two things: what value it produces and what side effects it produces.
Let's examine the first expression.
Postfix increment is of higher priority than dereferencing, so this is *(y++).
The postfix increment produces a side effect: it changes the value of y to point to a different location. The postfix increment also produces a value: the value that y had before it was incremented. The * operator then dereferences that value to produce an lvalue: that is, something you can use as a variable, either to store to or to fetch from.
I note that the side effect can happen at any point before or after the dereferencing. If you said
q = *y++
then the side effect of the ++ could happen at any point. This could be:
q = *y;
y = y + 1;
or it could be treated as
t = y;
y = y + 1;
q = *t;
Both are perfectly legal. (Except of course that if y is itself an expression with side effects, those side effects must be produced only once. For clarity, I'll make that assumption throughout.)
How about ++*y? That is straightforward: *y produces a variable, the content of the variable is incremented, and the value of the expression is the incremented value. Note that again, the side effect can be produced out-of-order:
q = ++*y
could be treated as:
t = *y + 1;
*y = t;
q = t;
or as
t = *y + 1;
q = t;
*y = t;
Remember, C does not produce very many restrictions on the order in which side effects may happen, so be careful.
what is the difference between *y++ and ++*y?
In case of expression *y++ and *z++; because the postfix version ++ takes precedence over *, the compiler sees this as;
*(y++) = *(z++);
In case of ++*y; compiler sees this as ++(*p) and it will first increment the value of the object it points to ( x in this case) and then return its incremented value.
Summary table for other possibilities;
Expression Meaning
-------------------------------------------------------------------------------------
*y++ or *(y++) Value of expression is *y before increment; increment y latter
(*y)++ Value of expression is *y before increment; increment *t later
*++y or *(++y) Increment y first; value of expression is *y after increment
++*y or ++(*y) Increment *y first; value of expression is *y after increment
EDIT: As pointed out by Eric Lippert in his comment that saying: value of expression is *y before increment, increment y later is misleading, I want to clarify here that the words I used latter and after to emphasize that previous or next value of *y, respectively, will be used in expressions.
Note that, the side-effect can be produced in any order, either side-effect produce first and value assigned latter or value assigned first and side-effect produce latter. For more detail read the answers :-- 1, 2 given by Eric Lippert.
I trust that you understand what the operators ++ and * means when used separately. When used together then operator precedence comes into play. In C++ the ++ operator has a higher precedence than the * operator. So effectively *y++ means *(y++) and ++y* means (++y)*. I hope this helps.

Resources