クラス内のポインターを含むガベージ、C ++
-
03-07-2019 - |
質問
Borland Builder C ++を使用しています。メモリリークがあり、作成したこのクラスが原因であるに違いないことはわかっていますが、修正方法はわかりません。私のコードを見てください-どんなアイデアでも大歓迎です!
.hファイルは次のとおりです。
#ifndef HeaderH
#define HeaderH
#include <vcl.h>
#include <string>
using std::string;
class Header {
public:
//File Header
char FileTitle[31];
char OriginatorName[16];
//Image Header
char ImageDateTime[15];
char ImageCordsRep[2];
char ImageGeoLocation[61];
NitfHeader(double latitude, double longitude, double altitude, double heading);
~NitfHeader();
void SetHeader(char * date, char * time, double location[4][2]);
private:
void ConvertToDegMinSec (double angle, AnsiString & s, bool IsLongitude);
AnsiString ImageDate;
AnsiString ImageTime;
AnsiString Latitude_d;
AnsiString Longitude_d;
double Latitude;
double Longitude;
double Heading;
double Altitude;
};
そして、ここにいくつかの.cppファイルがあります:
void Header::SetHeader(char * date, char * time, double location[4][2]){
//File Header
strcpy(FileTitle,"Cannon Powershot A640");
strcpy(OperatorName,"Camera Operator");
//Image Header
//Image Date and Time
ImageDate = AnsiString(date);
ImageTime = AnsiString(time);
AnsiString secstr = AnsiString(ImageTime.SubString(7,2));
AnsiString rounder = AnsiString(ImageDate.SubString(10,1));
int seconds = secstr.ToInt();
//Round off seconds - will this be necessary with format hh:mm:ss in text file?
if (rounder.ToInt() > 4) {
seconds++;
}
AnsiString dateTime = ImageDate.SubString(7,4)+ ImageDate.SubString(4,2) + ImageDate.SubString(1,2) + ImageTime.SubString(1,2)
+ ImageTime.SubString(4,2) + AnsiString(seconds);
strcpy(ImageDateTime,dateTime.c_str());
//Image Coordinates Representation
strcpy(ImageCordsRep,"G");
//Image Geographic Location
AnsiString lat;
AnsiString lon;
AnsiString locationlat_d;
AnsiString locationlon_d;
AnsiString corner;
for (int i = 0; i < 4; i++){
ConvertToDegMinSec(location[i][0],lat,false);
ConvertToDegMinSec(location[i][1],lon,true);
if(location[i][0] < 0){
locationlat_d = 'S';
ConvertToDegMinSec(-location[i][0],lat,false);
}else if(location[i][0] > 0){
locationlat_d = 'N';
}else locationlat_d = ' ';
if(location[i][1] < 0){
locationlon_d = 'W';
ConvertToDegMinSec(-location[i][1],lon,true);
}else if(location[i][1] > 0){
locationlon_d = 'E';
}else locationlon_d = ' ';
corner += lat + locationlat_d + lon + locationlon_d;
}
strcpy(ImageGeoLocation,corner.c_str());
}
メインでクラスを使用するとき、基本的にはポインタを作成するだけです:
Header * header = new Header;
header->SetHeader(t[5],t[6],corners->location);
char * imageLocation = header->ImageGeoLocation;
//do something with imageLocation
delete header;
コーナー-&gt;場所は別のクラスの文字列であり、t [5]とt [6]は両方とも文字列です。問題は、imageLocationに期待されるものが含まれておらず、多くの場合、単なるゴミであるということです。私はメモリリークとポインタについて多くのことを読みましたが、私はまだプログラミングが非常に新しく、その一部は非常に混乱しています。どんな提案でも素晴らしいでしょう!!
解決
ここには多くの問題があると思う。
初心者の場合 char ImageCordsRep [1];
は機能しません...文字列は常にヌルで終了するため、 strcpy(ImageCordsRep、&quot; G&quot;);
バッファがオーバーフローしています。
これらのすべての文字列バッファをコンストラクタでnullで終了することもお勧めです。したがって、これらは常に有効な文字列です。
さらに良いのは、char配列の代わりに文字列クラスを使用するか、少なくとも 'strncpy'を使用して、着信文字列が予想よりも大きい場合にバッファオーバーランを防ぐことです。
他のヒント
メモリリークは main
にあります。 new
でポインターを作成していますが、その後 delete
を呼び出していません。
main
の終了時に破棄されるタイプ Header
のオブジェクトを作成する場合は、単に&quot; Header header;として宣言します。
&quot;永続的なポインターを作成する場合は、 new
を使用する必要がありますが、 delete header;
およびプログラムの終了前のいくつかのポイントを確認してください。
ImageGeoLocationがゴミか、メモリリークが問題ですか?
コードがそのように書かれている場合:
Header * header = new Header;
header->SetHeader(t[5],t[6],corners->location);
char * imageLocation = header->ImageGeoLocation;
delete header;
printf("ImageLocation is %s", imageLocation);
問題はメモリリークではなく、imageLocationの下からメモリを削除していることです。 ImageLocationは単なるポインターであり、実際にはデータを含んでおらず、それを指しているだけです。したがって、データを削除すると、ポインターはゴミ箱を指します。
そうでない場合は、SetHeaderメソッドをデバッグします。 ImageGeoLocationに期待どおりのデータが入力されていますか?そうである場合、後でImageGeoLocationを損傷するいくつかの省略されたコードがない限り、imageLocationは有効なデータを指す必要があります。 ImageGeoLocationを見るウィンドウがコードをステップスルーして、どの行が予想外のImageGeoLocationを実際に変更するかを確認できるため、メモリが役立ちます。
strcpy()
を strncpy()
に変更し、問題を解決しました。
その他...
ヘッダーオブジェクトが削除された後、imageLocationを使用しないように注意してください。多くの場合、オブジェクトへのポインタを取得するよりも、オブジェクトから文字列をコピーする方が適切です。この場合、残りのコードによっては問題ない場合があります。
Header * header = new Header;
header->SetHeader(t[5],t[6],corners->location);
char * imageLocation = header->ImageGeoLocation;
ご返信ありがとうございます、Torlack、その他の方々。基本的に、imageLocationは、前に他のコードがない限り、正常に入力されます。たとえば、この文字列リストには基本的にファイル名が含まれています。
AnsiString fileType ("*.jpg");
AnsiString path = f + fileType;
WIN32_FIND_DATA fd;
HANDLE hFindJpg = FindFirstFile(path.c_str(),&fd);
//Find all images in folder
TStringList * imageNames = new TStringList;
if (hFindJpg != INVALID_HANDLE_VALUE) {
do{
if(!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
image = AnsiString(fd.cFileName);
imageNames->Add(image);
jpgFileCount++;
}
}while(FindNextFile(hFindJpg,&fd));
}else ShowMessage ("Cannot find images.");
FindClose(hFindJpg);
リストの画像を直前に参照しようとすると、imageLocation内に画像の名前が表示されます。
//char * imageLocation = header->ImageGeoLocation; //as expected
Image1->Picture->LoadFromFile(imageNames->Strings[j]);
char * imageLocation = header->ImageGeoLocation; //puts name of jpg file in imageLocation