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

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

ただいまの
回答率

88.78%

配列をアドレスとポインタを用いて実現するプログラムができません・・・

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,029

asakaaa

score 10

配列とアドレスやポインタを組み合わせたプログラムを作成中です

先日学校でアドレスやポインタを学び、その応用として配列をmain関数内のローカルのみで実現しようというプログラムを作成しています。
まだまだ作成途中なのですが、どうしてもわからなく先に進めていない状態です。

該当のソースコード

#include <stdio.h>
#include <stdlib.h>
#define true 1
#define false !true
#define STACKSIZE 10

#define bool int    //typedef int bool;

bool push(int data, int *stack, int *top);
int pop(int *stack, int *top);
int peek(int *stack, int *top);
bool is_full(int top);
bool is_empty(int top);
void print_stack(int *stack, int top);

int main(void)
{
    int stack[STACKSIZE];
    int top = 0;
    int *p_top;

    p_top = &top;

    push(1000, stack, p_top);
    printf("[0]=%d\n", stack[0]);
    printf("{1}=%d\n", stack[1]);
    printf("{2}=%d\n", stack[2]);
    push(2000, stack, p_top);
    printf("[0]=%d\n", stack[0]);
    printf("{1}=%d\n", stack[1]);
    printf("{2}=%d\n", stack[2]);
    push(3000, stack, p_top);
    printf("[0]=%d\n", stack[0]);
    printf("{1}=%d\n", stack[1]);
    printf("{2}=%d\n", stack[2]);
    print_stack(stack, top);

    pop(stack, p_top);
    printf("[0]=%d\n", stack[0]);
    printf("{1}=%d\n", stack[1]);
    printf("{2}=%d\n", stack[2]);
    print_stack(stack, top);
    pop(stack, p_top);
    printf("[0]=%d\n", stack[0]);
    printf("{1}=%d\n", stack[1]);
    printf("{2}=%d\n", stack[2]);
    print_stack(stack, top);
    pop(stack, p_top);
    printf("[0]=%d\n", stack[0]);
    printf("{1}=%d\n", stack[1]);
    printf("{2}=%d\n", stack[2]);
    print_stack(stack, top);

    return 0;
}


bool push(int data, int *stack, int *top) {

    if (is_full(*top) ){
        return false;
    }
    else {

        //*(stack + *top++) = data;
        //*(stack + *(top++)) = data;
        //*(stack + (i++)) = data;
        /* *(stack+(*top)) = data;
        *top = *(top + 1);*///動作停止
        *(stack + *top) = data;
        *top++;
        return true;

    }
}

int pop(int *stack, int *top) {
    if (is_empty(*top)) {
        fprintf(stderr, "Error:stack is empty.\n");
        return EXIT_FAILURE;
    }
    else {
        return *(stack + *top--);
    }
}

int peek(int *stack, int *top) {
    if (is_empty(*top)) {
        fprintf(stderr, "Error: stack is empty.\n");
        return EXIT_FAILURE;
    }
    else {
        return *(stack + *top - 1);
    }
}

bool is_full(int top) {
    return top == STACKSIZE;
}

bool is_empty(int top) {
    return top == 0;
}

void print_stack(int *stack, int top) {
    int i = top - 1;
    puts("");
    while (i >= 0) {
        printf("%d| %d\n", i, *(stack + i));
    }
}

質問したいこと

<push>停止と書いたところがあるのですが、なぜこのやり方だと動作が停止してしまうのか。
配列stackの0番目以降に(stack[1]やstack[2]など)にdataを入れるためには、*(stack+(top++))ではなぜだめで、stack[0]にしか格納されないのか。
<pop>pushと同様にどのような書き方をすれば値を取り出せるのか。
<print_stack>ここに関しては理解ができなかったので、自分が思うままにコードを書いてしまったので、間違っているところを指摘、修正案をお願いいたします。

その他

