質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.84%

  • C

    3349questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C言語 2次元配列のポインタについt

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 199

north_redwings

score 20

コード
//多次元配列でのポインタ利用
#include <stdio.h>

#define row 3 //行
#define col 2 //列
// 56 60
//54 65
//12 98
 int main(int argc, char const *argv[]) {
//点数入力
int score[row][col] = {{56, 60}, {54, 65}, {12, 98}};
//ポインタ利用で要素表示
//行ごとに表示
printf("\n");
for (int i = 0; i < row; i++ ){
  printf("\n (score + %d)= %p\t\n\n",i, (score + i) );

//列ごとに表示
  for (int j = 0; j < col; j ++){
    printf("(*(score + %d) + %d)  = %p\t\n",i, j, (*(score + i) + j) );
    printf("*(*(score + %d) + %d)  = %d\t\n",i, j, *(*(score + i) + j) );
  }
  printf("\n");
}
printf("\n");
  return 0;
}


これを実行するとErrorなく次のようになりました。

コード
 (score + 0)= 0x7ffee0038a30

(*(score + 0) + 0)  = 0x7ffee0038a30
*(*(score + 0) + 0)  = 56
(*(score + 0) + 1)  = 0x7ffee0038a34
*(*(score + 0) + 1)  = 60


 (score + 1)= 0x7ffee0038a38

(*(score + 1) + 0)  = 0x7ffee0038a38
*(*(score + 1) + 0)  = 54
(*(score + 1) + 1)  = 0x7ffee0038a3c
*(*(score + 1) + 1)  = 65


 (score + 2)= 0x7ffee0038a40

(*(score + 2) + 0)  = 0x7ffee0038a40
*(*(score + 2) + 0)  = 12
(*(score + 2) + 1)  = 0x7ffee0038a44
*(*(score + 2) + 1)  = 98


これを見るに、score+0は0行目の一番最初の要素、すなわち0行0列のscore[0][0]のAdressを格納するポインタ変数のように思われます。
score+1についても同様でscore[1][0]のAdressを格納しているポインタ変数のように思われます。
そこで

コード
  printf("\n *(score + %d)= %d\t\n\n",i, *(score + i) );


を付け加えたところ、

コード
multi_array.c:17:42: warning: format specifies type 'int' but the argument has type 'int *' [-Wformat]
  printf("\n *(score + %d)= %d\t\n\n",i, *(score + i) );
                            ~~           ^~~~~~~~~~~~
1 warning generated.


のようにErrorが出ました。
そもそも、*(score+0)は何を示しているのでしょうか。score+0がscore[0][0]のAdressと一致したので*を先頭につければその要素を示していると考えたのですが...。

まだポインタ変数について理解が浅いので質問がよろしくないかもしれませんがご回答お待ちしています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • A.Ichi

    2017/12/30 11:37

    追加された行とエラー(ワーニング)の内容が異なっている様にみれますが。

    キャンセル

  • north_redwings

    2017/12/30 11:40

    今変更しました、すいません。

    キャンセル

回答 2

checkベストアンサー

0

まず、Warning と Error は違いますよ。ウォーニングは警告ですから期待通りに動作しない可能性はありますが、コンパイルは通り、実行オブジェクトも出来ています。動かしてみることはできます…と、ここまでは簡単です(笑)。

