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

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

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

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

セグメンテーション違反

セグメンテーション違反とは、ソフトウェア実行時に発生するエラーのひとつであり、許可されていないメモリにアクセスしたときに起きます。しばしば、ポインタの不適切な使用、またはバッファオーバーフローによって起こります。

Q&A

解決済

3回答

1024閲覧

c言語 セグメンテーション違反の修正

tamintya

総合スコア34

C

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

セグメンテーション違反

セグメンテーション違反とは、ソフトウェア実行時に発生するエラーのひとつであり、許可されていないメモリにアクセスしたときに起きます。しばしば、ポインタの不適切な使用、またはバッファオーバーフローによって起こります。

0グッド

0クリップ

投稿2021/05/21 17:19

###セグメンテーション違反を直したいです

c言語でスタックを作ったのですがpopを実行時にセグメンテーション違反が発生してしまいます。
popの関数ではスタックから値を一つ消したいのですが、スタックの中身がひとつもないときにpopを実行するとプログラムが終了するようにしたいです。
またpopによって中身が0個になった場合はそのことを表示したいです。
よろしくおねがいします。

該当のソースコード

c言語

1#include<stdio.h> 2#include<stdlib.h> 3#include<string.h> 4 5void push( char ); 6char pop(); 7void free_stack(); 8void print_stack(); 9struct cell{ 10 char c; 11 struct cell *next; 12}; 13typedef struct cell cell; 14 15cell *p; 16cell *listhead; 17 18//pushする関数 19void push(char s/*pushする文字*/){ 20 p=(cell*)malloc(sizeof( cell ) ); 21 p->c = s; 22 p->next = listhead; 23 listhead = p; 24} 25 26//popする関数 27char pop(){ 28 cell *tmp = NULL; 29 if(listhead == NULL ){ 30 printf("スタックは空です\n"); 31 free_stack(); 32 } 33 else{ 34 tmp=p->next; 35 listhead = tmp; 36 free(p); 37 } 38 print_stack(); 39 return tmp->c; 40} 41 42//end後スタックのメモリを開放する関数 43void free_stack(){ 44 cell *q; 45 while(p != NULL){ 46 q=p->next; 47 free(p); 48 p=q; 49 } 50 printf("プログラムを終了します\n"); 51} 52 53//スタックの内容を表示する関数 54void print_stack(){ 55 while(p != NULL){ 56 printf(" -> %c" , p->c); 57 p=p->next; 58} 59 printf("\n"); 60 61} 62 63int main(void){ 64 char in[100];//スタック 65 int n=0;//保存されているデータ数 66 67 do{ 68 printf("pushする文字かpop/endを入力して下さい --> "); 69 scanf("%s" , &in[n]); 70 //endの入力 71 if(strcmp(&in[n],"end") == 0){ 72 printf("スタックを空にしました\n"); 73 free_stack(); 74} 75 //popの処理 76 else if (strcmp(&in[n],"pop") == 0){ 77 printf("popされた文字は %c です\n" , pop()); 78 if(n>0){ 79 n--; 80 } 81} 82 //popやendでない時の処理 83 else if(strlen(&in[n]) != 1){ 84 printf("不正な入力です\n"); 85 free_stack(); 86 break; 87} 88 //適切な入力の処理 89 else{ 90 push(in[n]); 91 print_stack(); 92 n++; 93} 94 95 }while(strcmp(&in[n],"end") != 0); 96 97 98 return 0; 99} 100

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

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

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

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

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

itagagaki

2021/05/21 17:34

listheadがスタックの先頭を指しているっぽいですが、ではpは何を指していますか?
thkana

2021/05/21 22:47

> よろしくおねがいします。 というのは、完成したソースを寄越せ、という意味ですか?
tamintya

2021/05/22 03:11

pはグローバル宣言しているのでpush関数内での値などが入っているわけではないのですか?
itagagaki

2021/05/22 03:37

tamintyaさんが、pという変数にどのような意味を持たせているのか、どのような値を保持し、いつどのように変更したり参照されるべきなのかを、どう設計し、どう把握しているのか、ということをお聞きしました。そこがかなり怪しいですね。
tamintya

2021/05/22 05:40

リスト構造だからという感じでpを使っていたのでもう一度確認し直したいと思います。 ありがとうございました。
guest

回答3

0

C言語のコードを書くなら、デバッグできる環境を整えましょう。
Eclipseや、WindowsならVisualStudioなど。
コードの任意の場所で実行を止め、変数のナカミを見ることができます。そこから1行づつ実行して、コードの流れを見れるようになります
そうすれば、アテズッポでコードを書かなくて済むようになります。

p に何も代入されてないように見えます。
なにがはいってるでしょうか

投稿2021/05/21 22:48

y_waiwai

総合スコア87749

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

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

tamintya

2021/05/22 03:12

回答ありがとうございます。 上にも書きましたがpはグローバル宣言しているのでpush関数内での値などが入っているわけではないのですか?
y_waiwai

2021/05/22 03:16

pushが実行されたら、たしかにそこに値が入ります 逆に言うと、pushが実行されない限り、そこには値は入りません で、どこでそれが実行されてますか?
tamintya

2021/05/22 03:38

その場合はlisthead == NULL となっているはずなのでpを使わないルートを用意しているはずなのですが?
y_waiwai

2021/05/22 03:44

まあとにかく、デバッグ環境を整えて、変数のナカミを見れるようにしましょう。 XXのはず、XXと思うから、といってるうちは問題は解決しませんよ
tamintya

2021/05/22 05:43

分かりました。 疑問点に答えて下さりありがとうございました。
guest

0

セグメンテーションフォールトが起こるのは、pop() の中で tmp = p->next; をしてますが、これが原因。この時 p の値が NULL になっている。
なぜNULLになるかというと、main() 関数が push() した後 print_stack() しているから。
print_stack() は p が NULL になった時、終了してますよね。

アドバイス

  1. pop の中で p->next から始めるのではなく、listhead を見ることから始めること。
  2. cell を free した後にメンバー変数 c や next をアクセスしないよう、注意深くコーディングする
  3. cell *p; をグローバル変数にするのではなく、各関数内のローカル変数にする

投稿2021/05/22 03:58

rubato6809

総合スコア1380

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

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

tamintya

2021/05/22 05:42

アドバイスありがとうございます。 参考にして自分で作ったソースコードを修正したいと思います。
asm

2021/05/22 06:58

main関数の変数inの扱いにもツッコミいれたい
rubato6809

2021/05/22 08:01

そうそう、まず最初にヘンと思ったのは in[] の使い方でした。セグフォの原因じゃなかったので抜けてしまいました。
rubato6809

2021/05/22 08:03

そこんとこ、epistemeさんのコードは普通の使い方のようなので、こちらはそのまま。
guest

0

ベストアンサー

C

