Quick answer: In both cases, what's being passed to the change
function is a pointer value (not a pointer object). That pointer value is the address of the first element of the target
array. In the first example, the change
function modifies the array that that pointer points to. In the second example, the change
function modifies the pointer. Specifically, it modifies the function's local copy of the pointer, which has no effect on the caller.
//reference from Herbert Schildt//
There's your first problem. Herbert Schildt has written several books on C, but he really doesn't know the language very well. Read some reviews of his books written by actual C experts: The Annotated Annotated C Standard, written by Clive D.W. Feather, and C: The Complete Nonsense, written by Peter "Seebs" Seebach.
I don't know which book your examples came from. His use of int main(void)
, which is correct, probably indicates that it's one of his later books; in his earlier books he uses void main(void)
, which is blatantly incorrect (or at least gratuitously non-portable).
Find a better book.
In your first example:
void change(char *tar);
...
char target[80]="hello";
change(target);
the parameter tar
is a pointer. That pointer is not changed; the change
function changes what the pointer points to. target
is an array object, but there's a special-case rule in C that says that an expression of array type is implicitly converted to a pointer to the array's first element in most contexts. (The exceptions are when the array is the operand of a unary &
or sizeof
operator, or when it's a string literal in an initializer used to initialize an array object; none of those apply here.)
So in the call change(target)
, the argument passed to the change
function is a pointer to (equivalently, the address of) the array element target[0]
; the call change(&target[0])
would be exactly equivalent. And via pointer arithmetic, the function can change not just the char
object that the pointer points to, but other char
objects that are elements of the same array. (The []
indexing operator is defined in terms of pointer arithmetic.)
Incidentally, this loop:
for(i=0;i<strlen(tar);i++)
/* ... */
is horribly inefficient. It recomputes strlen
on each iteration of the loop, and each recomputation traverses the entire string.
The change
function in the second example is quite different:
void change(char *tar)
{
int i;
tar="aaaaa";
}
The assignment copies a pointer value, not an array value. (There are no array assignment in C; that's why we have functions like strcpy
and memcpy
.) tar
, like in the first example, is a parameter of pointer type. A parameter is a local variable that take its initial value from the corresponding argument passed by the caller. The assignment modifies that local variable (so it points to the array associated with the string literal), but it has no effect on the value passed in by the caller.
Finally, in both examples, the main program does this:
printf("%s",target);
(Incidentally, it should be "%s\n"
, not just '%s"
.) The result of evaluating the expression target
does not change; it's the base address of the array, and that's fixed as long as the array exists. So why does the output change? Because the %s
format specifier, unlike any other printf
format specifier, prints not the value of the corresponding argument, but the value of what it points to.
Suggested reading: section 6 of the comp.lang.c FAQ, titled "Arrays and Pointers". It's the best resource I know of for explaining the often confusing relationship between arrays and pointers in C.