私の手元で、こんなコードをコンパイルしてみました(GCC 5.4.0, x86 64bit)。

    int score[3][2];

    for (int i = 0; i < 3; i++) {
        printf("  (score + %d) = %p\n", i,  (score + i)); // (A)
        printf(" *(score + %d) = %d\n", i, *(score + i)); // (B) Warning
        printf(" *(score + %d) = %p\n", i, *(score + i)); // (C)


実行した結果は、こうです。

  (score + 0) = 0x7ffc26f30ff0
 *(score + 0) = 653463536
 *(score + 0) = 0x7ffc26f30ff0
 // 途中省略
  (score + 1) = 0x7ffc26f30ff8
 *(score + 1) = 653463544
 *(score + 1) = 0x7ffc26f30ff8
 // 途中省略
  (score + 2) = 0x7ffc26f31000
 *(score + 2) = 653463552
 *(score + 2) = 0x7ffc26f31000


(A)の行と(C)の行の結果は全く同じです(ちなみに (B)の行で表示されている10進数値は、アドレスとして表示されている値の下位32bitを10進数で表示したもの)。

ソースコード上で(A)と(C)の違いは、「*(score + i)」と「(score + i)」、即ち「*」の有無だけ。「*」があっても無くても結果が同じという、一見訳分からない現象に見えます。
でも、score は二次元配列である事が重要。以下、私の解釈を書きます。

*(score+0)は何を示しているのでしょうか

(score + i) は score[i][0] のアドレスです。でも文法上 (score + i) は、まだ score[i][0] をポイントしていない、score[i][0] と score[i][1] をまとめたモノをポイントしている、そのようにコンパイラは扱っている、即ち「*」をつけて「*(score + i)」とアクセスし、ポインタを使って取りだした中身は要素数2の配列なのです。そう解釈すれば事情が見えてきます。

さて、Cコンパイラが配列を値として扱う場合、その値は何か?それは配列の先頭アドレスです。そう考えれば、*(score + 0) == (score + 0) で良いのではないでしょうか。

以上から、次のようなアクセスも可能だとわかりますが

    printf("%d\n", *(score + i)[0]);
    printf("%d\n", *(score + i)[1]);


ここは素直にこうすれば、ややこしいことに悩まずに済むと思うのですが、いかがですか。

    printf("%d\n", score[i][0]);
    printf("%d\n", score[i][1]);

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/30 17:38

    ありがとうございます。
    自分でも考えた結果なんとなくそう解釈するのが妥当かなと考えていたところに同様なご回答をいただいたので安心しました。
    そうですね、(笑)。
    ただ、今回は行列の動的メモリ確保のコードを理解するために一段階下げたコードで理解しようとしたものですからポインタを利用しました(笑)。
    解決しました、本当にありがとうございました。

    キャンセル

0

そもそも、そもそも、*(score+0)は何を示しているのでしょうか。は何を示しているのでしょうか。

scoreのアドレスの0番目のアドレスを示しています。*(score+1)はscre[]の二番目のアドレスを指しています。
*(score+2)は3番目なので &score[2][0]という事になります。
ですので下記の様にも書けます。

  int *scorep;
    scorep = (int *)score;
    for (i = 0; i < row*col; i++ ){
        printf("*(scorep + %d)  = %d\t\n",i, *(scorep + i));
    }

そのアドレスの前に’*’を付けると値となります。

  printf("\n *(score + %d)= %d\t\n\n",i, *(score + i) );
ワーニングはドレスを%dで表示させようとされたからです。

こちらの方が良いですね

 for (i = 0; i < row*col; i++ ){
    printf("*((int *)score + %d))  = %d\t\n",i, *((int *)score + i));
 }

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/30 16:56

    score+iは何なのでしょうか?
    score+1がscore[1][0]のアドレスと一致しているので混乱してきました。

    キャンセル

  • 2017/12/30 18:22

    score+iは、scoreのi番目です。ですのでscore+1は、score[0][1]と同じです。

    キャンセル

  • 2017/12/30 18:26

    > *(score+2)は3番目なので &score[1][0]

    は間違いでしょう。動かしてみましたか?>A.Ichiさん

    キャンセル

  • 2017/12/30 18:40

    ご指摘ありがとうございます。間違っておりました。&score[]のアドレスですね。score+1は、score[1]と同じですね。訂正しておきます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.84%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 受付中

    C言語 線形リスト

    初歩的な質問で非情に申し訳ないのですがどなたかお力添えをして頂けないでしょうか。 下記のコードの機能を新規作成、追加、ソートに変更したいのですが一向にうまくいかず、詰まっている状

  • 解決済

    PHP MySQL の連携

    PHPのWEBサイトで名前、年齢を登録ボタンを押すとMYSQLのテーブルに格納させる設定方法を教えて下さい。(レンタルサーバで各ソフトはインストールしています。)  PHPとMYS

  • 受付中

    プログラムを見やすく改良したい

    正常に動くプルグラムを見やすく改良したい。 具体的に教えていただければありがたいです。セグメンテーションフォルトでベスト7まで表示して停止します。173行あたりだと思うのですが、よ

  • 解決済

    行と列が違う配列の掛け算

    前提 書籍で勉強している学生です。 書籍の2周目をしています。 書籍の解答がないため問題のヒントや解説をしていただけると嬉しいです。 問題 4行3列の行列と3行4列の行列の積を

  • 解決済

    C言語において連続した文字列の作成及びhファイルからの文字列の表示方法

    前提・実現したいこと すごく初歩的なことで申し訳ないのですが、質問させてください。 aが256個続く文字列を作りたいのですが、 #include <stdio.h> #incl

  • 解決済

    fscanfがうまく動作しない

    前提・実現したいこと テキストファイルから情報を取り込みたい。 中身は Dbrenlhsij,11,162.2,55.9 Ijnpwthy,14,163.8,62.6 Csaztv

  • 解決済

    gcry_mpi_t 内の公開鍵をビット列で取り出したい

     gcry_mpi_t 内の公開鍵をビット列で取り出したい libgcrypt1.7.6 を使ってRSA暗号をいじってく中で, gcry_mpi_t型におさまっている公開鍵をビット

  • 解決済

    C言語: 文字型ポインタの配列

    #include <string.h> int main(void) { int a=0,b=0,c=0; int max = 100; int min

同じタグがついた質問を見る

  • C

    3349questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。