简体   繁体   中英

what c++ pointers do in this code

#include <cstdlib>
#include <iostream>

using namespace std;

void f(int k[0]){ --k[1]; }
void g(int *k){(*(--k))++;}
void h(int k[1]){--k;}

int main(){
    int k[]={1,2,3,4};
    f(k+2);
    g(k+2);
    h(k+2);
    for (int i = 1; i < 4; i++)
        cout << k[i];
}

Correct output is 333 but I thought it was 334 . I do not understand what exactly happen in function f with the instruction --k[1] . I could agree with the correct output if the code was k[0]-- . What's the difference? Thanks

--k[1] decrements the value at k[1] , and given f(k+2) means the f() -local k points to the caller's (ie main() 's) k[2] , and the 1 and 2 indices add, you're actually decrementing the caller's k[3] from 4 to 3.

k[0]-- would decrement the variable at *k , which for f would be known as k[2] in the caller's context.

The important insights for understanding this code are:

  • all the functions f , g and h ultimately get a pointer to an int , and their notion of " k " is completely independent of the caller's notion of k , specifically - it's offset 2 int s further into the caller's k array,

  • operator precedence : specifically, prefix decrement is applied after array subscripting in --k[1] .

That said, paxdiablo certainly has a point... ;-).

First, all three functions have exactly the same signature. It would be less confusing if it had been written:

void f(int* pi){ --pi[1]; }
void g(int* pi){(*(--pi))++;}
void h(int* pi){--pi;}

(I've changed the name of the argument to avoid ambiguity in the following discutions.)

Also, of course: a[b] is, by definition, *(a + b) , and that any operation on k will convert it from int[4] to int* , pointing to the first element.

So we get the following results:

f( k + 2 );
//  In f, pi is k + 2, so `pi[1]` is *(k + 3).
//  After f, k = { 1, 2, 3, 3 }
g( k + 2 );
//  In g, pi starts out as k + 2; it is then decrementd to give k + 1
//  After g, k = { 1, 3, 3, 3 }
h( k + 2 );
//  In h, pi is k + 2.  A local copy of k + 2, so h doesn't change
//  k at all.

The results are that k is { 1, 3, 3, 3 } after the four operations.

With a slight change to the code, you can see what each step is doing:

#include <cstdlib>
#include <iostream>
using namespace std;

int *globk;
void dumpk(int *pk) {
    cout << "Array:";
    for (int i = 0; i < 4; i++)
        cout << ' ' << globk[i];
    cout << ", k at index " << (pk-globk) << '\n';
}

void f(int k[0]) { dumpk(k);    --k[1];  dumpk(k); }
void g(int *k)   { dumpk(k); (*(--k))++; dumpk(k); }
void h(int k[1]) { dumpk(k);    --k;     dumpk(k); }

int main(){
    int k[]={1,2,3,4};
    globk = k;  // save for detecting where k is

    f(k+2);
    g(k+2);
    h(k+2);

    // slightly prettier output.

    for (int i = 1; i < 4; i++)
        cout << k[i] << ' ';
    cout << '\n';
}

The output of that shows what each step does:

Array: 1 2 3 4, k at index 2
Array: 1 2 3 3, k at index 2
--k[1];         // -- array VALUE at INDEX 3 (2+1) down to 3

Array: 1 2 3 3, k at index 2
Array: 1 3 3 3, k at index 1
(*(--k))++;     // -- POINTER to [1], then ++ that VALUE up to 3

Array: 1 3 3 3, k at index 2
Array: 1 3 3 3, k at index 1
--k;            // Simply -- POINTER with no change to any VALUE

What this code is doing is:

  1. Pass a an array starting at the 3rd element in k[] to f . f takes a 1-dimensional array and decreases its 2nd element (in this case it will be k[4] which will change its value of 4 to 3).

  2. Pass a pointer of the 3rd element in k[] to g . g takes a pointer to an integer or array, and first decreases the value of the pointer (becoming now a pointer to the 2nd element of k[] ) and then increases the value of what's pointed, changing it from 2 to 3.

  3. Pass a an array starting at the 3rd element in k[] to h . ``h receives a 1-dimensional array and decreases the pointer to the array (not the value it points to) thus not modifying the values of the pointed array.

f and g are modifying values, while h is modifying an address:

f(int k[0]){ --k[1]; }

f take one parameter, an array of int; k[1] is the same as k++ in this case; the function is decrementing the value of the element situated at the next address vs the one passes as argument. So It's decrementing k[3] in your main.

g is relatively straight forward and I think you figured that out.

h is similar to f

h(int k[1]){--k;}

h takes a int array as input and it decrements the address passed as argument.

Hope this helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM