4

//reference from Herbert Schildt//

This is the first code

void change(char *);

int main(void)
{
    char target[80]="hello";
    change(target);
    printf("%s",target);//printing aaaaa
    return 0;
}

void change(char *tar)
{
    int i;   
    for(i=0;i<strlen(tar);i++)
    {
        tar[i]='a';
    }
}

this is the second code

void change(char *);

int main(void)
{
    char target[80]="hello";
    change(target);
    printf("%s",target);/printing hello
    return 0;
}

void change(char *tar)
{
    int i;
    tar="aaaaa";
}

despite of not passing address of

target

why the string in

target

is getting altered in first code but not in second

why first code is printing

aaaaa

and second code print

hello
Kevin Brechbühl
  • 4,717
  • 3
  • 24
  • 47

3 Answers3

4

The first piece of code changes the contents of the characters pointed to by tar. The second piece changes the local variable tar Itself to point to a different memory location, not the contents of the original memory pointed to. Thus, the original content in main() is preserved in the second case.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
Filipe Gonçalves
  • 20,783
  • 6
  • 53
  • 70
  • but how tar is pointing to target as I have not passed the address as argument –  Jan 12 '14 at 17:47
  • 1
    @user3180902 Because arrays of type `T` decay into pointer to type `T` when used in expressions. So when you write `change(target)`, `target` decays into a pointer. – Filipe Gonçalves Jan 12 '14 at 17:49
  • but I think that the case is similar in both the codes.. I am unable to get the difference between the two codes –  Jan 12 '14 at 17:51
  • But the first code uses `tar[i]`, so you're dereferencing `tar` and writing to that specific memory location. The second code doesn't do that, it merely changes the pointer – Filipe Gonçalves Jan 12 '14 at 17:53
  • what does dereferencing means in your answer –  Jan 12 '14 at 17:56
  • @Filipe Goncalves i think you are confused with array initialisation and assignment.dereferencing means taking a pointer and going to where it points to an altering the data in that memory location. – tesseract Jan 12 '14 at 17:59
  • @tesseract No, I am not. Why would I be? – Filipe Gonçalves Jan 12 '14 at 18:07
  • what if I edit the function change in the first code as *tar[i]='a'; –  Jan 12 '14 at 18:15
  • it won't compile since tar[i] is of type char, not pointer, so it cannot be dereferenced – phuclv Jan 13 '14 at 01:41
  • if in the second code if I edit the change as follows strcpy(tar,"aaaaa"); then it is printing aaaaa not hello why? –  Jan 13 '14 at 06:54
  • Because `strcpy()` copies "aaaaa" into the location pointed to by `tar`. – Filipe Gonçalves Jan 13 '14 at 11:52
0

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.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
-1
char *string  = "something between quotes" 

when you use double quotes in C and put a string inside it, C automatically creates an array for us and puts the stuff between the double quotes to that new array, and the pointer to that new array is now put in the string variable. in your case "aaaa" will make a new array somewhere in memory(probably in the data section) and then the pointer to this new array is given to tar, expressions are evaluated from right to left, so first "aaaaa" is evaluated and then the result of this is given to tar. so basically always use double quotes "sometinh here" when you initialise an array.

@Filipe Goncalves answer is the correct answer, I couldn't write this in a comment, so had to make a new post.

tesseract
  • 891
  • 1
  • 7
  • 16
  • sorry @Filipe Goncalves i mean to say the OP was confused, your answer is correct.. my mistake got the names confused.. – tesseract Jan 12 '14 at 18:17
  • what if I edit the function change in the first code as *tar[i]='a'; –  Jan 12 '14 at 18:22
  • you don't need *, tar[i] = 'a' will print aello, *tar[i] will give you an error,i assumed i was 0. tar[0] = 'a' this will print aello. – tesseract Jan 12 '14 at 18:24
  • 4
    *expressions are evaluated right to left* This is not true. Depending on the expression, order of evaluation can be undefined - be careful when you say this – Filipe Gonçalves Jan 12 '14 at 18:26
  • tar[i] is already in pointer form, in C tar[i] means, *(tar+i), c automatically puts the star for us. do some reading on pointer arithmetic,http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/pointer.html – tesseract Jan 12 '14 at 18:27
  • @user3180902 `tar[i]` is the same as `*(tar+i)`. `*tar[i]` is the same as `**(tar+i)`, so you are actually using `h` as a memory address to write - obviously it won't work. – Filipe Gonçalves Jan 12 '14 at 18:27
  • 1
    This is very nearly a good answer, but it has two major flaws. *"the pointer to that new array is now put in the `string` variable"* -- no, there is no pointer object. `string` is an array, not a pointer. *"expressions are evaluated from right to left"* -- no, in most cases the order of evaluation is unspecified; in the few cases where the evaluation order is defined, it's left-to-right. – Keith Thompson Jan 12 '14 at 20:31
  • @KeithThompson yes you are right.I should have said, char *string. – tesseract Jan 12 '14 at 21:07
  • @tesseract: But then it wouldn't be an answer to the question, which defines an array object, not a pointer object. Are you planning to fix your answer? – Keith Thompson Jan 12 '14 at 21:18
  • if in the second code if I edit the change as follows strcpy(tar,"aaaaa"); then it is printing aaaaa not hello why? –  Jan 13 '14 at 06:58
  • If you want to write a comment, write a comment. If you don't have enough rep, don't write a comment in to the answer field. – David Heffernan Jan 13 '14 at 08:24
  • despite of teaching me how to use this site, you should have answered the question? –  Jan 13 '14 at 08:33