Pointers for 2D arrays - c

This is a question from Microsoft Test:
main()
{
int a[2][3]= { (1,2,3),(4,5,6)};
int (*ptr)[3] = &a[0];
printf("%d %d\n", (*ptr)[1],(*ptr)[2]);
ptr+=1;
printf("%d %d\n", (*ptr)[1],(*ptr)[2]);
}
Options given are:
segmentation fault
compiler error
bus error
run time error
I ran this code and I didn't get any of this. I got the following answer:
6 0
0 0
Can you please help me understand what's happening?

The main issue is this line:
int a[2][3]= { (1,2,3),(4,5,6)};
It is using parentheses instead of braces. The result of (1,2,3) is just 3, and the result of (4,5,6) is just 6. So this is equivalent to:
int a[2][3]= { 3,6 };
Which in turn is equivalent to
int a[2][3] = { {3,6,0}, {0,0,0} };
This line makes ptr point to a[0]:
int (*ptr)[3] = &a[0];
This line
printf("%d %d\n", (*ptr)[1],(*ptr)[2]);
is then equivalent to
printf("%d %d\n", (*&a[0])[1],(*&a[0])[2]);
which can be simplified to
printf("%d %d\n", (a[0])[1],(a[0])[2]);
or just
printf("%d %d\n", a[0][1],a[0][2]);
This line
ptr+=1;
makes ptr point to the next element of a, so it is equivalent to
ptr=&a[1];
so the next line simplifies to
printf("%d %d\n", a[1][1],a[1][2]);
The program effectively prints a[0][1], a[0][2], a[1][1] and a[1][2], so that's why you get 6,0,0,0.
Charles Baley points out that main() is missing the return type. This may be what they are getting at. The compiler would normally at least give a warning about that.

Are you sure you copied the text correctly?
(1,2,3) is an expression with two sequence or comma (,) operators; its value is 3. Likewise, the value of (4,5,6) is 6. This is the 6 that is being printed at a[0][1] (since ptr points to a[0] and you print (*ptr)[1]); the 0 is a[0][2], which has default initialization of 0. Then you increment ptr, pointing it to a[1], so you print a[1][1] and a[1][2], which also have default initialization of 0.

Related

Pointers in C Language (Code Explanation)

Could someone please explain to me step by step what this code does?
int main(int argc, const char* argv[]) {
int numbers [2] [3] = {{1,2,3},{4,5,6}};
int (*num_ptr) [3]= numbers;
printf ("value is : %d\n",*(*(num_ptr+1)));
printf ("value is : %d\n",**num_ptr);
printf ("value is : %d\n",*(*num_ptr)+1);
printf ("value is : %d\n",*(*(num_ptr+1))+1);
//return (EXIT_SUCCESS);
}
It is easier to understand the code if you use array index notation. A[B] is the same as *(A+B), and vice versa, in all cases; with a special case being that A[0] is the same as *(A + 0), which is the same as *A if A is a valid pointer.
Applying this transformation, your code becomes:
printf ("value is : %d\n", num_ptr[1][0]);
printf ("value is : %d\n", num_ptr[0][0]);
printf ("value is : %d\n", num_ptr[0][1]);
printf ("value is : %d\n", num_ptr[1][0] + 1);
Hopefully you can take it from here.
The definition of num_ptr ensures that num_ptr[A][B] is the same as numbers[A][B]. Your program would be unchanged if the printf statements used numbers instead of num_ptr, because the array numbers decays to the same pointer value that num_ptr has.
*(*(num_ptr+1))
^^^^^^^^^^
skip the first row
No columns skipped after that
Ans = 4
**num_ptr
No rows or columns skipped
Ans = 1
*(*num_ptr)+1
^^^^^^^^^^^
no rows or column skipped
add 1 to the ans
Ans = 2
*(*(num_ptr+1))+1
^^^^^^^^^^^^^^^
skip first row, no columns skipped
add 1 to answer
Ans = 5
int (*num_ptr) [3]= numbers; declares num_ptr as a pointer to an array of 3 int and initializes it to the first element of array numbers. It is equivalent to
int (*num_ptr) [3]= &numbers[0];
num_ptr points to array numbers[0] and num_ptr+1 points to numbers[1]. *(num_ptr+1) dereferences num_ptr+1 and gives an array. As array decays to pointer to its first element in most context, *(num_ptr+1) will finally give &number[1][0]. So, *(*(num_ptr+1)) is equivalent to *(*(&number[1])) == *(&number[1][0]) == 4.
Similarly, **num_ptr will give 1, *(*num_ptr)+1) will give 1+1 =2 and *(*(num_ptr+1))+1 will give 4+1 =5.
First of all let's remove redundant parenthese inside the printf statement.
It will look like
printf ("value is : %d\n", **(num_ptr + 1) );
printf ("value is : %d\n", **num_ptr );
printf ("value is : %d\n", **num_ptr + 1 );
printf ("value is : %d\n",**( num_ptr + 1 ) + 1 );
num_ptr is declared like pointer to the first element of array numbers.
The elements of the array numbers are two on-dimensional arrays { 1, 2, 3 } and { 4, 5, 6 }
So expression *num_ptr yields the first one-dimensional array. In expressions with rare exceptions arrays are implicitly converted to pointers to their first elements. Thus this expression *num_ptr is converted to pointer to first element that is to 1 And **num_ptr gives the value.
As result this statement
printf ("value is : %d\n", **num_ptr );
outputs 1.
This statement
printf ("value is : %d\n", **num_ptr + 1 );
just adds 1 to the value of the prvious expression and outputs it that is 2.
As num_ptr is pointer to the first one-dimensioanle array then num_ptr + 1 is pointer to the second on-dimensional array { 4, 5, 6 }. Other calculations are the same as described above.
Thus statement
printf ("value is : %d\n", **(num_ptr + 1) );
outputs 4 and statement
printf ("value is : %d\n",**( num_ptr + 1 ) + 1 );
outputs 4 + 1 that is 5.