main関数をいじるのでは無く、自作関数を書き換えろという意図があります。
まだまだ途中な上、多くの質問をしてしまいとても大変だと思われますが、どうか返答のほどよろしくお願いいたします。厚かましいとは思いますが、しっかりここの分野も理解したいのでどうか詳しく解説をしていただけると助かります。どうかよろしくお願いいたします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

0

こんにちは。

これはなかなかハードな課題ですね。

まず、topはstack配列のインデックスで、0~STACKSIZEの値を取りますね?
そして、p_topはそのtop変数へのポインタですね。
push関数の仮引数のtopにはp_topが渡されますから*topはメインのtopと同じものになります。

topがたくさん出てきてややこしいです。push関数はbool push(int data, int *stack, int *p_top)と定義されていると考えると分かり易いので、以下、このように定義されていると読み替えて説明します。

さて、メインのtop変数へのポインタがp_topに入ってますから、*p_topはtopと同じものです。
そして、*top = *(top + 1);*p_top = *(p_top + 1);と読み替えることになります。
この時、p_top+1はどこを指すでしょうか? メイン関数のtopの次のint型位置を指しますね。そこには何があるか分かりません。未定義です。従って*(p_top+1)は不正アクセスとなります。

普通のCコンパイラはこの程度だと落ちない筈ですが、お使いのCコンパイラは不正アクセスをシビアに検出する教育用で、不正アクセスを検出して落ちているのではないか思います。

配列stackの0番目以降に(stack[1]やstack[2]など)にdataを入れるためには、*(stack+(top++))ではなぜだめで、stack[0]にしか格納されないのか。

ご提示されているコードに*(stack+(top++))は存在しないようです。()の付き方を良く確認して下さい。

ところで、push関数の中に幾つか*top++というコードがあるようです。上記読み替えをするとこれは*p_top++ですね。
これは習っていると思いますが、p_topの指すメモリの値を返してからp_topをインクリメントします。
最初にpushが呼ばれた時、p_topはメイン関数のtop変数へのポインタが入っています。そしてtopには0が入ってます。
ということは、*p_top++はメイン関数のtop変数の値0を返しp_topはメイン関数のtop変数の次のアドレスを指します。
しかし、コードを見る限りメイン関数のtop変数の値をインクリメントしたかったのではないでしょうか?
その場合は、(*p_top)++と書けば良いです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/09/30 19:16

    回答ありがとうございます。
    してくださった詳しい解説のおかげで無事プログラムを作成することができました。ありがとうございます。
    *(stack+*(top+1))ではいけない理由が分かりすっきりしました。同じようにpop関数でも最初は不正なアクセスをしていて、直すことができました。ありがとうございました。

    キャンセル

0

スタックのインデックスをカウントアップする箇所が、スタックのインデックスの変数のポインタをカウントアップするようになっています。

*(stack + *top) = data;
        *top++;
         ↓
        (*top)++;

また、動作停止のコメント箇所の処理もインデックスではなくポインタをカウントアップしており、無効なアドレス位置の値を参照する処理になっています。

*top = *(top + 1);*///動作停止

*top = (*top) + 1;

【補足】

異なる型の変数を同じ名前で宣言しているのでプログラムがわかりづらくなっています。

以下の関数の引数topについて、

bool push(int data, int *stack, int *top);
int pop(int *stack, int *top);
int peek(int *stack, int *top);

次のようにポインタ型であることを明示するか、

bool push(int data, int *stack, int *p_top);
int pop(int *stack, int *p_top);
int peek(int *stack, int *p_top);

次のように参照で宣言したほうがよいです。

bool push(int data, int *stack, int &top);
int pop(int *stack, int &top);
int peek(int *stack, int &top);

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/09/30 19:13

    回答ありがとうございます。
    補足までいただいてとてもわかりやすく、無事プログラムを完成させることができました!
    インクリメントする場所が異なり、無効なアクセスをしていたとのことで、そこについて理解することができました。ありがとうございました。

    キャンセル

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

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

関連した質問

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