LoginSignup
0
0

More than 1 year has passed since last update.

【C】初めてのC言語(12. 3つのからくり構文+ポインタ演算)

Last updated at Posted at 2022-07-03

はじめに

※今回の内容は、スッキリわかるC言語入門 第2版のp.363~p.377となります。

学習環境

  • 今回はpaiza.ioのC言語のエディタを使いました。

3つのからくり構文

その1:関数宣言の解釈

関数の引数や戻り値に配列型を指定すると、ポインタ型を指定したものと見なされる。

Main.c
#include <stdio.h>

void funcA(int* x) {
    printf("2番目の要素は%dです。\n", x[1]);
}

int main(void){
    int array[3] = {2, 4, 6};
    funcA(array);

    return 0;
}
  • 上記のサンプルコードの場合、funcA関数の引数宣言は以下のものと実質的に同義だそうです。
    • funcA(int x[3])
    • funcA(int x[])
    • funcA(int*)

その2:配列変数の評価

ソースコード上に書かれた配列変数名は、その配列の先頭要素の位置を示すアドレスに「化ける」。

  • 上記のfuncA関数に配列を渡す場合、これまではfuncA(array);と書いてきましたが、funcA(&array[0]);と書いても同じ意味になるそうです。

その3:添え字演算子の評価

ポインタ変数pがある時、p[0]*pは同じ意味になる。
またpがvoid*型以外である時、p[整数]*(p+整数)も同じ意味になる。

  • このルールに従うと、上記のサンプルコードのfuncA関数は以下のように書き換えられます。
Main.c
void funcA(int x[]) {
    printf("2番目の要素は%dです。\n", *(x+1));
}

ポインタ演算

** X* 型のポインタ変数に加算や減算を行うと、その計算結果のアドレス値は「X*型のサイズ」を単位として増加・減少する。**

  • 例えばint型のポインタ変数aに対して1加算すると、int型は4byteなので、その結果のアドレス値は1ではなく4増えます。
    • 同様にshort型のポインタ変数bに対して3加算すると、short型は2byteなので、その結果のアドレス値は3ではなく6増えることになります。
  • この「ポインタ演算」が存在することで、上記の「3つのからくり構文」の「その3:添え字演算子の評価」のような書き方が出来るそうです。

オーバーラン

  • 以下のように要素数3の配列arrayに対して、大きすぎる(あるいは小さすぎる)添え字を指定することで、配列arrayのために確保されている領域外へのメモリアクセスをすることが出来ます。
  • このように本来割り当てられていないメモリ領域へのアクセスをオーバーランと呼びます。
  • 意図せずにオーバーランする不具合を抱えたプログラムは、サイバー犯罪に悪用されることもあります。
Main.c
int main(void){
    int array[3] = {2, 4, 6};

    // 配列のために確保されている領域外へのメモリアクセス
    printf(array[-1]);
    printf(array[3]);

    return 0;
}

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0