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

解決済みの質問

C++のポインタの動作を教えてください

ちょっと長いですが、ある部分の動作がわかりません
そこを詳しく教えてください。
void queue::store(int i)の//リスト末尾に置くっていうところからで
なぜ、if(tail)tail->next=item;
tail=item;
こう書くのかわからないです。
tail->next=itemの次にtail=itemを実行すると、tail->nextの内容も変わるのでは?と思っているのですがどうなっているのかわからないのでお願いします。
説明が下手ですがすみませんが教えてください。



//仮想関数の実例
#include <iostream>
#include <cstdlib>
#include <cctype>
using namespace std;

class list{
public:
list *head;//リスト先頭へのポインタ
list *tail;//リスと末尾へのポインタ
list *next;//次項目へのポインタ
int num;//格納される値
list(){ head=tail=next=NULL; }
virtual void store(int i)=0;
virtual int retrieve()=0;
};

//キュー型リストの作成
class queue:public list{
public:
void store(int i);
int retrieve();
};

void queue::store(int i)
{
list *item;
item=new queue;

if(!item){
cout << "メモリ割り当てエラー" << endl;

exit(1);
}

item->num=i;

//リスト末尾に置く
if(tail)tail->next=item;
tail=item;
item->next=NULL;
if(!head)head=tail;
}

int queue::retrieve()
{
int i;
list *p;

if(!head){
cout << "リストは空です" << endl;

return 0;
}

//リスト先頭から取り除く
i=head->num;
p=head;
head=head->next;
delete p;

return i;
}

//スタック型リストの作成
class stack:public list{
public:
void store(int i);
int retrieve();
};

void stack::store(int i)
{
list *item;
item=new stack;

if(!item){
cout << "メモリ割り当てエラー" << endl;

exit(1);
}

item->num=i;

//スタックのような操作になるよう、リスト最前部におく
if(head)item->next=head;
head=item;
if(!tail)tail=head;
}

int stack::retrieve()
{
int i;
list *p;

if(!head){
cout << "リストは空です" << endl;

return 0;
}

//リスト先頭から取り除く
i=head->num;
p=head;
head=head->next;
delete p;

return i;
}

class sorted:public list{
public:
void store(int i);
int retrieve();
};

void sorted::store(int i)
{
list *item;
list *p,*p2;

item=new sorted;

if(!item){
cout << "メモリ割り当てエラー" << endl;

exit(1);
}

item->num=i;

//次項目のおき場所を見つける
p=head;
p2=NULL;
while(p){//中へ
if(p->num>i){
item->next=p;
if(p2)p2->next=item;//先頭要素ではない
if(p==head)head=item;//新しい先頭要素
break;
}

p2=p;
p=p->next;
}

if(!p){//終わりへ
if(tail)tail->next=item;
tail=item;
item->next=NULL;
}

if(!head)//先頭要素
head=item;
}

int sorted::retrieve()
{
int i;
list *p;

if(!head){
cout << "リストは空です" << endl;

return 0;
}

//リスト先頭から取り除く
i=head->num;
p=head;
head=head->next;
delete p;

return i;
}

int main()
{
list *p;

//キューのデモ
queue q_ob;
p=&q_ob;//キューをさす

p->store(1);
p->store(2);
p->store(3);

cout << "キュー:";
cout << p->retrieve();
cout << p->retrieve();
cout << p->retrieve();

cout << endl;

//スタックのデモ
stack s_ob;
p=&s_ob;//スタックをさす

p->store(1);
p->store(2);
p->store(3);

cout << "スタック:";
cout << p->retrieve();
cout << p->retrieve();
cout << p->retrieve();

cout << endl;

//ソート済みリストのデモ
sorted sorted_ob;
p=&sorted_ob;

p->store(4);
p->store(1);
p->store(3);
p->store(9);
p->store(5);

cout << "ソ\ート:";
cout << p->retrieve();
cout << p->retrieve();
cout << p->retrieve();
cout << p->retrieve();
cout << p->retrieve();

cout << endl;

return 0;
}

投稿日時 - 2014-08-08 20:54:45

QNo.8709519

すぐに回答ほしいです

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

