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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

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

Q&A

解決済

2回答

1606閲覧

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

asakaaa

総合スコア10

C

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

0グッド

0クリップ

投稿2016/09/29 14:14

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

C

1#include <stdio.h> 2#include <stdlib.h> 3#define true 1 4#define false !true 5#define STACKSIZE 10 6 7#define bool int //typedef int bool; 8 9bool push(int data, int *stack, int *top); 10int pop(int *stack, int *top); 11int peek(int *stack, int *top); 12bool is_full(int top); 13bool is_empty(int top); 14void print_stack(int *stack, int top); 15 16int main(void) 17{ 18 int stack[STACKSIZE]; 19 int top = 0; 20 int *p_top; 21 22 p_top = &top; 23 24 push(1000, stack, p_top); 25 printf("[0]=%d\n", stack[0]); 26 printf("{1}=%d\n", stack[1]); 27 printf("{2}=%d\n", stack[2]); 28 push(2000, stack, p_top); 29 printf("[0]=%d\n", stack[0]); 30 printf("{1}=%d\n", stack[1]); 31 printf("{2}=%d\n", stack[2]); 32 push(3000, stack, p_top); 33 printf("[0]=%d\n", stack[0]); 34 printf("{1}=%d\n", stack[1]); 35 printf("{2}=%d\n", stack[2]); 36 print_stack(stack, top); 37 38 pop(stack, p_top); 39 printf("[0]=%d\n", stack[0]); 40 printf("{1}=%d\n", stack[1]); 41 printf("{2}=%d\n", stack[2]); 42 print_stack(stack, top); 43 pop(stack, p_top); 44 printf("[0]=%d\n", stack[0]); 45 printf("{1}=%d\n", stack[1]); 46 printf("{2}=%d\n", stack[2]); 47 print_stack(stack, top); 48 pop(stack, p_top); 49 printf("[0]=%d\n", stack[0]); 50 printf("{1}=%d\n", stack[1]); 51 printf("{2}=%d\n", stack[2]); 52 print_stack(stack, top); 53 54 return 0; 55} 56 57 58bool push(int data, int *stack, int *top) { 59 60 if (is_full(*top) ){ 61 return false; 62 } 63 else { 64 65 //*(stack + *top++) = data; 66 //*(stack + *(top++)) = data; 67 //*(stack + (i++)) = data; 68 /* *(stack+(*top)) = data; 69 *top = *(top + 1);*///動作停止 70 *(stack + *top) = data; 71 *top++; 72 return true; 73 74 } 75} 76 77int pop(int *stack, int *top) { 78 if (is_empty(*top)) { 79 fprintf(stderr, "Error:stack is empty.\n"); 80 return EXIT_FAILURE; 81 } 82 else { 83 return *(stack + *top--); 84 } 85} 86 87int peek(int *stack, int *top) { 88 if (is_empty(*top)) { 89 fprintf(stderr, "Error: stack is empty.\n"); 90 return EXIT_FAILURE; 91 } 92 else { 93 return *(stack + *top - 1); 94 } 95} 96 97bool is_full(int top) { 98 return top == STACKSIZE; 99} 100 101bool is_empty(int top) { 102 return top == 0; 103} 104 105void print_stack(int *stack, int top) { 106 int i = top - 1; 107 puts(""); 108 while (i >= 0) { 109 printf("%d| %d\n", i, *(stack + i)); 110 } 111}

###質問したいこと
<push>停止と書いたところがあるのですが、なぜこのやり方だと動作が停止してしまうのか。
配列stackの0番目以降に(stack[1]やstack[2]など)にdataを入れるためには、*(stack+(top++))ではなぜだめで、stack[0]にしか格納されないのか。
<pop>pushと同様にどのような書き方をすれば値を取り出せるのか。
<print_stack>ここに関しては理解ができなかったので、自分が思うままにコードを書いてしまったので、間違っているところを指摘、修正案をお願いいたします。
###その他
main関数をいじるのでは無く、自作関数を書き換えろという意図があります。
まだまだ途中な上、多くの質問をしてしまいとても大変だと思われますが、どうか返答のほどよろしくお願いいたします。厚かましいとは思いますが、しっかりここの分野も理解したいのでどうか詳しく解説をしていただけると助かります。どうかよろしくお願いいたします。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

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/29 14:59

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

asakaaa

2016/09/30 10:16

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

0

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

c

1 *(stack + *top) = data; 2 *top++; 34 (*top)++;

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

c

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

【補足】

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

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

c

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

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

c

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

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

c

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

投稿2016/09/29 14:31

編集2016/09/29 14:44
tkmtmkt

総合スコア1800

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

asakaaa

2016/09/30 10:13

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問