スタジオおふとん

プログラミング系

いっつも忘れる配列の狙ったindexからポインタ渡す方法

#include <stdio.h>

void test_print(char* array) {
    printf("%d\n", *array);
}

int main() {
    char array[] = {0, 2, 4, 6, 8, 10};
    test_print(array + 1);
    return 0;
}

出力は2です。

まぁこれtest_print(&array[1]);と同義なんですけど。いわゆるポインタ演算というやつ。
なんでわかりにくいかっていうとポインタ演算って普通、以下のような感じじゃないですか。
(これの出力も2)

    char test = *(array + 1);
    printf("%d\n", test);

記事にしようと思ったけど途中でめんどくさくなってやめた
ポインタ理解しにくい3つの理由の筆頭に上がるであろう
アスタリスクに意味持たせすぎ問題」
がめちゃくちゃ混乱を招いてしまうわけですよ。

引数の*はポインタという型を意味していて、
後者の右辺にある*(array + 1)*はポインタの中身を意味している
わけですよ(printfとかでよく使うのも後者)。

で、結局引数としてポインタ(アドレス)を渡しているので、指定したindexの配列のアドレスとしても置き換えられるのです。(test_print(&array[1]);と同義のところの解説)

(アドレスっていうと&だろ。っていう連想もポインタ理解しにくい3つの理由のうちのひとつなんですが、話すと長くなるのでまた今度)

ポインタ演算の突っ込んだ解説(おまけ)

ポインタ演算がなんでできるかっていうと、型が決まっているからなんですね。
つまり、型によって +1 で進むbyte数が違うんですよ。

実験してみましょう。
先ほどのコードのtest_printのprintfは*でそこのポインタ(の中)の値をとってきていたので、この*外すとアドレスをprintfできます。

というわけで以下のような感じ

#include <stdio.h>

void test_print(char* array) {
    printf("%p\n", array);
}

void test_print_int(int* array) {
    printf("%p\n", array);
}

int main() {
    char char_array[] = {0, 2, 4, 6, 8, 10};
    int  int_array[]  = {0, 2, 4, 6, 8, 10};

    test_print(char_array);
    test_print(char_array + 1);
    test_print_int(int_array);
    test_print_int(int_array + 1);

    return 0;
}

この結果は私の環境では以下の通り

0x7fff4e19d500
0x7fff4e19d501
0x7fff4e19d4e0
0x7fff4e19d4e4

最初の2つがchar型
最後の2つがint型
同じ+1だけど、差分が違うのがわかると思います。

もっと知りたい方は以下の本に詳しく書いてあります。