ポインタの操作でつまづきました

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
dic
記事: 657
登録日時: 13年前
住所: 宮崎県
連絡を取る:

ポインタの操作でつまづきました

#1

投稿記事 by dic » 10年前

dicです。 参考書を読んでいてて、私の思ったとおりにならなくて、
どういうことなのか私一人では解決できないので、質問させてください。

参考書は プログラマの考え方がおもしろいほど身につく本 を使っています。

文字列に文字を動的メモリの割り当てを使って追加する関数appendをつくっています。
そこで、うまくいくケースと、想定外のケースが用意されていました。
うまくいくケースはわかりました。
問題は想定外のケースで、関数appendに文字列と文字を指定するのですが、
指定する文字列がゼロ(nullを含む)の場合、したに載せるプログラムではうまく動かないと
私は思うのですが、メモリリークせずにうごいています。

下のプログラムでのappend関数の2回目の呼び出しでは、
27行目で、sの内容は 0 なので、実行時エラーにはならないのでしょうか?
0(ゼロ)を文字列終端文字としています。

下のプログラムは参考書のプログラムに、多少追加しています。

コード:

#include <crtdbg.h>
#include	<stdio.h>
#include	<iostream>
using namespace std;

#ifdef _DEBUG
	#define	new	new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif

typedef	char * arrayString;

void	append( arrayString &s, char c ) {
	int	oldLength = 0;
	while( s[oldLength] != 0 ) {
		oldLength++;
	}
	arrayString	newS = new char[oldLength + 2];
	for( int i=0; i<oldLength; i++ ) {
		newS[i] = s[i];
	}
	newS[oldLength] = c;
	newS[oldLength + 1] = 0;

	//	2回目の呼び出しで、この条件にはひっかからない?
	if( 0 == s )
		cout << "NULL" << endl;
	delete s;
	s = newS;
}

int		main()
{
	// メモリリーク検出
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

	cout << "First" << endl;
	char	*a = new char[5];
	a[0] = 't'; a[1] = 'e'; a[2] = 's'; a[3] = 't'; a[4] = 0;
	append( a, '!' );
	cout << a << endl;
	delete a;

	cout << "Second" << endl;
	char	*b = new char[1];
	b[0] = NULL;
	append( b, '!' );
	cout << b << endl;
	delete b;

	return 0;
}

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: ポインタの操作でつまづきました

#2

投稿記事 by softya(ソフト屋) » 10年前

なにかNULLポインタと0とNUL文字がごっちゃになっている感じです。
b[0] = NULL;は代入すべきはNUL文字ですNULLポインタではありません。
それとsは実体の配列を指しているので、NULLではありません。

【追記】
配列のdeleteも不適切です。
「C++編(言語解説) 第12章 new/delete」
http://www.geocities.jp/ky_webid/cpp/language/012.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
usao
記事: 1889
登録日時: 11年前

Re: ポインタの操作でつまづきました

#3

投稿記事 by usao » 10年前

オフトピック
>参考書は プログラマの考え方がおもしろいほど身につく本 を使っています。
amazonの内容紹介を斜め読みしてみましたが…
先に文法側をそれなりに固めた方が良いような予感も.

dic
記事: 657
登録日時: 13年前
住所: 宮崎県
連絡を取る:

Re: ポインタの操作でつまづきました

#4

投稿記事 by dic » 10年前

>>softyaさん
これであっていることが確認できてよかったです。

delete の配列解放もたしかにおかしいですね

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

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: ポインタの操作でつまづきました

#5

投稿記事 by softya(ソフト屋) » 10年前

dic さんが書きました:>>softyaさん
これであっていることが確認できてよかったです。

delete の配列解放もたしかにおかしいですね

解決しました
ありがとうございました。
あとあと過去ログを見る人のために、不適切では無い書き方に修正したコードを張って頂けると助かります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

dic
記事: 657
登録日時: 13年前
住所: 宮崎県
連絡を取る:

Re: ポインタの操作でつまづきました

#6

投稿記事 by dic » 10年前

コード:

int     main()
{
    // メモリリーク検出
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
 
    cout << "First" << endl;
    char    *a = new char[5];
    a[0] = 't'; a[1] = 'e'; a[2] = 's'; a[3] = 't'; a[4] = 0;
    append( a, '!' );
    cout << a << endl;
 
    cout << "Second" << endl;
    char    *b = new char[1];
    b[0] = NULL;
    append( b, '!' );
    cout << b << endl;
 
    return 0;
}

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: ポインタの操作でつまづきました

#7

投稿記事 by みけCAT » 10年前

No: 6のコードでaもbも解放されていないように見えますが、「メモリリーク検出」によって検出されないでしょうか?
NULLを整数型の変数に代入しているところも、コンパイラとコンパイルオプションによっては警告の対象になります。
また、append関数の中身が不明です(話の流れから、修正されている可能性が否定できません)。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

dic
記事: 657
登録日時: 13年前
住所: 宮崎県
連絡を取る:

Re: ポインタの操作でつまづきました

#8

投稿記事 by dic » 10年前

コード:

