かれこれ1時間くらい悩んでいて
問題として
関数delete()を作成し、プログラムを完成させよ(~yabuki/p7.c)。
関数delete()は、与えられたデータをリストから削除するものである。
ただし、データが先頭であっても動作しなければならない。
次のように出力されるはずである。
NEXT gyuri[23] -> sunyon[23] -> nicole[20] -> hara[20] -> jiyon[17] -> END
PREV jiyon[17] -> hara[20] -> nicole[20] -> sunyon[23] -> gyuri[23] -> END
NEXT gyuri[23] -> sunyon[23] -> nicole[20] -> hara[20] -> END
PREV hara[20] -> nicole[20] -> sunyon[23] -> gyuri[23] -> END
NEXT sunyon[23] -> END
PREV sunyon[23] -> END
list ha nakunarimasita
/*******/の間に5行のプログラムを入れる。それ以外にmain()関数を
変更してはならない。
.........;の部分に構造体のメンバーを定義せよ。
というもので、Deleteしていくプログラムをつくりたいのですが
NEXT gyuri[23] -> sunyon[23] -> nicole[20] -> hara[20] -> jiyon[17] -> END
PREV jiyon[17] -> hara[20] -> nicole[20] -> sunyon[23] -> gyuri[23] -> END
セグメントエラー
となり、続きができていません。
delete関数のif(p->next != NULL){ のところだけやると
最後まで出るみたいですが、うまくいってません
よろしくおねがいします。
↓ソースです・・・
#include <stdio.h>
#include <string.h>
struct kara {
char name[16];
int age;
struct kara *next;
struct kara *prev;
};
struct kara * delete(struct kara *,struct kara *);
struct kara * findend(struct kara *);
void* printforw(struct kara *);
void* printback(struct kara *);
int
main()
{
struct kara a, x, f, m, c, *start, *end, *p;
char name[128];
strcpy(a.name, "gyuri");
a.age = 23;
strcpy(x.name, "sunyon");
x.age = 23;
strcpy(f.name, "nicole");
f.age = 20;
strcpy(m.name, "hara");
m.age = 20;
strcpy(c.name, "jiyon");
c.age = 17;
a.next = &x;
x.next = &f;
f.next = &m;
m.next = &c;
c.next = NULL;
/********************* 5 lines */
a.prev = NULL;
x.prev = &a;
f.prev = &x;
m.prev = &f;
c.prev = &m;
/*********************/
start = &a;
end = findend(start);
printforw(start);
printback(end);
printf("\n");
p = &c;
start = delete(start, p);
if (start == NULL) {
printf("list ha nakunarimasita\n");
return 0;
} else {
end = findend(start);
printforw(start);
printback(end);
}
printf("\n");
x.next = NULL;
p = &a;
start = delete(start, p);
if (start == NULL) {
printf("list ha nakunarimasita\n");
return 0;
} else {
end = findend(start);
printforw(start);
printback(end);
}
printf("\n");
p = start;
start = delete(start, p);
//de senntou wo kaesu
if (start == NULL) {
printf("list ha nakunarimasita\n");
return 0;
} else {
end = findend(start);
printforw(start);
printback(end);
}
return 0;
}
struct kara *
delete (struct kara *start,struct kara *p)
{
/*if(p->next->next->next->next)
{
start = p->next->next->next->next;
}
*/
for(p = start;p != NULL;p = p->next)
{
start = p->next->next->next;
p = start;
}
/*
if(p->next)
{
start = p->next;
}
if(p->prev)
{
start = p->prev;
}
if(p->next != NULL){
p->next->prev = p->prev;
}
}
*/
return p;
}
struct kara *
findend(struct kara *start)
{
struct kara *pl;
for(pl = start;pl != NULL; pl = pl->next){
start = pl;
}
return start;
}
void*
printforw(struct kara *aa)
{
struct kara *pl;
printf("NEXT ");
for ( pl = aa; pl != NULL; pl = pl->next) {
printf("%s[%d] -> ", pl->name, pl->age);
}
printf("END\n");
}
void*
printback(struct kara *cc)
{
struct kara *pl;
printf("PREV ");
//for( ; cc != NULL;cc = cc->prev){
for (pl = cc; pl != NULL; pl = pl->prev) {
printf("%s[%d] ->", pl->name,pl->age);
}
printf("END\n");
}
No.2ベストアンサー
- 回答日時:
これを前提知識なしで出されたら、出題者が悪いと思いますが、そうでなかったらちゃんと授業を聞いていたかと問いただしたくなります。
リストの削除の方法って授業で説明しませんでしたか?他の人が書いたプログラムというのも勉強になると思いますので一応説明します。
deleteという操作は、リストから該当する要素を発見し、その要素を取り除くという操作で行います。
言い換えると、発見するというプログラムと取り除くというプログラムの組み合わせです。
まず、リストから所定の要素を探しだすというプログラムを書きましょう。
それは、こういうコードになるはずです。
struct kara *
find(struct kara *start, struct kara *to_find)
{
struct kara* cur;
for(cur = start;cur != NULL;cur = cur->next)
{
if (cur == to_find) {
printf("found %s %d\n", cur->name, cur->age);
return cur;
}
}
return NULL;
}
このプログラムはto_findに探したい要素のポインターを入れると、それを探しだして、printfで内容を表示した上でそれを返します。
次に、リストからの要素の削除です。
リストから要素を削除するという操作は、自分がいなかったかのようにポインターを付け替えるという操作です。
例えば、次のよなリストでbを消すことを考えます。
a -> b -> c
この場合、bが消えたあとの状態はこうなります。
a -> c
これは、bの指している先であるcをaの指し先に変更するということです。
言い換えると、bのprevのnextをbのnextにするということです。
よって、プログラムでやると b->prev->next = b->nextとなります。
また、prevについても同じ事をするのでb->next->prev = b->prevとなります。
ただし、リストの一番最後の要素に対して削除をする場合、b->nextは存在しないのでb->next->prev = b->prevの動作をする必要はありません。
まとめると、
if (b->prev != NULL) {
b->prev->next = b->next;
}
if (b->next != NULL) {
b->next->prev = b->prev;
}
となります。ただ、削除対象がstartだったとき b->prev == NULLのだけちょっとしたトリックが必要です。
この部分を実際のプログラムに起こすと書くとこんなかんじです。
struct kara *
delete (struct kara *start,struct kara *p)
{
struct kara* to_delete = find(start, p);
if (to_delete != NULL) {
if (to_delete->prev != NULL)
to_delete->prev->next = to_delete->next;
else /* head of the list. */
start = to_delete->next;
if (to_delete->next != NULL)
to_delete->next->prev = to_delete->prev;
}
return start;
}
以上でdelete関数が出来上がりました。
余談ですが、最後の要素を毎回手繰るというのは無駄な操作なので、こういうことをしたい場合は普通はtailqというtailを指すポインタを持つ両方向リンクリストを使うのが普通だと思います。
ついでに余談ですが、リスト操作はコンピュータサイエンスの基礎知識ではありますが、基本的にやることは決まっているので、queue.hなどを使って書くのが普通だと思います。
ちょろっと調べたら、そのtailqの内部構造を解説したページを見つけたので参考までに。
http://d.hatena.ne.jp/koseki2/20120105/tailq
もう一つ余談を言うと、セグメントエラーが出るようなプログラムで動きを確かめるにはgdbを使うと良いです。gdbを使うと、どこでセグメントエラーが出ているか一瞬でわかるので、とりあえず治すのは格段に早くなります。
今回の場合、gdbを使うとstart = p->next->next->next;で出ていると一発でわかります。まぁ、わかったところで上記のようなコードを書かないと動かないのですが。
では、頑張って。
この回答への補足
説明はまったくもってないです。簡単な構造体の作り方のみしか教わりません。
こういった応用問題は独学で学ぶしかないので、こういった頼りが必要になってしまいます。先生に聞いても答えてくれはくれないので。
少し参考にして自分なのにdelete関数を作ってみます。
No.1
- 回答日時:
リンク構造、ちゃんと理解していない…ってコトでしょうな。
start = delete(start, p);
struct kara *delete (struct kara *start,struct kara *p)
ということは…startからpを探して、リンクのつなぎ替えを実施しさらにその先頭を返却する。
ということになります。
で、
>ただし、データが先頭であっても動作しなければならない。
ということなので条件分岐が必要…ですな。
まず…
startとpが同じか?で分岐。
同じだったら先頭を取り除くので、
startの次へ進めます。
NULL(つまりリストにはstartしかない)であれば戻り値はNULLで、非NULLならstart(またはp)をリンクから外すためにprevをNULLにします。
# リスト構造としてはstartのnextもNULLにすべき…でしょうが……。
startとpが異なる場合はstartからリストを辿ってpを検索、
pの次の要素のprevにpが持っているprevをコピー、pの前の要素のnextにpが持っているnextをコピーしてリンクのつなぎ替えを行います。
# それぞれ、絵に描いてどういうつながりになるのか確認してみるといいでしょう。
pをリンクから外した後で先頭の要素のアドレスを返す。
と……。
まぁ、もう少し効率のいい方法もありますが。
# pは判っているのだからstartから検索する必要はない…よね。と…。
ちなみに…
>struct kara *
>delete (struct kara *start,struct kara *p)
>{
> for(p = start;p != NULL;p = p->next)
こんなコトしたら、削除対象のpのアドレスがいきなり不明になります。
この回答への補足
こういった問題を説明なしに出されるので、なんともいえません。
教えてくれるのはほんの一部で
構造体の簡単な作り方ー!みたいな感じで教えてくれるだけで
本質は課題として出されて、まったく構造体のポインタなどの説明がないんですよね。
最後のはよくわからないのでやってしまいました。
そもそもこのプログラムの前半自体は先生が書いたもので
自分で書いたものではないので、3回表示するんだろうな、くらいで
後は問題通りに何か色々やってみた結果です。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
好きな人を振り向かせるためにしたこと
大好きな人と会話のきっかけを少しでも作りたい、意識してもらいたい…! 振り向かせるためにどんなことをしたことがありますか?
-
【大喜利】【投稿~1/9】 忍者がやってるYouTubeが炎上してしまった理由
【お題】・忍者がやってるYouTubeが炎上してしまった理由
-
自分独自の健康法はある?
こうしていると調子がいい!みたいな自分独自の健康法、こだわりはありますか?
-
【選手権お題その3】この画像で一言【大喜利】
とあるワンシーンを切り取った画像。この画像で一言、お願いします!
-
【大喜利】【投稿~1/20】 追い込まれた犯人が咄嗟に言った一言とは?
【お題】追い込まれた犯人が咄嗟に言った一言とは?
-
C言語・要素除去
C言語・C++・C#
-
構造体の削除について
C言語・C++・C#
-
gcc: incompatible pointer type
C言語・C++・C#
-
-
4
SetWindowText関数について
C言語・C++・C#
-
5
Integer変数をカラにしたいのですが
Visual Basic(VBA)
-
6
C言語にて構造体のメンバがNULLであるかを判定するサンプルを作成して
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・「みんな教えて! 選手権!!」開催のお知らせ
- ・漫画をレンタルでお得に読める!
- ・【大喜利】【投稿~1/20】 追い込まれた犯人が咄嗟に言った一言とは?
- ・洋服何着持ってますか?
- ・みんなの【マイ・ベスト積読2024】を教えてください。
- ・「これいらなくない?」という慣習、教えてください
- ・今から楽しみな予定はありますか?
- ・AIツールの活用方法を教えて
- ・【選手権お題その3】この画像で一言【大喜利】
- ・【お題】逆襲の桃太郎
- ・自分独自の健康法はある?
- ・最強の防寒、あったか術を教えてください!
- ・【大喜利】【投稿~1/9】 忍者がやってるYouTubeが炎上してしまった理由
- ・歳とったな〜〜と思ったことは?
- ・ちょっと先の未来クイズ第6問
- ・モテ期を経験した方いらっしゃいますか?
- ・好きな人を振り向かせるためにしたこと
- ・【選手権お題その2】この漫画の2コマ目を考えてください
- ・【選手権お題その1】これってもしかして自分だけかもしれないな…と思うあるあるを教えてください
- ・スマホに会話を聞かれているな!?と思ったことありますか?
- ・それもChatGPT!?と驚いた使用方法を教えてください
- ・見学に行くとしたら【天国】と【地獄】どっち?
- ・これまでで一番「情けなかったとき」はいつですか?
- ・この人頭いいなと思ったエピソード
- ・あなたの「必」の書き順を教えてください
- ・14歳の自分に衝撃の事実を告げてください
- ・人生最悪の忘れ物
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C#でのEXCEL出力に関して
-
空のカラムを挿入
-
双方向リストのバブルソートに...
-
InvokeMemberメソッドとは何を...
-
信頼区間の1.96や1.65ってどこ...
-
Aの値からBの値を除するとは??
-
「Aに対するBの割合」と「Aに対...
-
#define _CRT_SECURE_NO_WARNIN...
-
Enterキーを押されたら次の処理...
-
2÷3などの余りについて
-
プログラムでの数字につく”f”の...
-
エクセルで可視セルにのみ値貼...
-
*をユーザーが入力した数字の数...
-
C言語での引数の省略方法
-
エクセルの問題です。絶対値の...
-
DWORDの実際の型は何でしょうか
-
20'(角度)の計算がわかりま...
-
変数とパラメータとは違うもの...
-
Excelで1つしかない値だけを抽...
-
「指定されたキャストは有効で...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
構造体のリスト削除
-
InvokeMemberメソッドとは何を...
-
C# ref引数のnull判定
-
C言語 リスト
-
コールバック関数はnullになら...
-
C#でのEXCEL出力に関して
-
空のカラムを挿入
-
if文でゼロとNULLを除外するた...
-
ばばぬきプログラムについて
-
リスト構造
-
C言語 リスト
-
信頼区間の1.96や1.65ってどこ...
-
「Aに対するBの割合」と「Aに対...
-
エクセルで可視セルにのみ値貼...
-
Enterキーを押されたら次の処理...
-
「指定されたキャストは有効で...
-
2÷3などの余りについて
-
C言語での引数の省略方法
-
Aの値からBの値を除するとは??
-
DWORDの実際の型は何でしょうか
おすすめ情報