C言語関係掲示板

過去ログ

No661 (*z)[j]を使ってなぜ各行の値が合計できるか

[戻る] [ホームページ]
No.7304

ポインタについて
投稿者---kan(2003/06/11 17:27:06)


このプログラムなんですが
関数のなかで(*z)[j]を使ってなぜ各行の値が合計されるんでしょうか?
(*z)[j]機能がどうしても理解できません。
すみませんが教えてください。

#include<stdio.h>

void sum(double (*z)[3], int n); /*関数プロトタイプ宣言*/

int main()
{
double goukei; /*変数宣言double型*/
double x[][3] = {{0.0, 0.0, 0.0}, /*配列宣言の中で初期化double型*/
{1.0, 2.0, 3.0},
{4.0, 5.0, 6.0},
{7.0, 8.0, 9.0}};
int nx = sizeof(x) / sizeof(x[0]);/*変数宣言の中で初期化*/

sum(x, nx); /*関数呼び出し*/

return 0; /*正常終了*/
}


/*関数名:sum*/
/*引数: n, */
/*返値: なし*/
/*機能:2次元配列の各行の値をプリントする*/
void sum(double (*z)[3], int n)
{
int i, j; /*変数宣言*/

for(i = 0; i < n; i++){
double sum = 0.0; /*変数宣言の中で初期化*/
for(j = 0; j < 3; j++){
sum += (*z)[j];
}
printf("%d行の合計 = %5.1f\n", i, sum);
z++;
}
}

No.7305

Re:ポインタについて
投稿者---こん!(2003/06/11 17:42:31)


見づらいのでまずリストをアップしなおしてと、
>#include<stdio.h>
>
>void sum(double (*z)[3], int n);       /*関数プロトタイプ宣言*/
>
>int main()
>{
>    double goukei;                    /*変数宣言double型*/
>    double x[][3] = {{0.0, 0.0, 0.0}, /*配列宣言の中で初期化double型*/
>                     {1.0, 2.0, 3.0},
>                     {4.0, 5.0, 6.0},
>                     {7.0, 8.0, 9.0}};
>    int nx = sizeof(x) / sizeof(x[0]);/*変数宣言の中で初期化*/
>
>    sum(x, nx);                       /*関数呼び出し*/
>
>    return 0;                         /*正常終了*/
>}
>
>
>/*関数名:sum*/
>/*引数: n, */
>/*返値: なし*/
>/*機能:2次元配列の各行の値をプリントする*/
>void sum(double (*z)[3], int n)
>{
>     int i, j;                  /*変数宣言*/
>
>     for(i = 0; i < n; i++){
>        double sum = 0.0;       /*変数宣言の中で初期化*/
>        for(j = 0; j < 3; j++){
>            sum += (*z)[j];
>        }
>        printf("%d行の合計 = %5.1f\n", i, sum);
>        z++;
>     }
>}
>関数のなかで(*z)[j]を使ってなぜ各行の値が合計されるんでしょうか?
>(*z)[j]機能がどうしても理解できません。

まず、どこまで理解されていますか?
1.函数への参照渡しが分からない?
2.for文の動作が分からない?
3.加算しているのが分からない?
4.配列のポインタ参照が分からない?

もしまるっきりならもう少し単純なリストをサンプルとして探すかこちら
少し基礎になれてからの方がよろしくないですか?

No.7309

Re:ポインタについて
投稿者---kan(2003/06/11 18:50:43)


ありがとうございました。
ページ見たら分かりました。

No.7311

Re:ポインタについて
投稿者---城後(2003/06/11 19:23:25)


>void sum(double (*z)[3], int n); /*関数プロトタイプ宣言*/
> sum(x, nx); /*関数呼び出し*/
>void sum(double (*z)[3], int n)

>1.函数への参照渡しが分からない?
>4.配列のポインタ参照が分からない?
>
について教えてください。

No.7312

Re:ポインタについて
投稿者---TDa(2003/06/11 19:32:57)



>>1.函数への参照渡しが分からない?
>>4.配列のポインタ参照が分からない?
>>
>について教えてください。

直接答えにならないけど元のコードだと意味がわからないのも無理ないと
思います。

p[i]は*(p + i)と同義です。

次のようにしてはどうでしょう。
/*関数名:sum*/
/*引数: n, */
/*返値: なし*/
/*機能:2次元配列の各行の値をプリントする*/
void sum(double (*z)[3], int n)
{
    int i, j; /*変数宣言*/
    
    for(i = 0; i < n; i++){
        double sum = 0.0; /*変数宣言の中で初期化*/
        for(j = 0; j < 3; j++){
            sum += z[i][j];
        }
        printf("%d行の合計 = %5.1f\n", i, sum);
    }
}


No.7315

Re:ポインタについて
投稿者---城後(2003/06/11 19:52:17)


>void sum(double (*z)[3], int n); /*関数プロトタイプ宣言*/
> sum(x, nx); /*関数呼び出し*/
>void sum(double (*z)[3], int n)

2次元配列の関数への渡し方ですが、
2次元配列の先頭アドレスを渡せれば受け渡しができると思うのですが、