#include <crtdbg.h>
#include    <stdio.h>
#include    <iostream>
using namespace std;
 
#ifdef _DEBUG
    #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif
 
typedef char * arrayString;
 
void    append( arrayString &s, char c ) {
    int oldLength = 0;
    while( s[oldLength] != 0 ) {
        oldLength++;
    }
    arrayString newS = new char[oldLength + 2];
    for( int i=0; i<oldLength; i++ ) {
        newS[i] = s[i];
    }
    newS[oldLength] = c;
    newS[oldLength + 1] = 0;
     delete s;
    s = newS;
}
 
int     main()
{
    // メモリリーク検出
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
 
    cout << "First" << endl;
    char    *a = new char[5];
    a[0] = 't'; a[1] = 'e'; a[2] = 's'; a[3] = 't'; a[4] = 0;
    append( a, '!' );
    cout << a << endl;
 
    cout << "Second" << endl;
    char    *b = new char[1];
    b[0] = NULL;
    append( b, '!' );
    cout << b << endl;
 
    return 0;
}

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: ポインタの操作でつまづきました

#9

投稿記事 by みけCAT » 10年前

newSに代入されたポインタの指す領域が解放されないと思います。
また、deleteの使い方が不適切なままです。
softya(ソフト屋) さんが書きました:【追記】
配列のdeleteも不適切です。
「C++編(言語解説) 第12章 new/delete」
http://www.geocities.jp/ky_webid/cpp/language/012.html
このサイトは読みましたか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
usao
記事: 1889
登録日時: 11年前

Re: ポインタの操作でつまづきました

#10

投稿記事 by usao » 10年前

本件の質問内容が
>27行目で、sの内容は 0 なので、実行時エラーにはならないのでしょうか?
であったので,それに関して「解決」したということなのでしょう.

で,それとは別に
>なにかNULLポインタと0とNUL文字がごっちゃになっている感じです。
とか
>配列のdelete
とかの,他の部分に関しては,
質問者様としては それらはこの場はそのままでOK ということなのか否か
という点が示されるとよいのではないでしょうか.

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: ポインタの操作でつまづきました

#11

投稿記事 by ISLe » 10年前

本(の著作者)の名誉を傷付けるのはフォーラムルール違反ではないかと思います。

アバター
usao
記事: 1889
登録日時: 11年前

Re: ポインタの操作でつまづきました

#12

投稿記事 by usao » 10年前

>本(の著作者)の名誉を傷付けるのはフォーラムルール違反ではないかと思います。

おっと,これは私のNo3の書き込み

>amazonの内容紹介を斜め読みしてみましたが…
>先に文法側をそれなりに固めた方が良いような予感も.

に対してのご指摘でしょうか.
(そうじゃなかったとしても)そのようにも読めてしまうので,意図したところをより明確に今一度書いておきますと,


その本の紹介文を見た限りだと「考え方」みたいなことに関する本のようです.
そういった考え方を学ぶのも有用だと思うけれども,そういった内容の本は,
少なくとも「基本的な文法的な面(No2で指摘されているような事柄とか)を把握したうえで」読む方がよいのではないか,と.

要するに,(誠に失礼ながら)質問者様の習得状況を提示コードから推し量るに,
組む上での考え方みたいなことよりも,最低限の文法を把握することをまず先にやらた方がよいのではないかな,という.
オフトピック
今度はなにやら すごく上から目線 な感じに見えてしまう文章に…

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: ポインタの操作でつまづきました

#13

投稿記事 by みけCAT » 10年前

softya(ソフト屋) さんが書きました:あとあと過去ログを見る人のために、不適切では無い書き方に修正したコードを張って頂けると助かります。
私はdicさんがこれに従ってコードを貼ったものとして問題点を指摘しましたが、
そもそもこのレス以降dicさんはコードのみを貼り付け、コード外のコメントは今のところ全くありません。
従って、dicさんの貼ったコードが本当にこれに従ったものなのかはわかりません。

よって、これらのコードが「不適切では無い書き方」かどうか、
もしくは「不適切では無い書き方に修正したコードを張って頂けると助かります。」という発言とは全く関係なく貼られたものなのか、
softya(ソフト屋)さんの判定を待ちたいと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: ポインタの操作でつまづきました

#14

投稿記事 by softya(ソフト屋) » 10年前

dic さんが書きました: delete の配列解放もたしかにおかしいですね
と書かれているので、これに関してはどうされたいのかお聞きしたい所です。
「どうでも良い」って返答でも良いので、その場合は正しい答えを誰かが投稿して過去ログとして役立つ形で終わりたいですね。
dicさんが正しいのを書いてくれるのが一番ですが。

NULLポインタや0やNUL文字に関しては元の書籍の内容が分からないので、意図して悪い例と書かれている可能性がありますね。
なので、出来ればdicさんが解説してくれると助かります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: ポインタの操作でつまづきました

#15

投稿記事 by ISLe » 10年前

単純にひどいコードなので、このまま終わるとそれは本のせいかもという疑惑が残ります。

むしろusaoさんの指摘に賛成です。
せめて見た目だけでもきちんとして欲しい。

閉鎖

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