ポインタ曖昧性除去のアレイ/アレイへのCポインタ
-
21-08-2019 - |
質問
次の宣言の違いは何ですかます:
int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);
より複雑な宣言を理解するための一般的なルールは何ですか?
解決
int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers
3つ目は最初と同じである。
一般的なルールは、演算子の優先順位です。関数ポインタは、画像に入って来るように、それはでもはるかに複雑得ることができます。
他のヒント
、 CDECL のプログラムを使用します。
$ cdecl
Type `help' or `?' for help
cdecl> explain int* arr1[8];
declare arr1 as array 8 of pointer to int
cdecl> explain int (*arr2)[8]
declare arr2 as pointer to array 8 of int
cdecl> explain int *(arr3[8])
declare arr3 as array 8 of pointer to int
cdecl>
これは、あまりにも他の方法で動作します。
cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )
それは正式名称を持っている場合、私は知らないが、私は右から左Thingyの(TM)を呼び出します。
右、左、右...というように行く、変数で起動します。
int* arr1[8];
のARR1は整数に8つのポインタの配列です。の
int (*arr2)[8];
ARR2 8つの整数の配列へのポインタ(括弧は左右ブロック)である。
int *(arr3[8]);
のARR3は整数に8つのポインタの配列です。の
この複雑な宣言であなたを助ける必要があります。
int *a[4]; // Array of 4 pointers to int
int (*a)[4]; //a is a pointer to an integer array of size 4
int (*a[8])[5]; //a is an array of pointers to integer array of size 5
最後の二つのための答えはまたCでの黄金律から控除することができます:
宣言を使用し、以下ます。
int (*arr2)[8];
はどうなりますか?あなたは8つの整数の配列を取得します。
int *(arr3[8]);
はどうなりますか?あなたは、整数へのポインタを取得します。
関数へのポインタを扱うときにこのも役立ちます。 sigjuiceの例を取るために:
float *(*x)(void )
何をするときには、xデリファレンスどうなりますか?あなたは引数なしで呼び出すことができる機能を取得します。あなたはそれを呼び出すときはどうなりますか?これは、フロートへのポインタを返します。
演算子の優先順位は、しかし、常に注意が必要です。宣言は使用を以下のためしかし、括弧を使用すると、実際にも混乱することができます。少なくとも、私には、直感的にARR2はint型へのポインタの配列8のように見えますが、それは実際に周りに他の方法です。ただ、いくつかのに慣れが必要。あなたは私に言わせれば、常に、これらの宣言にコメントを追加するのに十分な理由:)
の編集:例の
静的マトリックスを有し、かつ、行ポインタが範囲外にあるかどうかを確認するためにポインタ演算を使用する関数:ところで、私は次のような状況に出くわし。例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_ELEM(ar) (sizeof(ar) / sizeof((ar)[0]))
int *
put_off(const int newrow[2])
{
static int mymatrix[3][2];
static int (*rowp)[2] = mymatrix;
int (* const border)[] = mymatrix + NUM_ELEM(mymatrix);
memcpy(rowp, newrow, sizeof(*rowp));
rowp += 1;
if (rowp == border) {
rowp = mymatrix;
}
return *rowp;
}
int
main(int argc, char *argv[])
{
int i = 0;
int row[2] = {0, 1};
int *rout;
for (i = 0; i < 6; i++) {
row[0] = i;
row[1] += i;
rout = put_off(row);
printf("%d (%p): [%d, %d]\n", i, (void *) rout, rout[0], rout[1]);
}
return 0;
}
出力:
0 (0x804a02c): [0, 0] 1 (0x804a034): [0, 0] 2 (0x804a024): [0, 1] 3 (0x804a02c): [1, 2] 4 (0x804a034): [2, 4] 5 (0x804a024): [3, 7]
ボーダーの値が変化しないことに注意してくださいので、コンパイラはそれを離れて最適化することができます。これは、あなたが最初に使用したいかもしれないものとは異なります。const int (*border)[3]
:限り変数が存在すると値を変更しないであろう3つの整数の配列へのポインタとして国境を宣言しています。しかし、そのポインタは、いつでも任意の他のそのようなアレイを指摘することができます。 (この関数は、これらの整数のいずれかを変更しないので)私たちは、代わりに、引数のための行動のようなものをしたいです。宣言は、使用を次のます。
(p.s:このサンプルを改善して自由に感じる!)
typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];
は、経験則として、右単項演算子は([]
、()
、などのように)左のものよりも優先してください。だから、int *(*ptr)()[];
は(とすぐに括弧から抜け出すとすることができますように、右の演算子を取得)intへのポインタの配列を返す関数を指すポインタになります。
私たちは、単純なルールを使用することができると思う..
example int * (*ptr)()[];
start from ptr
「ptr
はへのポインタです」
「(」「)」今、そのAを左に行く右..its向かいます
右に行く出てくる「()」そう
「ポインタを返すと」左に行く「引数を取らない関数に」に」右に行きます
配列の整数の「左に行く」「
ここで私はそれを解釈する方法は次のとおりです。
int *something[n];
の優先順位に関して:配列添字演算子(「[]」)は、より高い優先度を有します 間接参照演算子( '*')。
だから、ここではと同等の文を作り、「[]」「*」の前に適用されます
int *(something[i]);
宣言は、理にかなっている方法の注:
int num
手段(NUM)(INT)、int *ptr
又はint (*ptr)
手段、(PTRにおける値)であります intへのポインタptrを行う(INT)。
(何かのi番目のインデックスで(値)の値)の整数であり、これを読み出すことができます。だから、(何かのi番目のインデックスの値)が何か整数ポインタのアレイを作る(整数ポインタ)である。
第一
int (*something)[n];
この文のうち、意味を理解するには、この事実に精通している必要があり
アレイのポインタ表現に注:somethingElse [I] *(somethingElse + I)に相当する
だから、(*何か)でsomethingElseを交換、我々は(*何か+ I)*宣言どおりの整数である、得ます。だから、(*何か)私たち(配列へのポインタ)と同等のものを作るの配列を、与えられます。
ここではCで複雑なタイプを読み取る方法を説明し、興味深いサイトです。 http://www.unixwiz.net/techtips/reading-cdecl.html
私は2番目の宣言は、多くの混乱だと思います。ここではそれを理解する簡単な方法です。
整数のアレイ、即ちint B[8]
を有することができます。
のも今B.を指す変数Aてみましょう、Aの値がB、すなわち(*A) == B
あります。したがって、整数の配列を指します。あなたの質問では、ARRはに似ています。
同様に、int* (*C) [8]
で、Cは整数へのポインタの配列へのポインタである。
整数へのポインタはポインタがインクリメントされている場合、それは次の整数になります。
ポインタのアレイ内のポインタは、それが次の配列にジャンプインクリメントされている場合