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

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

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

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

Q&A

解決済

2回答

908閲覧

連結リストから入力した数字の位置のノードを削除するプログラムで、2回目からの入力がおかしくなってしまいます。

aoa

総合スコア4

C

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

0グッド

0クリップ

投稿2022/11/14 15:44

前提

大学の課題で躓きました。連結リストから入力した数字の位置のノードを削除するプログラムで、2回目からの入力がおかしくなってしまいます。どのようにすれば2回目からも普通に動作するようになるでしょうか。
お願いします。

頭のある連結リストに対し、先頭の節点を削除する関数

void delete(list l);

を定義せよ。この関数は先頭を削除する関数であるが、リスト l の先頭の次を削除したい場合は delete(l->next)、さらにその次を削除したい場合はdelete(l->next->next) のようにすれば、先頭以外の位置のものも削除することができる。なお、メモリリーク)が起こらないように、不要になった節点のメモリは free 関数によって必ず解放する必要がある。作成すべきプログラムは、標準入力の 1 行目に与えられる文字列から char 型のリストを作成し、以降の入力の各行に与えられる「位置」に対し、その位置のアルファベットを削除するプログラムを作成せよ。「位置」は整数値で与えられ、0 番目が先頭を表すものとする。

実行例

>Bingo Bingo >2 Bigo >3 Big >Linked Linked >4 Linkd >4 Linkd >4 Linkd >4 Linkd >0 ink

発生している問題・エラーメッセージ

>Bingo Bingo >2 Bigo >3 Bi >0 iiiiiiiiiiiiiiiiiiiiiii.... >Linked Linked >4 Linkd >4 Linked >4 Linked >0 inkinkinkinkinkinkinkinkinkink........

該当のソースコード

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5 6typedef char elementtype; 7struct node { 8 elementtype element; 9 struct node* next; 10}; 11 12typedef struct node* list; 13 14struct node *initlist(elementtype e, struct node *x) { 15 struct node *n = (struct node *)malloc(sizeof(struct node)); 16 n->element = e; 17 n->next = x; 18 return n; 19} 20 21void insert(list *l, elementtype e) { 22 *l = initlist(e, *l); 23} 24 25void delete (list *l) { 26 if((*l)->next!=NULL){ 27 struct node *n=initlist(NULL,(*l)->next); 28 free(*l); 29 l=&n; 30 } 31} 32 33void printlist(list l) { 34 for( ; l != NULL; l=l->next) printf("%c", l->element); 35 printf("\n"); 36} 37 38int main() { 39 char buf[128]; 40 struct node head; 41 int i; 42 list l ; 43 fgets(buf, sizeof(buf), stdin); 44 int len = strlen(buf); 45 if(len>0 && buf[len-1]=='\n') buf[len-1] = '\0'; 46 47 head.next = NULL; 48 for(i=strlen(buf)-1; i>=0; i--) insert(&head.next, buf[i]); 49 50 printlist(head.next); 51 52 while(fgets(buf,sizeof(buf),stdin) != NULL) { 53 sscanf(buf,"%d",&i); 54 l = &head; 55 for(i; i>0 && l->next!=NULL; i--, l=l->next); 56 delete(&l->next); 57 printlist(head.next); 58 } 59 60 return 0; 61}

補足情報(FW/ツールのバージョンなど)

unix gcc 4.8.5

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

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

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

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

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

jimbe

2022/11/14 18:33 編集

何が起きているとお考えでしょうか。 また、それをどうすれば調べられる/確認できると思われますか。 …実行例の Linked のほう、 4 を指定しても d が消えてないですね。
guest

回答2

0

ベストアンサー

頭のある連結リストに対し、先頭の節点を削除する関数
void delete(list l);
を定義せよ。

質問者の方は、こちらの文言を誤解しているように思います。(誤解を招く表現になっているのは確かなのですが)

出題者はおそらく、引数lの「次の」要素を削除する関数を書いて欲しいのだと思われます。
(頭のある連結リストの場合、先頭の接点は「頭」の次の接点となる)

それを誤解してlの指す要素そのものを削除する関数を書こうとした結果、引数の型をlist lからlist* lに変えざるを得なくなって、混乱を招いているように思います。
(こちらの方針でも書けないことはありませんが、難易度は上がります)

まずは素直に、lの「次の」要素を削除する関数void delete(list l);を書いてみてはいかがでしょうか。


なお、現状のコードで、初回だけうまくいっているように見えるのは、偶然にすぎません。

l=&n;とすることで、引数として渡したポインタを書き換えようとしたのだと思いますが、これでは元のポインタは書き換わりません。
(void f(int x) { x = 2; }としても、引数として渡した変数が書き換わらないのと同じ)

その結果、free(*l);で解放された node がそのまま使われ続けることになります。
解放済みメモリの使用は未定義動作なので、何が起こってもおかしくはありません。

投稿2022/11/14 17:51

編集2022/11/14 23:17
actorbug

総合スコア2242

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

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

aoa

2022/11/14 23:56

delete(l)にすることで治りました。ありがとうございました。
guest

0

Text

1i番目の要素を削除すると、i-1番目とi+1番目が連結になる。

投稿2022/11/14 16:17

atcoderyellow

総合スコア481

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

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

jimbe

2022/11/14 19:22 編集

↑無意味な大量の改行によりコメント欄が圧迫されている為、通報しました。
atcoderyellow

2022/11/14 19:41

時間を戻す方法を知りたい。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問