This is the chunk of code I've copied from my lecture notes
/* 2D processing */
printf("\n");
for (i=0; i<3; i++)
for (j=0; j<3; j++)
printf("%d ", *(*(ar+i)+j) );
Since ar
is the pointer referring the address location and *(ar+i)
is actually refers to the content of the address location of ar+i
, but I don't understand how it will work with *(ar+i)+j
, it's like content + a number.
one more thing is,
(1) char *ptr; ptr = "This is a string";
(2) char *ptr = "This is a string";
Why (1) can not be char *ptr; *ptr="this a string"
when declaration and assignment are separated?
Thank you very much in advance.
In the first case ar
is most probably a pointer to a pointer (declared as int **ar;
), thus *(a + i)
is a pointer or an array and *(*(a + i) + j)
is the element.
In C and C++ however there is a rule that says that an array can implicitly "decay" to a pointer to the first element in many cases and thus it's also possible that ar
has been declared in other ways:
int **ar; // (1) A pointer to a pointer
int *ar[3]; // (2) An array of pointers
int ar[3][3]; // (3) An array of arrays
When writing ar + i
in case ar
is an array it decays to a pointer to the first element (case 2 and 3) and the result is the address of a pointer (case 2) or the address of an array (3). Using the dereference operator *
then gets the element that is either a pointer or an array.
When you the add j
and the element is an array (case 3) this array also decays to a pointer to its first element before computing the addition. Thus to recap, dependin on how ar
is defined:
ar // (1) a pointer to a pointer,
// (2) a pointer to array,
// (3) an array of array
ar + i // (1) and (2) address of a pointer
// (3) address of array
*(ar + i) // (1) and (2) a pointer
// (3) an array
*(ar + i) + j // address of an integer in any case
*(*(ar + i) + j) // an integer in any case
Don't worry if this seems confusing, because it is. Normally when you use *(x + i)
is because x
is a pointer however and that's why I guessed that ar
has been declared as int **ar;
. Note also that in C and C++ *(x + i)
is perfectly equivalent to x[i]
or even to i[x]
.
In the second case the reason is how the declaration are written in C.
char * s = "foo";
should be read as
(char *s) = ("foo"); // Not legal C, just to show type declaration and
// initialization
in other words the *
is part of the type declaration of s
, not an operation applied to s
.
Note however that
char *s, t;
declares s
as a char *
and t
as a char
.
Type declarations are probably the most powerful but difficult part of C syntax because it's not obvious what is the part being declared. For example
int *(*f)(int *(*g)(int x));
is a valid declaration for the type of f
and the names g
and x
are instead irrelevant and could be omitted.
int *(*f)(int *(*)(int)); // Same as above
The type of f
in this case is a pointer to a function accepting a pointer to a function accepting an int and returning a pointer to an int, and returning a pointer to an int.
My guess is that the vast majority of C programmers would however need to think a bit before being able to decipher that :-D
To elaborate a bit:
a[b]
is always a shorthand of *(a+b)
.If you combine that with the pointer arithmetics rules (or derive these from there), any of a
and b
can be a pointer, the other one an integer, denoting the offset.
With this rule, you can transform an expression like *(*(ar + i) + j)
to *(ar[i] + j)
and then to ar[i][j]
.
Alas, you don't tell us what your ar
is, but we can tell the following:
ar[i][j]
is a valid expression, ar[i]
is a pointer or an array which has decayed into a pointer in this expression.ar
.In order for this to be true, ar
can be any of
type** ar
type (*ar)[]
type ar[][]
type * ar[]
where type
is the type of each of the components.
These four alternatives all have a different memory layout, but are accessed the same way.
That's how pointer arithmetics and array decaying works. Best have a look at a good book or tutorial.
The second question should better be a separate question.
It is just because of the assignment and initialization rules of C.
You define a pointer
type * p;
type * p = <init value>;
but
p = <new value>;
is how you assign it.
Keep in mind that a string literal is transformed into the address of that string in its readonly memory section.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With