Richard Hengeveld said:
Thanks for replying.
Yes, that is exactly what is confusing me.
I understand you set a pointer (if you're not passing to functions) by:
int a, *p;
p = &a;
Right, this sets p to contain the address of a (or, equivalently,
causes p to point to a).
The unary '*' operator is prefix, not postfix. You could argue that
it would be easier if it were postfix, but that's not how the language
defines it.
If you meant
*p = &a;
that wouldn't make sense. Since p is a pointer to int, *p is an int,
but &a (address of a) is a pointer to int. The types don't match.
In an assignment, the left hand side has to be an expression (e.g., a
name) that refers to an object of some type, and the right hand side
has to be an expression of that same type (not necessarily an object).
(That's not quite true (there are implicit conversions in some cases),
but it's a good enough first approximation.)
So given:
int a;
int *p;
we can have
a = 42; /* the name "a" refers to an object of type int,
"42" is an expression of type int */
p = &a; /* the name "p" refers to an object of type pointer-to-int,
"&a" is an expression of type pointer-to-int */
*p = 2+2; /* the name "*p" refers to an object of type int
(the object happens to be "a"), and "2+2" is an expression
of type int */
Wouldn't it be more logical if it was something like:
void f(int i) {
int *p
p = i;
No, p refers to an object of type pointer-to-int, but i is an expression
of type int. The types don't match. You can legally say "p = &i;".
p* is a syntax error. *p = 0; is legal, since *p refers to an object
of type int (assuming p has been initialized properly), and 0 is an
expression of type int.
}
int main(int argc, char* argv[]) {
int a;
f(&a);
The function f() expects an argument of type int; you're giving it an
argument of type pointer-to-int. Function argument types have to
match, just as the types in an assignment have to match.
If you want the function f() to be able to modify an int object that
you pass to it, you have to pass the object's address, and f() has to
take an argument of type pointer-to-int. If f() takes an argument of
type int, it just gets a copy of the value of whatever you pass to it;
f() can do whatever it likes with its own copy, but that won't affect
the original object.
If f() is defined as:
void f(int i) { ... whatever ... }
then this:
int x;
f(x);
can't change the value of x, any more than this:
f(42);
can change the value of 42.
Some languages do have ways of specifying that an argument is passed
in a way that allows the function to modify the original object
(Pascal has VAR parameters, Ada as "in out" and "out" parameters, C++
has reference parameters). C doesn't have such a mechanism.
If you want to argue that C could be improved, there are several
things I can say in response:
1. You're right. C's declaration syntax in particular causes no end
of headaches, especially to novices.
2. It's not going to change. Any significant change would break
existing code. That's just not going to happen. If you want a
language with better syntax than C (and that's a subjective
judgement), you'll just have to use a language other than C.
3. If you're interested in C, you should probably learn the language
as it is before you start worrying about how it could be better. K&R2
(Kernighan & Ritchie's _The C Programming Language_, Second Edition)
is one of the best tutorials; buy or borrow a copy and read it.