#1です。
>tail->nextはtailポインタとは関係ないものなんでしょうか?
>tail->nextの値はtail自体を変えるとtail->nextも変わってしまうのかなと思っているのですが…。
なんとなく、わからないところがわかりました。
多分、ポインタの概念がまだしっくりときていないのかと思います。

tailというのはポインタなので、実体はありません。
リスト構造の最後のitemを指し示す目印のようなものです。

なので、
>tail=item;
というのは、tailの中身を操作するものではなく、tailの指し示しているものを新しいitemに変更するという意味になります。
なので、それまでのtail->nextの値に変化はありませんが、これ以降はtailの指し示す対象が新しいitemになるので、tail->nextで参照すると変わっているように見えます。

それまでのtail->nextが変わっていないのを確認するために、以下のようにしてデバッガで値を確認してみるのもひとつの方法です。


list* oldtail = tail; //ここでtail->nextの値を確認
if(tail)tail->next=item;
tail=item;
list* a = oldtail->next; //ここで前に確認したtail->nextの値と比較する

nextの値に変化が無いのが確認できると思います。

ただ、ちょっと気になったのは教科書的なリスト構造とはちょっと異なっているので、その他のリスト構造のサンプル等も参考にすると良いと思います。

C言語のポインタは実感しにくくつまづく人も多いので、それだけの内容の本も結構あります。
http://www.amazon.co.jp/s/ref=nb_sb_noss_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&url=search-alias%3Dstripbooks&field-keywords=%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF
どうしても理解できない場合は評判の良い本を選んで1冊読んでみることをお勧めします。

投稿日時 - 2014-08-09 00:24:25

お礼

実はこのプログラムも勉強しているもので独習C++という本を使ってやっているのですが、いきなりこういうのが出てきてわからないことがあり、質問してみたのですが、詳しく教えていただきありがとうございました。
自分なりの解釈では理解できたと思うのですが、自分の解釈が間違っているかもしれないので、本を読んでみようかと思います。

投稿日時 - 2014-08-09 00:52:51

ANo.3

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

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

回答(3)

ANo.2

>tail->nextはtailポインタとは関係ないものなんでしょうか?

はい。関係ありません。

>tail->nextの値はtail自体を変えるとtail->nextも変わってしまうのかなと思っているのですが…。

変わりません。
変数の値と、それがポイントするオブジェクトを混同していますね。

市長が山田さんだとします(変数:市長へのオブジェクト:山田のポインタの代入)。
市長さんに子どもが生まれたとして(変数:市長の指すオブジェクトの変化)、その後、市長が田中さんに替わったからと言って(変数へ別のオブジェクトポインタの代入)、山田さんの子ども(さっきのオブジェクト:山田の内容)はそのままです。

投稿日時 - 2014-08-08 23:16:03

お礼

わかりやすく例を出していただいてありがとうございました。
ポインタのことをまた一から勉強しなおそうかなと思っています。

投稿日時 - 2014-08-09 00:54:07

ANo.1

リストはななめ読みですが、これはリストの一般的な操作方法です。
tailはリスト末尾のポインタを保持していますね?

>なぜ、if(tail)tail->next=item;
そこにitemを追加しています。

>tail=item;
そうすると、tailが指しているポインタはリストの末尾ひとつ前になるので、今追加したitemをリストの末尾として登録してあげているのです。

>tail->nextの内容も変わるのでは?
次に参照した場合はさっき追加した場合のitemがtailになっているので、リストをつなげていくことができます。

item->item
------↑tail

item->item->item
------------↑tail
となった感じです。

大ざっぱな説明なので不明なところがあれば補足してください。

投稿日時 - 2014-08-08 21:29:47

補足

tail->nextはtailポインタとは関係ないものなんでしょうか?
tail->nextの値はtail自体を変えるとtail->nextも変わってしまうのかなと思っているのですが…。

投稿日時 - 2014-08-08 22:09:25

お礼

if(tail)tail->next=itemが変数を追加していて、
tail=itemが次の参照のときに、変数を追加するための準備っていうことですかね…。

投稿日時 - 2014-08-08 23:56:05

あなたにオススメの質問