二次配列用のポインタ

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Cr

二次配列用のポインタ

#1

投稿記事 by Cr » 8年前

Crです。
プログラムの質問というより仕組みの質問です。

コード:

int **dis;
と宣言した場合,
disはポインタ型へのポインタですよね。
では
**dis,*dis,dis[1],dis[2][3]
は何を示すのでしょう?

box
記事: 1746
登録日時: 9年前

Re: 二次配列用のポインタ

#2

投稿記事 by box » 8年前

Cr さんが書きました: **dis,*dis,dis[1],dis[2][3]
は何を示すのでしょう?
適切にmalloc()できていると仮定して、
**dis:dis[0][0](型はint)
*dis:dis[0](型はint *)
dis[1]:型はint *
dis[2][3]:型はint

なお、
int **dis;
は定義です。宣言ではありません。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

アバター
へろりくしょん
記事: 92
登録日時: 9年前
住所: 福岡

Re: 二次配列用のポインタ

#3

投稿記事 by へろりくしょん » 8年前

box さんが書きました:なお、
int **dis;
は定義です。宣言ではありません。
重隅かもしれませんが、ちょっと強く言い切ってしまってますので。

基本的に定義というのは、記憶域の確保を伴う宣言の事です。
ですので、通常、一般に変数は宣言と定義が同時に行われます。

変数に限って言えば、関数の仮引数・構造体のメンバ変数・extern register 等の記憶クラス指定子といった、定義を伴わない宣言のみ
というのはありますが、原則としてその逆はあり得ません。

ですので、ここで宣言ではありません。 と言い切ってしまうのは些か語弊があると思うのですが、どうでしょう。

box
記事: 1746
登録日時: 9年前

Re: 二次配列用のポインタ

#4

投稿記事 by box » 8年前

定義はみな宣言であるということがわかりました。
よって、「定義であって宣言ではない」という前言を撤回いたします。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

ISLe
記事: 2645
登録日時: 9年前
連絡を取る:

Re: 二次配列用のポインタ

#5

投稿記事 by ISLe » 8年前

質問のコードはC++が指定されているので余談になってしまいますが、Cの外部変数だとこれまた純粋な定義と違うんですよね。

box
記事: 1746
登録日時: 9年前

Re: 二次配列用のポインタ

#6

投稿記事 by box » 8年前

ISLe さんが書きました:質問のコードはC++が指定されているので余談になってしまいますが、Cの外部変数だとこれまた純粋な定義と違うんですよね。
CODEタグの後ろに何も付けないと自動的にC++となってしまうので、
質問者さんが明示的にC++を指定されたかどうかは(今のところ)不明ですね。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

YuO
記事: 941
登録日時: 9年前
住所: 東京都世田谷区

Re: 二次配列用のポインタ

#7

投稿記事 by YuO » 8年前

Cr さんが書きました:**dis,*dis,dis[1],dis[2][3]
は何を示すのでしょう?
  • **dis
    disが指し示すオブジェクト(int **型)が参照するオブジェクト(int *型)が参照するオブジェクト(int型)

    コード:

       dis
    +-------+        +-------+        +-------+
    | int** | -----> | int * | -----> =  int  =
    +-------+        +-------+        +-------+
    
  • *dis
    disが指し示すオブジェクト(int **型)が参照するオブジェクト(int *型)

    コード:

       dis
    +-------+        +-------+
    | int** | -----> = int * =
    +-------+        +-------+
    
  • dis[1]
    disが指し示すオブジェクト(int **型)が参照するオブジェクト(int *型)を先頭要素とする配列(int *[]型)の,2番目(先頭を1番目とする)のオブジェクト(int *型)

    コード:

       dis
    +-------+        +-int*[]+
    | int** | -----> | int * |
    +-------+        +-------+
                     = int * =
                     +-------+
    
  • dis[2][3]
    disが指し示すオブジェクト(int **型)が参照するオブジェクト(int *型)を先頭要素とする配列(int *[]型)の,3番目(先頭を1番目とする)のオブジェクト(int *型)が参照するオブジェクト(int型)を先頭要素とする配列(int []型)の,4番目(先頭を1番目とする)のオブジェクト(int型)

    コード:

       dis
    +-------+        +-int*[]+
    | int** | -----> | int * |
    +-------+        +-------+
                     | int * |
                     +-------+        +-int[]-+
                     | int * | -----> |  int  |
                     +-------+        +-------+
                                      |  int  |
                                      +-------+
                                      |  int  |
                                      +-------+
                                      =  int  =
                                      +-------+
    
枠一つがオブジェクト,またはサブオブジェクトです。
また,----->は「参照する」を意味し,=が左右にあるオブジェクトまたはサブオブジェクトが式の表すオブジェクトです。
# 整形のためにcodeタグを使っています。

ところで,タイトルを見て気になったのですが,int **は二次元配列で使えるポインタではありません。
配列の配列へのポインタの場合,int (*)[]となります。
# []内には定数を入れて下さい。


余談ですが……。
宣言と定義について,規格に言葉の定義が記述されています。
  • Cにおいて,定義は一部の宣言のこと言います。 ISO/IEC 9899:1999 / 6.Language - 6.7 Declarations / Paragraph 5
    A definition of an identifier is a declaration for that identifier that
    (以下列挙は省略)
  • C++において,宣言は一部を除いて定義でもあります。 ISO/IEC 14882:2003 / 3 Basic Concepts / 3.1 Declarations and definitions / Paragraph 2
    A declaration is a definition unless it declares ...
    (列挙部省略)
Cでは宣言のうちで定義であるものが列挙されていますが,C++では宣言のうちで定義でないものが列挙されています。
ちなみに,省略した列挙には,CでもC++でもtypedefが挙がっています。
つまり,Cではtypedefは定義になりますが,C++では定義になりません。

// 注
C++11が発行されているのでC++03は旧規格ですが,とりあえず旧規格から拾いました。
n3242を見る限り,対象の段落の書き方に変化はありませんでしたが。

閉鎖

“C言語何でも質問掲示板” へ戻る