pedja
pedja

Reputation: 3413

c - incrementing array pointer

Can someone explain to me why this doesn't work. I'm java developer and new to c/c++
As far as i understood pointer of array is actually pointer of arrays first element, is that correct?

void test(char *tmp)
{
    test2(tmp);
    //*tmp++ = '1';
    //*tmp++ = '2';
    *tmp++ = '3';
    *tmp++ = '4';
    *tmp = 0;
}

void test2(char *tmp)
{
    *tmp++ = '1';
    *tmp++ = '2';
}

int main(int argc, char **argv)
{
    char tmp[5];
    test(tmp);
    printf("%s", tmp);
    return 0;
}

only 34 gets printed. When i debug this code in function test2 pointer of tmp is incremente by one but back in function test after test2 is called, pointer of tmp is back to its initial value.
If i just put all of the code in single function like this, it works:

void test(char *tmp)
{
    *tmp++ = '1';
    *tmp++ = '2';
    *tmp++ = '3';
    *tmp++ = '4';
    *tmp = 0;
}

Also what does the *tmp = 0 on the last line do. I copied it from some other code. Without it there is some junk on the end of the array.

Upvotes: 3

Views: 4637

Answers (5)

Vlad from Moscow
Vlad from Moscow

Reputation: 310930

Function parameters are its local variables. Arguments are passed to functions by values that means that copies of the arguments are passed.

So in function test2 there is used a copy of pointer tmp of function test. Any changes of a copy of an object do not influence on the object itself.

The call of test2 can be imagine the following way

void test(char *tmp)
{
//  test2(tmp);
    char *new_ptr = tmp;
    test2( new_ptr );
//  ...
}

void test2(/*char *tmp*/)
{
    char *tmp = new_ptr;
    *tmp++ = '1';
    *tmp++ = '2';
}

If you declared the parameter of test2 as a reference to pointer then in this case the pointer itself could be changed. For example

void test(char *tmp)
{
    test2( &tmp );
    //     ^^^^
    //*tmp++ = '1';
    //*tmp++ = '2';
    *tmp++ = '3';
    *tmp++ = '4';
    *tmp = 0;
}

void test2(char **tmp)
//         ^^^^^^^^^^
{
    *( *tmp )++ = '1';
    *( *tmp )++ = '2';
}

As for arrays then an array used in expression with rare exceptions as for example using an array in operator sizeof is implicitly converted to pointer to its first element.

So if for example you have an array of type T

T a[N];

then the following declaration

T *p = a;

is valid and the pointer is initialized by the address of the first element of the array a.

Another example

char *s = "Hello";

Here is string literal "Hello" is used in an expression as an initializer. The string literal that includes terminating zero '\0' has type char[6] is implicitly converted to pointer to its first character 'H'.

In C++ string literals have types of constant character arrays. So the string literal "Hello" in C++ has type const char[6].

So in C++ you have to write

const char *s = "Hello";

But in the both languages string literals are immutable.

Upvotes: 1

Nunchy
Nunchy

Reputation: 948

The 0 is a nul terminator, the string ends with a 0 or nul byte so that functions like printf() know where the string ends, because - how long is a piece of string?

Since you're passing the pointer to test2() and test2() is incrementing the pointer - but not actually passing the altered/incremented pointer back to the calling function...as far as test() is concerned the pointer hasn't changed so subsequent alterations are overwriting previous changes.

#include <stdio.h>
#include <stdlib.h>

char *test2(char *tmp)
{
   *tmp++ = '1';
   *tmp++ = '2';

   return tmp;
}

void test(char *tmp)
{
    tmp = test2(tmp);

    //*tmp++ = '1';
    //*tmp++ = '2';
    *tmp++ = '3';
    *tmp++ = '4';
    *tmp = 0;
}

int main(int argc, char **argv)
{
    char tmp[5];

    test(tmp);
    printf("%s", tmp);

    return 0;
}

Here test2 is returning the altered/incremented pointer to the caller, tess() will receive the updated char. Since you're adding the 0 or nul byte at teh end you need an array of at least 5 elements here.

the above code should work fine for you.

Upvotes: 1

Timmy
Timmy

Reputation: 745

It's normal that if you write all in 1 function you get 1234, but if you write 2 function passing always the same pointer the second one overwrite what the first has already done.

test:
tmp -> Point to [100]
call test2 giving [100] as parameter
write 3 in [100]
increment pointer from [100] to [101]
write 4 in [101]
increment pointer from [101] to [102]

test2:
tmp -> Point to [100]
write 1 in [100]
increment pointer from [100] to [101]
write 2 in [101]
increment pointer from [101] to [102]

Now I imagine you can see the error.

Upvotes: 0

tdao
tdao

Reputation: 17678

In function test2, pass-by-pointer means you can modify what tmp points to, but test2 does not modify the pointer itself.

void test2(char *tmp)
{
    *tmp++ = '1';
    *tmp++ = '2';
}

So in the caller function test, after calling test2 the pointer does not move forward by 2 positions as you would expect, instead tmp remains the same (which is pointing the the very first value of the array). So what actually happens is test2 assign 1 and 2 for the first two elements, and then test overwrite those two values with 3 and 4.

void test(char *tmp)
{
    test2(tmp);
    *tmp++ = '3';
    *tmp++ = '4';
    *tmp = 0;
}

Also what does the *tmp = 0 on the last line do.

That's string terminator.

Upvotes: 4

Martin James
Martin James

Reputation: 24847

Incrementing the 'tmp' in test2() does not increment the 'tmp' in test(). After the test2() call returns, the '1' and '2' written by test2 are overwritten by '3' and '4'.

The zero is the '\0' c-style 'string' terminator.

Upvotes: 2

Related Questions