494

次の宣言の違いは何ですか。

int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);

より複雑な宣言を理解するための一般的なルールは何ですか?

4

13 に答える 13

462
int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers

3つ目は1つ目と同じです。

一般的なルールは、演算子の優先順位です。関数ポインタが登場するにつれて、さらに複雑になる可能性があります。

于 2009-05-13T18:37:30.057 に答える
270

K&Rの提案に従って、 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 )
于 2009-05-13T18:44:59.733 に答える
129

正式名称かどうかはわかりませんが、Right-LeftThingy(TM)と呼んでいます。

変数から始めて、右、左、右に移動します...など。

int* arr1[8];

arr1整数への8つのポインタの配列です。

int (*arr2)[8];

arr2は、8つの整数の配列へのポインター(括弧は左右をブロックします)です。

int *(arr3[8]);

arr3整数への8つのポインタの配列です。

これは、複雑な宣言に役立つはずです。

于 2009-05-13T18:41:48.613 に答える
27
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 
于 2011-03-02T08:03:18.593 に答える
16

最後の2つの答えは、Cの黄金律から差し引くこともできます。

宣言は使用に続きます。

int (*arr2)[8];

間接参照するとどうなりますarr2か?8つの整数の配列を取得します。

int *(arr3[8]);

から要素を取得するとどうなりますarr3か?整数へのポインタを取得します。

これは、関数へのポインターを処理するときにも役立ちます。sigjuiceの例をとると:

float *(*x)(void )

間接参照するとどうなりますxか?引数なしで呼び出すことができる関数を取得します。あなたがそれを呼ぶとどうなりますか?へのポインタを返しますfloat

ただし、演​​算子の優先順位は常に注意が必要です。ただし、宣言は使用に続くため、括弧の使用も実際には混乱を招く可能性があります。少なくとも、私には、直感的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 &lt; 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]

borderの値は変更されないため、コンパイラーはそれを最適化できることに注意してください。これは、最初に使用したいものとは異なります。const int (*border)[3]::変数が存在する限り値を変更しない、3つの整数の配列へのポインターとしてborderを宣言します。ただし、そのポインタはいつでも他のそのような配列を指すことができます。代わりに、引数にそのような動作が必要です(この関数はこれらの整数を変更しないため)。宣言は使用に続きます。

(ps:このサンプルを自由に改善してください!)

于 2010-03-30T09:40:55.997 に答える
5
typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];
于 2010-08-14T17:51:34.160 に答える
3

経験則として、右の単項演算子([]()など)は左の演算子よりも優先されます。したがって、int *(*ptr)()[];intへのポインターの配列を返す関数を指すポインターになります(括弧から抜けたら、できるだけ早く適切な演算子を取得してください)

于 2014-09-19T13:34:06.017 に答える
2

簡単なルールが使えると思います。

example int * (*ptr)()[];
start from ptr 

"ptrは"右に行く..その")"へのポインタです"("出て右に行く "()"なので"引数をとらない関数に"左に行く"そしてポインタを返す"行く右「配列へ」「整数の左へ」

于 2012-07-09T15:04:34.017 に答える
2

これが私がそれをどのように解釈するかです:

int *something[n];

優先順位に関する注意:配列添え字演算子([])は、間接参照演算子()よりも優先順位が高くなります*

したがって、ここでは[]beforeを適用*し、ステートメントを次と同等にします。

int *(something[i]);

宣言がどのように意味をなすかについての注意:int nummeansnumは、、intまたはint *ptrmeans int (*ptr)、(の値ptr)は、intptrのポインタになりintます。

これは、((何かのi番目のインデックスの値)の値)は整数であると読み取ることができます。したがって、(何かのi番目のインデックスの値)は(整数ポインター)であり、何かを整数ポインターの配列にします。

2つ目は、

int (*something)[n];

このステートメントを理解するには、次の事実に精通している必要があります。

配列のポインタ表現に関する注意:somethingElse[i]と同等です*(somethingElse + i)

したがって、に置き換えるsomethingElseと、宣言ごとの整数である、が(*something)得られます。*(*something + i)したがって、配列を指定すると、 (配列へのポインタ)と(*something)同等のものになります。

于 2015-10-11T18:52:17.780 に答える
2

Cで複雑な型を読み取る方法を説明する興味深いWebサイトは次のとおりです。http: //www.unixwiz.net/techtips/reading-cdecl.html

于 2018-08-22T19:51:14.243 に答える
0

2番目の宣言は多くの人を混乱させていると思います。これを理解する簡単な方法があります。

整数の配列、すなわちint B[8]

Bを指す変数Aも用意しましょう。ここで、Aの値はB、つまり(*A) == Bです。したがって、Aは整数の配列を指します。あなたの質問では、arrはAに似ています。

同様に、ではint* (*C) [8]、Cは整数へのポインタの配列へのポインタです。

于 2016-10-12T11:46:19.940 に答える
0
int *arr1[5]

この宣言でarr1は、は整数への5つのポインターの配列です。理由:角かっこは*(逆参照演算子)よりも優先されます。このタイプでは、行数は固定されていますが(ここでは5)、列数は可変です。

int (*arr2)[5]

この宣言でarr2は、は5つの要素の整数配列へのポインタです。理由:ここでは、()角かっこは[]よりも優先されます。このタイプでは、行数は可変ですが、列数は固定されています(ここでは5)。

于 2020-05-31T03:17:14.210 に答える
-9

整数へのポインタでは、ポインタがインクリメントされると、次の整数になります。

ポインタの配列でポインタがインクリメントされると、次の配列にジャンプします

于 2013-03-31T14:41:58.040 に答える