こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

C言語 スタックを使ったプログラミングについて

C言語のスタックを使った逆ポーランド記法を使ったプログラミングについて質問です。
今回作ったプログラムは、キーボードで入力した逆ポーランド記法の数式を計算してその結果を出力するといったものです。
実際に以下のプログラムをcygwin上で動かしてみたのですが、コアダンプ表示が出てうまく動作しませんでした。
一応printfなどを使って確認してみたところ。main関数までは辿り着いているみたいなのですが、スタックを使うあたりから怪しくなっているみたいでよくわかりませんでした。。

どこが間違っているのかわかりやすく教えていただけると大変助かります。
長々とすみません、よろしくお願いいたします。


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

typedef struct cell_{
double vall;
struct cell_ *next;
}cell;

cell *sp = NULL;

int empty(void){
cell *retnode = sp -> next;

if(retnode == NULL){
return 1;
}

return 0;
}

void push(double x){
cell *newnode;

newnode = (cell*)malloc(sizeof(cell));

newnode -> vall = x;
newnode -> next = sp -> next;
sp -> next = newnode;
}

double pop(void){
int i;
double num;

i = empty();

if(i == 1) exit(1);

cell *shownode = sp -> next;

num = shownode -> vall;
sp -> next = shownode -> next;
free(shownode);
return num;
}

double print(void){
cell *printnode = sp -> next;

return printnode -> vall;
}

int main(){
double a, b;
double i;
char c;
char *ends;

while((c = getchar()) != EOF){
if(isdigit(c)){
a = c;

push(a);
}else{
switch(c){
case '+':
a = pop();
b = pop();
i = a + b;
push(i);
break;
case '-':
a = pop();
b = pop();
i = a - b;
push(i);
break;
case '*':
a = pop();
b = pop();
i = a * b;
push(i);
break;
case '/':
a = pop();
b = pop();
i = a / b;
push(i);
break;
case EOF || '\n':
a = print();
printf("%f\n", a);
default:
printf("Irregular character is found. Try again\n");
while((c = getchar()) != EOF && c != '\n'){}
break;
}
}
}
return 0;
}

投稿日時 - 2016-02-08 12:52:46

QNo.9124389

すぐに回答ほしいです

質問者が選んだベストアンサー

添削してみました。
spがスタックに最後に積んだ要素を指すようにしました。初期値はNULLです。
main関数も修正しました。コメントで示しました。

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

typedef struct cell_{
double vall;
struct cell_ *next;
}cell;

cell *sp = NULL;

int empty(void){
return sp==NULL;
}

void push(double x){
cell *newnode;

newnode = (cell*)malloc(sizeof(cell));

newnode->vall = x;
newnode->next = sp;
sp = newnode;
}

double pop(void){
int i;
double num;
cell *nextnode;

if (empty()) exit(1);

num = sp->vall;

nextnode = sp->next;
free(sp);

sp = nextnode;
return num;
}

double print(void){
return sp->vall;
}

int main(){
double a, b;
double i;
char c;
char *ends;

while ((c = getchar()) != EOF){
if (isspace(c)) continue;// 空白を無視しないと Irregular Character 扱いになる
if (isdigit(c)){
a = c-'0';
push(a);
}
else{
switch (c){
case '+':
a = pop();
b = pop();
i = a + b;
push(i);
break;
case '-':
a = pop();
b = pop();
i = b - a;// aとbが逆 先に積んだほうが後から出てくる
push(i);
break;
case '*':
a = pop();
b = pop();
i = a * b;
push(i);
break;
case '/':
a = pop();
b = pop();
i = b / a;// aとbが逆 後で積んだほう(先に取り出したほう)が除数になる
push(i);
break;

// c==EOFのときはwhileの判定ではじかれている

default:
printf("Irregular character is found. Try again\n");
while ((c = getchar()) != EOF && c != '\n'){}
break;
}

// 全部処理してから結果を表示する
a = print();
printf("%f\n", a);
}
}
return 0;
}

投稿日時 - 2016-02-22 16:26:27

お礼

ありがとうございました!
解決いたしました!

投稿日時 - 2016-07-02 16:29:01

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(3)

ANo.2

だとしたら、main関数のwhileの前に
cell *sp = &sp_real;
を書けばいいかと。

ちなみに
cell *sp = NULL;
は、念のための初期化として書くことは習慣的にあります。
Cの場合、変数は定義した直後の値は保障されていないので、どんな数値が入っているかわかりません。
入っていた値によっては偶然動作してしまい、何度も実行してようやく異常が発生するなんてこともあるのです。
NULLにしておけば、初期化をミスっていたら、コアダンプ吐くのですぐ分かるためです。

あと、よく見たらpush関数で実体分を切り出してたので、
cell sp_real;
だけでいいですね。

投稿日時 - 2016-02-08 14:02:56

お礼

ありがとうございました。
ご意見を参考に何度か試してみたところ正常に動作することができました。
とても助かりました^^

投稿日時 - 2016-02-08 14:49:33

ANo.1

変数「sp」の実体がどこにもないように見えます。
また、
cell *sp = NULL;
の表記もまちがってますね。ポインタにNULLを入れてしまっては、
sp -> next
などで異常を起こしてしまうでしょう。

書くとしたら、
cell sp_real[100];
cell *sp = &sp_real[0];
てなかんじになります。[100]は適当な数値なので、10でも300でもかまいません。

投稿日時 - 2016-02-08 13:06:41

補足

ご回答ありがとうございます。
自分も疑問を持ったのですが、
cell *sp = NULL;
というのは出題者から指定されたもので変更できないみたいなのです。

大変申し訳ないのですが、この場合にも解決法というのはございますか?

投稿日時 - 2016-02-08 13:15:42

あなたにオススメの質問