Мусор с указателями в классе, C ++ - PullRequest
0 голосов
/ 02 октября 2008

Я использую 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());

}  

Теперь, когда я использую класс в main, я просто создаю указатель:

Header * header = new Header;
header->SetHeader(t[5],t[6],corners->location);
char * imageLocation = header->ImageGeoLocation;
//do something with imageLocation
delete header;

Где угол-> расположение - строка из другого класса, а t [5] и t [6] - строки. Проблема в том, что imageLocation не содержит того, что ожидается, и часто просто мусор. Я много читал об утечках памяти и указателях, но я все еще плохо знаком с программированием, и некоторые из них довольно запутанные. Любые предложения будут сказочными !!

Ответы [ 6 ]

5 голосов
/ 02 октября 2008

Боюсь, здесь есть ряд проблем.

Для начала char ImageCordsRep[1]; не работает ... строка всегда заканчивается нулем, поэтому, когда вы делаете strcpy(ImageCordsRep,"G");, вы переполняете буфер.

Было бы также неплохо завершить все эти строковые буферы нулем в вашем конструкторе, чтобы они всегда были допустимыми строками.

Еще лучше было бы использовать строковый класс вместо массивов символов или, по крайней мере, использовать strncpy, чтобы предотвратить переполнение буфера, если входящие строки больше, чем вы ожидаете.

2 голосов
/ 02 октября 2008

Ваша утечка памяти в main; вы делаете указатель с new, но впоследствии не вызываете delete.

Если вы хотите просто создать объект типа Header, который будет уничтожен при выходе из main, просто объявите его как "Header header;". Если вы хотите создать постоянный указатель, вы должны использовать new как вы делаете, но не забудьте delete header; и некоторые точки до окончания программы.

1 голос
/ 02 октября 2008

Я изменил strcpy() на strncpy(), и это решило мою проблему.

1 голос
/ 02 октября 2008

Ваша проблема в том, что 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 данными, как вы ожидаете? Если это так, то imageLocation должен указывать на действительные данные, если только не будет пропущен некоторый код, который позже повреждает ImageGeoLocation. Память, какое окно, смотрящее на ImageGeoLocation, может помочь, так как вы сможете просмотреть свой код и посмотреть, какая строка на самом деле меняет ImageGeoLocation там, где вы этого не ожидаете.

0 голосов
/ 02 октября 2008

Спасибо, Торлак и другие за быстрый ответ. По сути, 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
0 голосов
/ 02 октября 2008

Что-то еще ...

Будьте осторожны, чтобы не использовать imageLocation после удаления объекта заголовка. Часто лучше скопировать строку из объекта, а не получить указатель на него. В этом случае все может быть в порядке в зависимости от остальной части кода.

Header * header = new Header;
header->SetHeader(t[5],t[6],corners->location);
char * imageLocation = header->ImageGeoLocation;
...