Pointer not printing in the desired way

This is a C code
int (*a)[3];
a is a pointer to an array of 3 integers
a=(int (*)[3])malloc(sizeof(int)*3);
note the Typecast used here; the number of elements must be specified in the typecast shown. Also, the brackets around the * is necessary.
printf("brrbrrbrr %d %d %d %d\n",&a,a,a+1,a+2);
*(a+0)[0]=40;
*(a+0)[1]=41;
*(a+0)[2]=42;
printf("noobnoob %d %d %d \n",a[0][0],*(a+0)[1],(*(*(a+0)+2)));
The output is:
brrbrrbrr -7077000 29278656 29278668 29278680
noobnoob 40 41 0
I am not getting why the last number is 0 instead of 42?
Indexation has higher precedence than dereferencing a pointer. Your assignments don't do what you want. They are evaluated like:
*((a+0)[0])=40;
*((a+0)[1])=41;
*((a+0)[2])=42;
If you want to keep your syntax, you shall use parenthesis like:
(*(a+0))[0] = 40;
(*(a+0))[1] = 41;
(*(a+0))[2] = 42;
The same applies for printing the second element of the array. *(a+0)[1] shall be (*(a+0))[1].
What you are looking for is
int (*a)[3] = malloc(sizeof(int) *3);
(*a)[0] = 40;
(*a)[1] = 41;
(*a)[2] = 42;
printf("%d %d %d\n",(*a)[0],(*a)[1],(*a)[2]);
a is a pointer to an array of 3 int members. So allocate memory for the pointer and store values as shown above.
If you want the address of where the values are stored then you should do
printf("%p\n",(void*)(a)[0]);

pre-increment and post-increment in printf

int main()
{
int value = 4321;
int *ptrVal = &value;
printf("%d %d",++value,(*(int*)ptrVal)--);
return 0;
}
How does pre-increment/post increment works in above print statement ?
And why is answer 4321 4321 ?
You are modifying the object value twice between two sequence points: you are invoking undefined behavior. Undefined behavior means your program can print 4321 4321, print 42 or even just crash.
A correct version of your program would be:
int value = 4321;
int *ptrVal = &value;
++value;
(*ptrVal)--; // no need to cast to int *
printf("%d %d", value, *ptrVal); // same as printf("%d %d", value, value);
Of course you don't need any temporary pointer to achieve this.
The code above is just broken. It is unspecified how it will work or what the answer will be. You need a sequence point between modifications or modifications and accesses.

Why this c program output like this?