void sum(double **,int); /*関数プロトタイプ宣言*/
main()
{
    double x[][3] = {{0.0, 0.0, 0.0},
                     {1.0, 2.0, 3.0},
                     {4.0, 5.0, 6.0},
                     {7.0, 8.0, 9.0}};
    int n;

    n = sizeof(x) / sizeof(x[0]);

    sum(x,n);/*関数呼び出し*/
}
void(z,n)
    double **z;
    int n;
{
    int i, j;
    
    for(i = 0; i < n; i++){
        double sum = 0.0;
        for(j = 0; j < 3; j++){
            sum += z[i][j];
        }
        printf("%d行の合計 = %5.1f\n", i, sum);
    }
}


「(*z)[3]」と受け側での宣言の意味はどういうことなのでしょうか。



No.7316

Re:ポインタについて
投稿者---YuO(2003/06/11 20:12:55)


>>void sum(double (*z)[3], int n); /*関数プロトタイプ宣言*/
>> sum(x, nx); /*関数呼び出し*/
>>void sum(double (*z)[3], int n)
>2次元配列の関数への渡し方ですが、
>2次元配列の先頭アドレスを渡せれば受け渡しができると思うのですが、

double (*pad)[3];

double **ppd;
の違いがわかっていますか?

double (*pad)[3];
というのは,
pad : pointer to array[3] of double
であり,「配列へのポインタ」になります。

それに対して,
double **ppd;
というのは,
ppd : pointer to pointer to double
であり,「ポインタへのポインタ」になります。

余談ですが,
double *apd[3];
は,
apd : array[3] of pointer to double
で,「ポインタの配列」になります。


double a[2][3];
があったとして,
式中で(単項&演算子及びsizeof演算子のオペランド以外として)aを使った場合,
aは
a : array[2] of array[3] of double
から
a : pointer to array[3] of double
に変換されます。
#pointer to pointer to doubleではない。

なので,aは引数として
・double (*)[3]
・double [][3]
をとる関数に渡すことはできますが,
・double **
をとる関数に渡すことはできません。

逆に,
double *b[3];
や,
double **c;
は,
・double **
をとる関数に渡すことができますが,
・double (*)[3]
・double [][3]
をとる関数に渡すことはできません。

また,bは
・double *(*)[3];
に,&bという形で渡すことができますが,
#↑pointer to array[3] of pointer to double
cは渡すことはできません。
#&c : pointer to pointer to pointer to double


ポインタと配列はきっちり区別しましょう。


No.7321

Re:ポインタについて
投稿者---城後(2003/06/11 22:43:36)


>double (*pad)[3];
>「配列へのポインタ」になります。

>double **ppd;
>「ポインタへのポインタ」になります。

>double *apd[3];
>「ポインタの配列」になります。

ポインタのポインタとかポインタの配列は、よくよく見かけたり、
使用したりしていますので分かりますが、「配列へのポインタ」は、
あまり見かけないというか、使用していないのでとっきにくいです。

「ポインタの配列」とは、アドレスが格納されている配列のことで
「配列へのポインタ」とは、配列の先頭アドレス。?
なんか、言葉では、ピントきません。

No.7325

Re:ポインタについて
投稿者---YuO(2003/06/12 00:58:23)


>ポインタのポインタとかポインタの配列は、よくよく見かけたり、
>使用したりしていますので分かりますが、「配列へのポインタ」は、
>あまり見かけないというか、使用していないのでとっきにくいです。
>「ポインタの配列」とは、アドレスが格納されている配列のことで
>「配列へのポインタ」とは、配列の先頭アドレス。?

ポインタと配列がごっちゃになっていませんか?
ポインタと配列は全く別の物であることをまず認識すべきです。

このあたりはFAQレベルの問題になります。
http://www.catnet.ne.jp/kouno/c_faq/c6.html
などを熟読してみてください。
他には,昔私が別の掲示板で書き込んだ書き込み
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200204/02040087.txt
なんかが役に立つかもしれません。


No.7361

Re:ポインタについて
投稿者---城後(2003/06/12 23:03:28)


ありがとうございます。
>このあたりはFAQレベルの問題になります。
>http://www.catnet.ne.jp/kouno/c_faq/c6.html
>などを熟読してみてください。
>他には,昔私が別の掲示板で書き込んだ書き込み
>http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200204/02040087.txt
>なんかが役に立つかもしれません。

char *a[6] char型ポインタが6つある配列
char (*a)[6] char型の6つの要素を持つ配列の先頭アドレスを格納するポインタ


No.7362

Re:ポインタについて
投稿者---TDa(2003/06/12 23:46:04)



>char *a[6] char型ポインタが6つある配列
>char (*a)[6] char型の6つの要素を持つ配列の先頭アドレスを格納するポインタ

「型」という言葉がC言語で一般と違う特別な意味があることはわかりますよね。
それからすると上記の表現はまずいでしょう。

char *a[6] charをさすポインタの配列(その要素数は6)
char (*a)[6] char配列(要素数6)を指すポインタ

ちなみに型は宣言から識別子を抜いたものになります。
よって
前者の型は char *[6]
後者の方は char (*)[6]
です。後者の()は省略できません。