2011-06-24 9 views
9

人。「char(* p)[5];」の意味は?

私はこれら三つの宣言の違いを把握しようとしている:

char p[5]; 
char *p[5]; 
char (*p)[5]; 

ような読書の宣言とスタッフのすべてのガイドが助けていないので、私は、いくつかのテストを行うことによって、これを見つけるためにしようとしています私はこれまで通り。私は、この小さなプログラムを書き、それが(私は第三宣言の使用の他の種類を試してみたと私は選択肢を使い果たしました)働いていない:

#include <stdio.h>                
#include <string.h>                
#include <stdlib.h>                

int main(void) {                 
     char p1[5];                
     char *p2[5];                
     char (*p3)[5];               

     strcpy(p1, "dead");              

     p2[0] = (char *) malloc(5 * sizeof(char));        
     strcpy(p2[0], "beef");             

     p3[0] = (char *) malloc(5 * sizeof(char));        
     strcpy(p3[0], "char");             

     printf("p1 = %s\np2[0] = %s\np3[0] = %s\n", p1, p2[0], p3[0]);   

     return 0;                
} 

第一及び第二の作品を無事、と私はしました彼らが何をしているのか理解し第3の宣言の意味とそれを使う正しい方法は何ですか?

ありがとうございました!第二は、charへアレイ 5のポインタがあるのに対し

+0

デコード宣言は、CとC++の中で私の最も好ましからざる部分です。 –

答えて

12

第三は、5つの文字の配列へのポインタあります。

"abc" "def" "ghi" "jkl" "mno" 
    ^ ^ ^ ^ ^
    |  |  |  |  | 
____________________________________ 
|0x9999|0x7777|0x3333|0x2222|0x6666| 
|___0__|___1__|___2__|___3__|___4__| 
        p 

これは、ポインタと配列の違いを理解することが不可欠である例1である:秒1は、そのように見えるのに対し

________   _____________________ 
|0x7777| -------> | H | e | l | l | o | 
|______|   |_0_|_1_|_2_|_3_|_4_| 
    p   ^
        | 
        0x7777 

はこのようにそれを想像してみてください。配列は、各要素のサイズにサイズを掛けたサイズのオブジェクトですが、ポインタは単にアドレスにすぎません。

sizeof(p)は、5 * the_size_of_a_pointerとなります。

第3の場合、sizeof(p)は、the_size_of_a_pointerとなります。これは、ターゲットマシンに応じて、通常4または8です。

+9

[時計回りのスパイラルルール](http://c-faq.com/decl/spiral.anderson.html)は、あなたが 'C 'をつぶしている時を知るのに便利です。 –

+0

p3を使って5文字を割り当てようとしましたが、それらにp3を指定しても動作しませんでした。あなたが言ったようにうまくいかない...いくつかのサンプルコードや何かを明確に投稿してもらえますか? – jpmelos

+0

3番目のケースでは、sizeof(p3)はあなたの言ったことを生み出すものではなく、マシンのポインタのサイズである8を生成します。 – jpmelos

4

これは、文字の配列へのポインタです。それはC FAQで説明されています。将来宣言を理解できない場合は、cdeclまたはcdecl(1)を使用してください。

+0

ありがとう、CのFAQへのあなたのリンクは私がこのトピックを大いに理解するのを助けました。 – jpmelos

3
char (*p3)[5]; 

は、実際には5 charの配列へのポインタを宣言します。つまり、5 charの配列を指すポインタを指す必要があります。それは何かの5つ、ちょうどポインタを割り当てません、それは5 charを指して何かを指す必要があります。

ので、正しい使用は、次のとおりです。

#include <stdio.h>                
#include <string.h>                
#include <stdlib.h>                

int main(void) {                 
     char p1[5];                
     char *p2[5];                
     char (*p3)[5];               

     strcpy(p1, "dead");              

     p2[0] = (char *) malloc(5 * sizeof(char));        
     strcpy(p2[0], "beef");             

     p3 = &p1;                

     printf("p1 = %s\np2[0] = %s\np3 = %s\n", p1, p2[0], *p3);    

     return 0;                
} 

あなたがそれにアクセスするためにP3を使用して、そのP1列の単一の位置にアクセスしたい場合は、例えば、(*p3)[2]を行う必要があります。それは3番目の位置にアクセスします。これは、最初にp3をp1(位置算術を実行する前に(*p3)逆参照)に変換してから、そのアドレスの3番目の位置にアクセスする必要があるからです(デリファレンスされたポインタによって示されます)。

+0

偉大な、私の答えをまとめた:-) –

4
char p[5];  // p is a 5-element array of char 
char *p[5];  // p is a 5-element array of pointer to char 
char (*p)[5]; // p is a pointer to a 5-element array of char 

C宣言構文は表現の種類ではなく、オブジェクトを中心に構築されています。考え方は、宣言の形式がコードに現れるような式の形式と一致するということです。

上記のケースでは、配列を扱っています。最初のケースでは、pcharの配列です。特定の文字の値にアクセスするには、我々だろう単に配列のインデックス:

val = p[i]; 

表現p[i]の種類は、このようにpの宣言はchar p[5]で、charです。

次の場合、pはcharへのポインタの配列です。値にアクセスするために、アレイに結果間接参照我々度:上記

val = *(p[i]); 

として解析されるように

val = *p[i]; 

[]等のPostfix演算子は、*よう単項演算子よりも高い優先順位を有しています式*p[i]の型がcharであるため、pの宣言はchar *p[5]です。最終場合

pそう配列ポインタ間接参照するために、我々が持っているchar値にアクセスし、その結果に添字するために、文字の配列へのポインタである:[]がが高いので

val = (*p)[i]; 

単一*よりも優先順位が高い場合は、とは対照的に、*pに明示的にグループ化するためにかっこを使用する必要があります。ここでも式(*p)[i]のタイプはcharなので、pの宣言はchar (*p)[5]です。

  1. あなたが明示的にN次元配列のアドレスを取っている::アレイへの

    ポインタは次のコンテキストに表示

    EDIT

    int x[10]; int (*px)[10] = &x; 
    注意しながら表現することをx&xは、同じ(配列の最初の要素のアドレス)を返します。タイプint *int (*)[10])。あなたは、動的アレイ型オブジェクトを割り当てている

  2. int x[10][20]; 
    foo(x); 
    ... 
    void foo(int (*px)[20]){...} 
    

int (*px)[10] = malloc(sizeof *px); 

  • アンN次元配列の発現は(N-1)-dimension配列へのポインタに "崩壊します"

  • +0

    +1。非常に良い説明!ありがとう、本当に宣言について考える方法を明確にしました! – jpmelos

    +0

    最初の文脈では、 'x'は' int * '型で'&x'は 'int(*)[10]'型です。実際に 'x'は' int [10] '型を持っていると思いますか? – jpmelos

    +1

    @jpmelos: 'sizeof'や'& 'のオペランドではないので、' x'は 'int *'に崩壊します。 –