ポインタ演算とconstについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
K_Tarou
記事: 22
登録日時: 10年前

ポインタ演算とconstについて

#1

投稿記事 by K_Tarou » 10年前

初めてこちらの掲示板を利用させて頂きます、K_Tarouと申します。よろしくお願いいたします。
私は現在、C++を入門書を片手に独学しておりまして、いずれはゲームも作りたいと考えております。
プログラミング自体は勉強し始めて一ヶ月未満で、文法も完全にマスターしていない初心者です。


入門書に書かれているポインタについての事柄が気になって、コードを書きましたが予想に反した結果になってしまいました。
下記のようなコードを書いて色々と動作を試しておりました。お聞きしたいことは二つあります。

コード:

#include <cstdio>
using namespace std;

class Mystr{
private:
	char* text;
	int get_Leng(char *s){    //文字配列の長さを取得
		int n = 0;
		while (*s){
			printf("get_Leng %d : sのアドレスは \" %d \" です 値は \' %c \' でした\n", n,s,*s);    //内容確認用
			++s;
			++n;
		}
		return n;
	}
	void arr_Copy(char *s){    //文字配列の内容をコピー
		for(int n=0; *(text+n) = *s; n++){
			printf("arr_Copy %d : sのアドレスは \" %d \" です 値は \' %c \' でした\n", n,s,*s);    //内容確認用
			++s;
		}
	}
public:
	Mystr(char* ss = "");
	Mystr(const Mystr& obj);
	~Mystr(){delete[] text;}
};

Mystr::Mystr(char *ss){     //引数で指定された文字列をtextに確保
	text = new char[get_Leng(ss)+1];
	arr_Copy(ss);
	printf("コンストラクタ : text(s1)のアドレスは \" %d \" です 値は \' %s \' でした\n",text,text);    //内容確認用

}

Mystr::Mystr(const Mystr& obj){    //引数のオブジェクトの text をコピー
	text = new char[get_Leng(obj.text)+1];
	arr_Copy(obj.text);
	printf("コピーコンストラクタ : text(s2)のアドレスは \" %d \" です 値は \' %s \' でした\n",text,text);    //内容確認用
	printf("コピーコンストラクタ : obj.text(s1)のアドレスは \" %d \" です 値は \' %s \' でした\n",obj.text,obj.text);    //内容確認用
}

int main(){
    Mystr s1("abcd");
    Mystr s2 = s1;    //オブジェクトをコピー
    return 0;
}
まず一つ目の疑問ですが、
配列の長さを取得するget_Leng関数に渡された、コンストラクタのss(元は文字列リテラルの先頭アドレス?)は、get_Lengの中で更新(++s)されて
ポインタが終端文字('\0')に向けられる。そしてget_Lengから戻り、arr_Copyに同じくssを渡しますが、このssは先程のget_Leng関数によってポインタが進められていて、
意図した通りに動かない(コピーコンストラクタの方も)と考えていたのですが実際には、ちゃんと文字列の内容をコピーできています。
私のイメージは以下のようなものだったんですが、

    'a' → 'b' → 'c' → 'd' → '\0'  の '\0' に向けられている為、インクリメントしても意図した通りにならない

しかし、どうも結果を見ていると違うようですし
このget_Lengとarr_Copyに渡される"char *ss"並びに文字列リテラル"abcd"は、それぞれ別物なのでしょうか?
それとも他に何か大変な勘違いをしてしまっているのでしょうか......


二つ目の疑問ですが、
コピーコンストラクタの仮引数にconstをつけていますが、処理の中でget_Lengとarr_Copyにメンバ変数を渡し、"++s"の部分でアドレスを更新しているように見えます。
const付きのオブジェクトのメンバ変数は値を変更できないと入門書にも書いているのですが、何故"++s"という式を記述できるのでしょうか?


初歩的質問という以前に、解釈自体が間違っているのだろうと私も感じてはいるのですが
調べてみても理解できなかったので、質問をさせて頂きました。
どなたか教えて頂けませんか?

[追記]
すいません、文章中の変数名を間違って書いておりましたので訂正いたしました。

nil
記事: 428
登録日時: 12年前

Re: ポインタ演算とconstについて

#2

投稿記事 by nil » 10年前

1つ目.
コンストラクタに"abcd"のアドレスのコピーが渡される。
get_Lengにssのコピーが渡される(="abcd"のアドレスのコピーが渡される)。
sはssのコピーなので、sのアドレスが前置インクリメントで進められても、ssは変更されない->以上のような実行結果に。
(get_Lengやarr_Copyの引数はconst char*型にしたほうが良いかと)

2つ目.
1つ目より、メンバ変数が変更されることはない。

ポインタ周辺はやはり複雑ですね。
ここいらの感覚を身につけるのは私も苦労した覚えがあります。
ダブルポインタ(ポインタへのポインタ)や、参照などの概念に触れると少し理解しやすいかと思います。

K_Tarou
記事: 22
登録日時: 10年前

Re: ポインタ演算とconstについて

#3

投稿記事 by K_Tarou » 10年前

涼雅 さんが書きました:1つ目.
コンストラクタに"abcd"のアドレスのコピーが渡される。
get_Lengにssのコピーが渡される(="abcd"のアドレスのコピーが渡される)。
sはssのコピーなので、sのアドレスが前置インクリメントで進められても、ssは変更されない->以上のような実行結果に。
(get_Lengやarr_Copyの引数はconst char*型にしたほうが良いかと)

2つ目.
1つ目より、メンバ変数が変更されることはない。

ポインタ周辺はやはり複雑ですね。
ここいらの感覚を身につけるのは私も苦労した覚えがあります。
ダブルポインタ(ポインタへのポインタ)や、参照などの概念に触れると少し理解しやすいかと思います。

涼雅様
ご回答頂いた上、アドバイスもして頂き、ありがとうございます!

「コンストラクタに渡されているアドレスも、get_Lengに渡されているアドレスも、元のアドレスのコピー
つまり、アドレス(ポインタ)という値自体は、参照とは違って「値渡し」になっている
呼び出された側がポインタを " * " で間接参照した上で値を書き換えて始めて、呼び出し側の値に影響を与える......」

という解釈で宜しいのでしょうか?

nil
記事: 428
登録日時: 12年前

Re: ポインタ演算とconstについて

#4

投稿記事 by nil » 10年前

おそらくはその認識で間違いないと思います。
>アドレスの中身も
より正確に言うならば、アドレスの指す位置にある数値、といったところでしょうか?
この辺りの用語や言葉にはどうにも疎いので、誰か補足をいただけると幸いです。

K_Tarou
記事: 22
登録日時: 10年前

Re: ポインタ演算とconstについて

#5

投稿記事 by K_Tarou » 10年前

涼雅 さんが書きました: おそらくはその認識で間違いないと思います。
分かりました。おかげさまでようやく納得できました。
提示された、"ポインタのポインタ" や "参照" についても、もう一度勉強をして精進したいと思います。

迅速なご回答ありがとうございました!

閉鎖

“C言語何でも質問掲示板” へ戻る