#include<stdio.h>
main
{
int x[]={1,2,3,4,5};
int i,*j;
j=x;
for(i=0;i<=4;i++)
{
printf("%u",j);
j++;
}
}
output:
65512
65514
65516
65518
65520
But when I change the printf to"
printf("%u",&j[i]);
Output is:
65512
65516
65520
65524
65528
Why the address differ by 2 in first case and 4 in second casee?
What is wrong with just printing j and printing &j[i]?
You get jumps of 4 in the second example because you are incrementing j and offsetting by i! Both of these contribute a difference of 2.
Note also that printf is not type-safe; it is up to you to ensure that the arguments match the format-specifiers. You have specified %u, but you've given it an int *, you should use %p for pointers.
First, just to make it clear, you are printing the pointer j, and not the pointed value, *j
Now, regarding the printed address. In your second example:
for(i=0;i<=4;i++)
{
printf("%u",&j[i]);
j++;
&j[i] equals to (j+i). i is incremented in each iteration, which contributes 2 to the pointer's value, and j is incremented too, which contributes another 2.

C: Pointer confusion

I understand this is part of the basic stuff, but i am stuck :-(
Can someone please help me?
Program 1:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a=1,b=2,c;
c=(a+b)++;
}
Why is the output an error? lvalue required?
Program 2:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *p1="name";
char *p2;
p2=(char*)malloc(20);
memset(p2,0,20);
while(*p2++=*p1++);
printf("%s\n",p2);
}
Why is the output, an empty string? And if i reverse the order of increment, that is: while(++*p2=++*p1);, why the lvalue error comes?
For the first question,(a+b)++ means "increment the value of a+b by 1".
You cannot increment a+b, though, for it's not a variable. What would you expect to happen in the following code?
int a = 1, b = 2;
printf("a = %d, b = %d, a+b = %d\n", a, b, a+b);
(a+b)++;
printf("a = %d, b = %d, a+b = %d\n", a, b, a+b);
Clearly the first printf should print
a = 1, b = 2, a+b = 3
But what about the second one?
a = ?, b = ?, a+b = 4
It's not clear what a or b should be if we increment the sum.
As for the second question, remember that you're changing p2 when you copy over the data, so when you ask to print out what it's pointing at, it's pointing at the end of the string, not the beginning.
An easier way to do the string copy would be to use strcpy, like so:
strcpy(p2, p1);
Note, this is only safe because you know that the size of the string in p1 isn't greater than the size of p2. If you're not sure about the size of the string (for instance, if you get the string from user input), you'll need to be careful, as is outlined on Wikipedia.
As for why while(++*p2=++*p1); doesn't work, while while(*p2++=*p1++); does:
Postfix-++ has higher precedence than *. This means, *p2++ means *(p2++).
So
*(p2++) = something;
is the same as
*p2 = something;
p2 += 1;
Meanwhile, ++*p2 means ++(*p2), or "whatever p2 points to, incremented by one".
Again, you get the problem, if you say:
int a = 5, *p2 = &a;
++*p2 = 10;
printf("a = %d\n", a);
What would you expect this to print? If anything, it should print 9, because you're telling the compiler that *p2+1 = 10.
You can't expect a C-compiler to solve that equation, however, so in order to keep the language simple and efficient, this sort of thing is forbidden.
c=(a+b)++;
a+b is not a lvalue - how would you want to assign something to the result of an addition (a rvalue) - and the ++/-- operators do assign the new value.
while(*p2++=*p1++);
You p2 points at the \0 at the end of the string. You need to store the original address p2 points to before your loop:
char *p3 = p2;
while(*p2++=*p1++)
;
printf("%s\n",p3);
c=(a+b)++;
The ++operator doesn't work with temporary variables. (a+b) forms a temporary.
while(*p2++=*p1++);
You're incrementing p2 here. After the loop, p2 no longer points to the beginning of the memory block returned by last malloc() call.
If you look at the while loop:
while(*p2++ = *p1++);
remember that an expression is "True" in C if it is non-zero, and false if it is zero. Even though the loop has no body, the flow of control is still:
check condition -> execute statement in body --> check condition
and here, "check condition" means "evaluate the statement and see if it is non-zero".
The while loop continues to operate until p1 points to zero, at which point control passes to printf.
e.g.
int main()
{
int array1[] = {2, 3, 1, 0, 3, 5};
int array2[20];
int * p2 = (int *)memset(array2, 0, 20*sizeof(int));
int * p1 = array1;
while(*p2++ = *p1++) {
printf("In while: p1 is %d\n", *p1);
}
printf("Out of while: %d\n",*p2);
return 0;
}
yields:
In while: p1 is 3
In while: p1 is 1
In while: p1 is 0
Out of while: 0

Resources