3

C/C++ クラスでポインターを調べ始めたところですが、ポインターがどのように機能するかについて少し混乱しています。この問題が表示されます:

多次元配列 char ma[5][30] を宣言したとします。要素「ma[0][0]」のアドレスは?アドレスをポインター変数に割り当てるには、2 つの異なる方法を使用します。(ma[0][0] に具体的なアドレスを指定しないでください。これは、割り当てられたメモリに基づいて、プログラムが実行されるたびに異なります。)

宿題の問題に対する「答え」を提供することに、このコミュニティがどれほど眉をひそめているかを私は知っています。答えは必要ありませんが、ポインターを使用して配列内の要素のアドレスを取得する方法を誰かが説明してくれることを願っています。

4

6 に答える 6

4

2つの方法は

char* p1 = (char*)ma;
char* p2 = &ma[0][0];

最初のものは、「ma」がすでに配列が格納されているメモリ内の場所へのポインターであるため機能します。

2 つ目は、アドレス演算子 (&) を使用して機能します。&ma[0][0] は「ma のアドレス、要素 0,0」に変換されます

于 2013-09-17T20:38:17.703 に答える
3

ポインタ p があるとしましょう。& 演算子でメモリを取得します。

p = &ma[row][col];

または、配列の変数名からポインターを取得できます。

p = ma;

次に、ポインター演算を使用してこれにアクセスします。

p = p + (row * num_per_col + col);
于 2013-09-17T20:35:46.887 に答える
1

実際には、インデックス (0,0) の要素へのポインターを取得する簡単な方法が 3 つあります。そのうちの 2 つはキャストフリーです。

char const* const p1 = (char const*)ma;
char const* const p2 = ma[0];
char const* const p3 = &ma[0][0];

これらが機能する理由は、 のメモリ レイアウトによるものですma。マトリックスは、一連の 150 の連続した文字 (つまり、150 バイト) です。C では、必要に応じて、配列をそれぞれの最初の要素へのポインターに減衰させることができます。実際、このメカニズムは非常に乱雑であり、配列とポインターの間に違いはないと信じ込まされることがあります。

2 行目から始めましょう ( p2)。ma[0]は型の 30 個の要素からなる 1 次元配列でありchar、C では、その式をポインターに分解して、30 文字の配列の最初の要素を指すようにすることができます。3 行目 ( p3) では、 element のアドレスを明示的に取得しています[0][0]。これを使用するために、メモリがどのように配置されているかを理解する必要さえありません。

最初の行 ( p1) は、キャストが含まれているため、少し厄介です。の最初の要素は char ではなく配列であるため、通常はmachar 配列へのポインターに減衰する可能性がありますma。しかし、その配列の最初の要素が探している文字であることはわかっているので、最初の要素の前にパディングがない配列に依存し、最初の配列全体のアドレスを最初の文字のアドレスとして再解釈します。

于 2013-09-17T21:07:01.087 に答える
0

sizeofまたは 単項演算子のオペランドである場合、または宣言で別の配列を初期化するために使用される文字列リテラルである場合を除いて&、型 "N 要素配列 " の式は次の式Tに変換 ("decay") されます。 「ポインタT」と入力すると、式の値が配列の最初の要素のアドレスになります。

宣言を仮定して

char ma[5][30];

その場合、次のすべてが真です。

  1. 式のma型は「30 要素配列の 5 要素配列char」です。がまたは unarymaのオペランドでない限り、 「またはの 30 要素配列へのポインタ」型の式に変換され、その値は配列の最初の要素のアドレスまたは になります。sizeof&charchar (*)[30]&ma[0]

  2. 式のma[i]型は「30 要素配列char」です。がまたは unaryma[i]のオペランドでない限り、型「ポインタ」またはの式に変換され、その値は配列の最初の要素のアドレスまたは になります。 sizeof&charchar *&ma[i][0]

  3. 式のma[i][j]型はcharです。

  4. 式の型は、「 、または&maの 30 要素配列の 5 要素配列へのポインタ」です。 charchar (*)[5][30]

  5. 式の&ma[i]型はchar (*)[30]です。

  6. 式の&ma[i][j]型はchar *です。

  7. 式、、、、およびのはすべて同じです。配列のアドレスは、配列の最初の要素のアドレスと同じです。 ma&mama[0]&ma[0]&ma[0][0]

タイプchar (*)[30]とは、 、または相互に互換性char (*)[5][30]ないことに注意してください。これらの型の値を type の変数に割り当てたい場合は、 などの明示的なキャストを使用する必要があります。 char *char *char *p = (char *) ma;

編集

タイプは重要です。ポインター演算は、ポイント先の型に基づいているため、式 likeは、ポイント先ptr+1の型に基づいて異なる結果を返します。ptr例えば:

#include <stdio.h>

int main( void )
{
  char ma[5][30] = {{0}};

  char (*p0)[5][30] = &ma;
  char (*p1)[30]    = &ma[0];
  char *p2          = &ma[0][0];

  printf("%5s%-15s%-15s\n"," ","ptr","ptr+1");
  printf("%5s%-15s%-15s\n"," ","-----","-----");
  printf("%-5s%-15p%-15p\n","p0", (void *) p0, (void *) (p0+1));
  printf("%-5s%-15p%-15p\n","p1", (void *) p1, (void *) (p1+1));
  printf("%-5s%-15p%-15p\n","p2", (void *) p2, (void *) (p2+1));

  return 0;
}

異なるタイプの 3 つのポインターを作成します。p0は 型char (*)[5][30]で の結果を受け取り、&map1char (*)[30]で の結果を受け取り、&ma[0]p2char *で の結果を受け取ります&ma[0][0]。次に、各ポインターの値に 1 を加えた値よりも、各ポインターの値を出力します。結果は次のとおりです。

     ptr ptr+1
     ----- -----
p0 0x7fff36670d30 0x7fff36670dc6
p1 0x7fff36670d30 0x7fff36670d4e
p2 0x7fff36670d30 0x7fff36670d31

各ポインターは同じ値で始まりますが、ポインターに 1 を追加すると、型に基づいて異なる結果が得られます。 p0の 5x30 要素配列を指すcharためp0 + 1、 の次の 5x30 要素配列の先頭を指しcharます。 p1の 30 要素配列を指しているcharため、 ( )p1 + 1の次の 30 要素配列を指しています。最後に、単一の を指すため、次の文字 ( ) を指します。 charma[1]p2charp2 + 1ma[0][1]

于 2013-09-17T22:18:58.427 に答える
0

あなたはそれを得ることができます

&ma[0][0];

として定義された多次元配列がある場合int [][]、は (参照回答)x = y[a][b]と同等です。x = *((int *)y + a * NUMBER_OF_COLUMNS + b);

于 2013-09-17T20:37:18.323 に答える
-2

または、配列から (x,y) の値を取得しますaddr = &ma[0][0] + sizeof(<type of array>)*columns * x + sizeof(<type of array>) * y

于 2013-09-17T20:39:20.040 に答える