新たに作ったLPWSTRの内容を、あらかじめ用意しておいたLPWSTRにコピーしたいのですが、うまくいきません。
どうするのが正解なのでしょうか。
簡易化したソースコードと失敗例を載せておきます。
(見やすくするために行頭に全角スペースを入れています。)
class LPWSTR_Copy{
public:
LPWSTR lpwstr;
public:
// lpwstrにNewStrをコピーしたい
void StrCopy( LPWSTR NewStr){
// lpwstr= NewStr; // 失敗
// lstrcpy( lpwstr, NewStr); // 失敗
/* TCHAR tchar[20];
lstrcpy( tchar, NewStr);
lpwstr= tchar;
*/ // 失敗
/* lpwstr= new TCHAR[sizeof(NewStr)];
lstrcpy( lpwstr, NewStr);
*/ // 失敗(実行時エラー)
}
};
void copy(LPWSTR_Copy *str){
LPWSTR newstr= TEXT("コピー元文字列");
str->StrCopy(newstr);
}
void main(){
LPWSTR_Copy strcpy;
copy(&strcpy);
LPWSTR str= strcpy.lpwstr;
// ↑ここでstr.lpwstrの中身が"コピー元文字列"となっていてほしい
}
No.1
- 回答日時:
お疲れ様です。
まず、お伺いしたいのが、「lpwstr= NewStr; 」で失敗していると言う事ですが、どう失敗しているのでしょうか?
理論上はこれでうまく行くはずです。
([Visual C++ Express Edition] + [Windows Visuta])でコンパイルしデバックモードで追っかけて問題が無い事も確認済み。
(copy関数内のnewstrはデータ領域に生成された文字列「コピー元文字列」の先頭アドレスを指しています。)
(LPWSTR_Copy::StrCopy関数は引数でもらってきた、スタック領域の先頭アドレスをきちんとlpwstrにコピーしています。)
ちなみに、こんなクラスの作り方はまずしません。
「静的領域・データ領域・スタック領域・ヒープ領域」等のメモリ区分についてご理解はありますか?
この回答への補足
回答ありがとうございます。
「lpwstr= NewStr;」について補足します。
void copy(LPWSTR_Copy *str)を抜けたとき、copy()の内部で作られたnewstrは消滅します。
するとnewstrのアドレスをコピーしたlpwstrも消えてしまう、ということです。
このクラスを作った理由は、vector<LPWSTR>で失敗したからです。
メモリ区分についてはよく知りません。ざっと調べた限りでは、
・プログラム領域:関数
・静的領域:グローバル変数、static変数用
・スタック領域:自動変数などの自動的に消える変数用
・ヒープ領域:ポインタにnewで割り当てた領域
・データ領域:?
という感じでしょうか。
下により原型に近いソースを書いておきます。
class LPWSTR_Copy{
public:
LPWSTR lpwstr;
public:
// lpwstrにNewStrをコピーしたい
void StrCopy( LPWSTR NewStr){
// どうにかこうにか
}
LPWSTR_Copy( LPWSTR lpw){
StrCopy(lpw);
}
/* そのほかの関数
void operator=( LPWSTR lpw);
operator LPWSTR();
*/
};
class UseLSC{
public:
vector<LPWSTR_Copy> vlc;
void In(){
WCHAR wc[20];
for( int i=0; i<20; i++){
wsprintf( wc, "a_%02d_", i);
vlc.push_back(wc);
}
return; // この地点でvlcの中身は全て"a_19_"。連番になってほしい。
}
void Make(){
In();
return; // この地点でvlcの中身は全て""。
}
}
void main(){
UseLSC use;
use.Make();
}
ちなみに、for文ではなく
vlc.resize(20);
vlc[0]= TEXT("a_00_");
vlc[1]= TEXT("a_01_");
vlc[2]= TEXT("a_02_");
...
と書けば一応うまくいきます。
しかし、総数が増えた場合を考えるとこれは避けたいのです。
No.2
- 回答日時:
えーと
こんなクラスの作り方しないのは#1の方と同意です。笑
他の視点から気付いたのでそれを挙げますね。
LPWSTRを使っているならそれに統一すべきです。
なぜTCHARやTEXTを使ってるのでしょうか?
_T、TEXT、TCHARマクロは
UNICODEを定義するかしないかでCHAR、TCHARまたはLPSTRとLPWSTRを切り替えてくれるマクロです。
LPWSTRにするのであれば
L"文字列"
とLをつけるだけです。
Program Tips - UNICODE
http://www.246.ne.jp/~y-ookubo/program/tips/unic …
>こんなクラスの作り方
「vector<LPWSTR> vlc;」としたときと全く同じ挙動。つまり無意味ということ…。
たしか「クラス化してコピーコンストラクタ内でnewすれば新しい領域が取られるから、コピーしてからコピー元が消えても大丈夫かもしれない…」と思って作ったんです。
この方法はコピーはうまくいったんですが、その後にエラーが発生しました。
>TEXTマクロ
調べました。
TEXTマクロはLPWSTRではなくLPTSTRじゃないと意味なさそうですね。
WCAHRとTCHARの違いが分かってませんでした。勉強になります。
No.3ベストアンサー
- 回答日時:
まず、クラスの作り方で違うという意味については
C++で追加されたクラスという物は、データとそのデータを扱う関数をセットにしたものです。
よって、文字列をコピーするだけのクラスというものは意味がありません。
ということで、とりあえず動くものを添付します。
#include <windows.h>
#include <iostream>
#include <vector>
class cstring{
private:
LPWSTR lpwstr;
public:
cstring(){
lpwstr = NULL;
}
~cstring(){
lpwstr = NULL;
}
cstring( LPWSTR NewStr){
lpwstr = NULL;
lpwstr= new TCHAR[wcslen(NewStr)+1];
lstrcpy( lpwstr, NewStr);
}
const LPWSTR chr(){
return lpwstr;
}
void operator=( LPWSTR NewStr){
if (lpwstr != NULL) {
delete []lpwstr;
}
lpwstr= new TCHAR[wcslen(NewStr)+1];
lstrcpy( lpwstr, NewStr);
}
};
class UseLSC{
public:
std::vector<cstring> vlc;
void In(){
WCHAR wc[20];
for( int i=0; i<20; i++){
wsprintf( wc, L"a_%02d_", i);
vlc.push_back(wc);
}
}
void Make(){
In();
}
};
int main(){
int i;
setlocale( LC_ALL, "Japanese" );
UseLSC use;
use.Make();
for ( i=0; i<20; i++ ){
wprintf(L"%s\n", use.vlc[i].chr());
}
}
私も汎用機の世界でしか仕事をしていないので、TCHAR等のマクロやUnicodeプログラミングの世界については分からないので、少し不安な箇所もあります。。。
出来ました!
コピーコンストラクタでnewを使い割り当てるのが正解のようです。
最初に実行時エラーになったのは、
lpwstr= new TCHAR[lstrlen(NewStr)+1];
とすべきところを
lpwstr= new TCHAR[sizeof(NewStr)];
としていたからのようです。
http://www.pro.or.jp/~fuji/mybooks/cdiag/cdiag.7 …
などを見ると結果同じだと思ったのですが。
なにはともあれ解決しました。
ありがとうございました!
No.4
- 回答日時:
>>「lpwstr= NewStr;」について補足します。
>>void copy(LPWSTR_Copy *str)を抜けたとき、copy()の内部で
>>作られたnewstrは消滅します。
>>するとnewstrのアドレスをコピーしたlpwstrも消えてしまう、
>>ということです。
>>このクラスを作った理由は、vector<LPWSTR>で失敗したから
>>です。
>>メモリ区分についてはよく知りません。ざっと調べた限りでは、
>>・プログラム領域:関数
>>・静的領域:グローバル変数、static変数用
>>・スタック領域:自動変数などの自動的に消える変数用
>>・ヒープ領域:ポインタにnewで割り当てた領域
>>・データ領域:?
>>という感じでしょうか。
補足します。
「データ領域」という言葉で正しかったかどうか調べてみましたが、ちょっと分かりませんでした。(申し訳ありません)
調べてみる限りでは「プログラム領域」で正しいような感じです。
これを踏まえて最初にご提示頂いたソースコートではcopy関数で記述されている「TEXT("コピー元文字列")」の文字列の実体は書換え不可能なプログラム領域に置かれます。
([Visual C++]+windowsの場合)
「newstrは消滅します」と記載されている内容は正しいのですが、消滅するまえに、lpwstrへ文字列の先頭アドレスをコピー出来ているため問題ありません。
以上。
NewStrが消えても中の文字列はメモリに残留し、そのアドレスを保持するlpwstrから参照できる…と思うのですが、どうもうまく出来ません。
全要素が同じ内容になるのは同じアドレスを使っているからまあいいとして、消滅後に参照できない問題は解決していません。
LPWSTR newstr= TEXT("コピー元文字列")
はスタック領域に取られるのでは?
そして他の自動変数などが領域を取る際、かつてのnewstrと同じ~+xバイトのアドレス位置に取ると、そこにあった文字列は破壊されます。
するとlpwstrからアクセスできるなら"コピxxx..."みたいになってしまうため、これを防ぐためにアクセス禁止にしているのだと思います。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# C# で、あるフォルダー内にあるすべてのテキストファイルを別のフォルダーにコピーする。 4 2022/11/21 13:23
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- JavaScript javascriptのちょっとした動作不良(原因は突き止めたのですが) 1 2023/06/15 19:58
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- Excel(エクセル) Excei で、項目の横展開 2 2023/07/15 09:56
- C言語・C++・C# C#テキストボックスの文字を配列にいれてその後表示する 4 2022/07/17 04:47
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- Chrome(クローム) 【 Chrome 】鎖のアイコンの「Copy Link Text」が機能しなくなりました。 1 2023/03/27 10:32
- Excel(エクセル) エクセル VBAの構文について 2 2023/02/10 18:26
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
mallocについて
-
C言語 mallocとfreeについて
-
newしないオブジェクトについて
-
C++で、メンバもヒープに確保さ...
-
スタック破壊の上手な見つけ方...
-
HEAP に関すること
-
構造体でchar name[]と*nameの...
-
ビットをローテートするプログ...
-
C++のnewで確保したメモリーの...
-
OpenCV cvLoadImageについて
-
配列の添え字の最大数とは?
-
allocってなんですか?
-
メモリ不足になってしまう。
-
ヒープメモリの解放について
-
画像を読み込む配列の確保。
-
MSDNがgethostbynameではなくge...
-
malloc呼び出し時のセグメンテ...
-
C言語 配列の長さの上限
-
セグメントエラー
-
ファイル名「1.jpg ~10.jpg~...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
mallocについて
-
c言語のポインタへの文字列入力...
-
allocってなんですか?
-
newしないオブジェクトについて
-
ヒープメモリの解放について
-
C++で、メンバもヒープに確保さ...
-
MSDNがgethostbynameではなくge...
-
プログラムが途中で強制終了し...
-
配列の添え字の最大数とは?
-
Accessで、メモリを開放するタ...
-
ヒープ領域の限界値設定
-
malloc呼び出し時のセグメンテ...
-
スタック破壊の上手な見つけ方...
-
C言語 mallocとfreeについて
-
指定したメモリアドレスの値の...
-
stringの最大サイズ
-
16進ダンプのプログラム
-
64ビットと32ビットの違い
-
入れ子になった構造体について
-
free関数で動作が止まる
おすすめ情報