1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CS50 filter RGBTRIPLE notation

Last updated at Posted at 2021-12-12

概要

CS50 week4 problemset4 Filter (less comfortable)にて、以下構文の左辺の理解に苦しんだ。

RGBTRIPLE (*image)[width] = calloc(height, width * sizeof(RGBTRIPLE));

この表記法は講義では説明されなかったので、ネットで検索していても混乱している人が多い印象を受けた。
同じように迷った人がいる場合の手助けとなれば嬉しい。

RGBTRIPLEとは

赤、緑、青の相対的な強さで構成される色を表す構造体

typedef uint8_t  BYTE; // 8ビットの符号なし整数型

typedef struct
{
    BYTE  rgbtBlue; //青色の強度
    BYTE  rgbtGreen; //緑色の強度
    BYTE  rgbtRed; //赤色の強度
} __attribute__((__packed__))
RGBTRIPLE;

右辺について

calloc(height, width * sizeof(RGBTRIPLE));

C言語のcalloc関数とは、ヒープメモリに対し、指定したバイト数のメモリを指定個数分確保し、そのメモリブロックを0にクリアする関数である。

■calloc関数の書式

calloc(確保するメモリの個数, 確保するメモリ1つあたりのバイト数)

■calloc関数の戻り値
成功時 : 確保したメモリblockのポインタ
失敗時:NULL

■calloc関数とmalloc関数の違い
これら2つの関数の本質的な違いは、確保したメモリ領域に格納される値

malloc関数で確保した領域の値は不定である。
一般に、malloc関数を呼び出す前にそのメモリ領域に格納されていた値がそのまま残る。

それに対してcalloc関数では、確保したメモリ領域の全ビットがゼロにクリアされる。

左辺について

結論を言うと、左辺は**「RGBTRIPLE型のwidth個の要素を持つ配列」へのポインターimageを宣言して、右辺で初期化**しているといえる。

簡単に言うと、imageは配列へのポインターだ。

RGBTRIPLE (*image)[width] = ...

これだけだと「ん?」と思われるかもしれない。
2日間探して「ベストアンサー」だと思った記事に出会えたので、引用しながら噛み砕いていく。

(引用)配列へのポインターの書き方

■参考記事
https://atmarkit.itmedia.co.jp/ait/articles/1208/08/news133.html

以下、引用です。

配列へのポインターはどのように書くのでしょうか。
例えば、次のように書いたら、変数pの型はどうなるでしょうか。

int ary[] = { 1, 2, 3 };
int (*p)[3] = &ary;

これは、「int型の3つの要素を持つ配列」へのポインターpを宣言して、aryで初期化しています。

とはいえ、慣れないうちは読みづらいと思いますので、1つずつ追いながら読んでみます。

まず右側です。
&ary は配列 ary のアドレスになります。
ary の型はint型の3つの要素を持つ配列ですので、int [3] となります。

このアドレスですから、**&ary の型はint (*)[3]**となります。

なぜ * を()で囲う必要があるかというと、int *[3] では「int *型の要素を持つ3つの配列」という別の意味になってしまうからです。

次に左側を見てみましょう。
まず注目すべきは、p という識別子です。
pの型を見るには、近いところにある記号から見ていきます。

pの最も近くにあるのは()内にある * です。
型の中に出てくる * はポインターを表しますから、p は何かを参照するポインターであることがわかります。

ここで () 内を外してみると、int [3] になります。

これはint型の要素を3つもつ配列です。
これらをまとめて読むと、**p は“「int型の要素を3つもつ配列」へのポインター”**であることがわかります。

つまり、型の一部を取り除くと、取り除いた部分の型が残るのです。

また、**左側から識別子pを取り払ってみると、int (*)[3]**になります。

これは、右側の型 int (*)[3]と同じです。
まずは識別子を取り除くだけでも、どんな型になるかわかりやすくなります。

このことを覚えておくと、見慣れない型に出会っても、落ち着いて対処できるはずです。

結論

先程結論は述べたが、改めて。
上記の引用の理由から、左辺は**「RGBTRIPLE型のwidth個の要素を持つ配列」へのポインターimageを宣言して、右辺で初期化**していると言えます!

RGBTRIPLE (*image)[width] = ...
1
1
1

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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?