1#include<stdio.h> 2#include<stdlib.h> 3#include<string.h> 4 5void push(char); 6char pop(); 7void free_stack(); 8void print_stack(); 9 10struct cell { 11 char c; 12 struct cell* next; 13}; 14typedef struct cell cell; 15 16cell* listhead = NULL; 17 18//pushする関数 19void push(char s/*pushする文字*/) { 20 cell* p = (cell*)malloc(sizeof(cell)); 21 p->c = s; 22 p->next = listhead; 23 listhead = p; 24} 25 26//popする関数 27char pop() { 28 char c = '\0'; 29 if (listhead == NULL) { 30 printf("スタックは空です\n"); 31 } else { 32 cell* tmp = listhead->next; 33 c = listhead->c; 34 free(listhead); 35 listhead = tmp; 36 } 37 print_stack(); 38 return c; 39} 40 41//end後スタックのメモリを開放する関数 42void free_stack() { 43 cell* p = listhead; 44 while (p != NULL) { 45 cell* q = p->next; 46 free(p); 47 p = q; 48 } 49 printf("プログラムを終了します\n"); 50} 51 52//スタックの内容を表示する関数 53void print_stack() { 54 cell* p = listhead; 55 while (p != NULL) { 56 printf(" -> %c", p->c); 57 p = p->next; 58 } 59 printf("\n"); 60} 61 62int main(void) { 63 char line[64]; 64 do { 65 printf("pushする文字かpop/endを入力して下さい --> "); 66 scanf("%s", line); 67 if (strcmp(line, "end") == 0) { 68 printf("スタックを空にしました\n"); 69 free_stack(); 70 } else if (strcmp(line, "pop") == 0) { 71 char c = pop(); 72 if ( c != '\0' ) { 73 printf("popされた文字は %c です\n", c); 74 } 75 } else if (strlen(line) != 1) { 76 printf("不正な入力です\n"); 77 free_stack(); 78 break; 79 } else { 80 push(line[0]); 81 print_stack(); 82 } 83 } while (strcmp(line, "end") != 0); 84 return 0; 85}

[おまけ] 僕ならこう書く

C

1#include<stdio.h> 2#include<stdlib.h> 3#include<string.h> 4 5struct cell { 6 char c; 7 struct cell* next; 8}; 9 10typedef struct stack_t { 11 struct cell* head; 12} stack; 13 14void initialize(stack* stk) { 15 stk->head = NULL; 16} 17 18//スタックの内容を表示する 19void print_stack(const stack* stk) { 20 struct cell* p = stk->head; 21 while (p != NULL) { 22 printf(" -> %c", p->c); 23 p = p->next; 24 } 25 printf("\n"); 26} 27 28//pushする 29void push(stack* stk, char s) { 30 struct cell* p = (struct cell*)malloc(sizeof(struct cell)); 31 p->c = s; 32 p->next = stk->head; 33 stk->head = p; 34} 35 36//popする(空のときは'\0'を返す) 37char pop(stack* stk) { 38 char c = '\0'; 39 if ( stk->head != NULL) { 40 struct cell* tmp = stk->head->next; 41 c = stk->head->c; 42 free(stk->head); 43 stk->head = tmp; 44 } 45 return c; 46} 47 48// スタックを空にする 49void clear(stack* stk) { 50 struct cell* p = stk->head; 51 while (p != NULL) { 52 struct cell* q = p->next; 53 free(p); 54 p = q; 55 } 56 stk->head = NULL; 57} 58 59int main(void) { 60 stack stk; 61 initialize(&stk); 62 char line[64]; 63 do { 64 printf("pushする文字かpop/endを入力して下さい --> "); 65 scanf("%s", line); 66 if (strcmp(line, "end") == 0) { 67 } else if (strcmp(line, "pop") == 0) { 68 char c = pop(&stk); 69 print_stack(&stk); 70 if ( c != '\0' ) { 71 printf("popされた文字は %c です\n", c); 72 } else { 73 printf("スタックは空です\n"); 74 } 75 } else if (strlen(line) != 1) { 76 printf("不正な入力です\n"); 77 break; 78 } else { 79 push(&stk, line[0]); 80 print_stack(&stk); 81 } 82 } while (strcmp(line, "end") != 0); 83 clear(&stk); 84 printf("スタックを空にしました\n"); 85 printf("プログラムを終了します\n"); 86 return 0; 87}

投稿2021/05/22 01:24

編集2021/05/22 07:57
episteme

総合スコア16614

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

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

tamintya

2021/05/22 03:32

回答ありがとうございます。 上のソースコードを実行してみたのですがpop関数が2回走っている? ようなのですが修正個所が分からないです。
episteme

2021/05/22 03:51 編集

あーごめんなさい。printf() 中の pop() は c のマチガイ。(修正しておきました) # いや修正箇所が分らんのはヤバいっしょ...
tamintya

2021/05/22 05:42

ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問