Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
int c[]={2.8,3.4,4,6.7,5};
You've declared c as an array of int, and the size is taken from the number of elements in the initializer (5). Note that the floating-point values in the initializer (2.8, 3.4, 6.7) will have their fractional portion discarded (2, 3, 6). If you want an array of floating-point values, you must declare it as either float or double instead of int.
In the declaration
int j,*p=c,*q=c;
c is not the operand of the sizeof or unary & operators, so it is converted to a pointer expression, and its value is the address of the first element in the array, so both p and q are initialized with the address of the first element in c. In memory, it would look something like this (addresses are pulled out of thin air, and we're going to assume 4-byte ints, 4-byte pointers, and a big-endian architecture):
Item Address 0x00 0x01 0x02 0x03
---- ------- ---- ---- ---- ----
c 0x80001000 0x00 0x00 0x00 0x02
0x80001004 0x00 0x00 0x00 0x03
0x80001008 0x00 0x00 0x00 0x04
0x8000100c 0x00 0x00 0x00 0x06
0x80001010 0x00 0x00 0x00 0x05
j 0x80001014 0x?? 0x?? 0x?? 0x?? // ?? represents unknown byte value
p 0x80001018 0x80 0x00 0x10 0x00
q 0x8000101c 0x80 0x00 0x10 0x00
Both p and q contain the address of the first element of c. j is not explicitly initialized, so its value is indeterminate.
In your first loop,
for(j=0;j<5;j++)
{
printf(" %d ",*c);
++q;
}
You're dereferencing c (which is allowed; since c is not the operand of the sizeof or unary & operators, it's converted to a pointer type); *c is equivalent to c[0], and it evaluates to the value of the first element of c, which is 2. You then update the value of q to point to the next element of c, but you don't do anything with it. Changing the value in q does not affect the value in c.
In the second loop,
for(j=0;j<5;j++)
{
printf(" %d ",*p);
++p;
}
You're printing the value that p points to. Initially p points to the first element of c; each time through the loop, p is updated to point to the next element of c, sort of like this:
j p *p
- ---------- --
0 0x80001000 2
1 0x80001004 3
2 0x80001008 4
3 0x8000100c 6
4 0x80001010 5
The same thing is happening with q in the first loop, you just aren't using it in the print statement.
Note that p++ doesn't simply add 1 to the value stored in p; pointer arithmetic takes the size of the pointed-to type into account, so that p++ will advance p to point to the next element of that type. If the type of *p is char (size 1), then it will advance 1 byte. If the type of *p is a four-byte integer, then it will advance 4 bytes.
Note that even though the expression c may be converted to a pointer type under most circumstances, the object that c designates is not a pointer. c does not store an address anywhere. Also, c may not be the operand of the ++ or -- operators, nor may it be the target of an assignment; you can change the values stored in each c[i], but you cannot change the value of c itself.