Файл забивается мусором, а при завершении программы происходит аварийная остановка

Пытался написать свой тип файла позволяющий хранить в нём другие файлы.

P.S. Я никогда таким не занимался и делаю это впервые, прошу не швыряться тапками.

Компилируется все замечательно, но падает с ошибкой free(): double free detected in tcache 2 Аварийный останов (стек памяти сброшен на диск)

Всего в проекте 3 файла

main.cpp

#include <iostream>
#include "gymfile.h"

 int main()
 {
    gymdata teser("Hello hi","Some data");
    gymdata ass("Another File","Some data");

    gymfile test("gamefile.gym",false);

    test.writeData(teser);    
    test.writeData(ass);

    test.closeFile();

    gymfile testa("gamefile.gym",true); 
    gymdata popka(testa.getData(0));    

 }

gymdata.h

#define GYMD
#ifdef GYMD

class gymdata
{
    protected:
    char name[255];
    std::vector <char> rawdata;
    
    public:
    char *getData(){
        return &rawdata[0];
    }
    char *getName(){
        return name;
    }
    void setName(char *nname){
        strcpy(name,nname);
    }
    void resize(int size){
        rawdata.resize(size);
    }
    void addbyte(char byte){
        resize(rawdata.size()+1);
        rawdata[rawdata.size()]=byte;
    }
    int getArraySize(){
        return rawdata.size();
    }
    gymdata(const char *nname,const char *dt=""){
        if(strlen(nname)>255) return;
        if (strcmp(dt,"")==0) return;
        memset(name,0,255);
        strcpy(name,nname);
        resize(strlen(dt));
        for(int i=0;i<=(strlen(dt));i++){
            rawdata[i]=dt[i];
        }
    }
    gymdata(const gymdata &dtb){
        rawdata.resize(dtb.rawdata.size()+1);
        rawdata = dtb.rawdata;
        strcpy(name,dtb.name);
    }
};
#endif

gymfile.h

#define GYMF
#ifdef GYMF
#include <fstream>
#include <string>
#include <vector>
#include <cstring>
#include <cstdio>
#include "gymdata.h"
class gymfile{
    private:
    std::uint16_t files[1024];
    char name[255];
    FILE *writef;
    FILE *readf;
    std::string fname;
    bool newfile{false};
    bool rw;
    
    std::uint16_t getFileStartAddr(int fn){
        if (fn>511) return 0;
        return files[fn*2];
    }
    std::uint16_t getFileEndAddr(int fn){
        if(fn>511) return 0;
        return files[fn*2+1];
    }
    public:
    void openFileWrite(std::string name){
        for(int i=0; i<=1024; i++){
            files[i]=0;
        }
        fname=name;
        writef = fopen(name.c_str(),"wb");
        if(fopen(name.c_str(), "wb")==NULL){
            fclose(writef);
            return;
        }
        fseek(writef,0,SEEK_END);
        if(2048>ftell(writef)){
            newfile=true;
        }
        fseek(writef,0,SEEK_SET);
    }

    void openFileRead(std::string name){
        for(int i=0; i<=1024; i++){
            files[i]=0;
        }
        readf = fopen(name.c_str(),"rb");
        fread(files,sizeof(std::uint16_t),1024,readf);
    }

    void closeFile(){
        if (rw==true) fclose(writef); else
        fclose(readf);
    }


    gymdata getData(int filen){
        if (getFileStartAddr(filen)==0) return gymdata("Unknown File","This file not exists");
        char filname[255];
        fseek(readf,getFileStartAddr(filen),SEEK_SET);
        fread(filname,sizeof(char),255,readf);
        fseek(readf,256,SEEK_CUR);
        std::vector<char> data;
        data.resize(getFileEndAddr(filen)-getFileStartAddr(filen));
        memset(&data[0],0,data.size());
        fread(&data[0],sizeof(char),getFileEndAddr(filen)-getFileStartAddr(filen),readf);
        std::cout<<filname<<"\n"<<&data[0]<<std::endl;
        return gymdata(filname,&data[0]);
    }
    gymdata getData(char *filen){

    }
    void writeData(gymdata dat){
        fseek(writef,0,SEEK_SET);
        int i=0;
        while(i!=1024 && files[i]!=0){
            i++;
        }
        if(i-1<0){
            files[i]=2049;
            files[i+1]=files[i]+dat.getArraySize()+255;
            fseek(writef,2049,SEEK_SET);
        } else{
            files[i]=files[i-1]+1;
            files[i+1]=files[i]+dat.getArraySize()+255;
            fseek(writef,files[i-1]+1,SEEK_SET);
        }
        fwrite(dat.getName(),sizeof(char),255,writef);
        fseek(writef,256,SEEK_CUR);
        fwrite(dat.getData(),sizeof(char),dat.getArraySize(),writef);
        sync();
    }
    void sync(){
        fseek(writef,0,SEEK_SET);
        fwrite(files,sizeof(std::uint16_t),1024,writef);
    }
    gymfile(std::string finame="",bool read=true){
        if(read){
            rw=false;
        }else{
            rw=true;
        }
        if(finame!=""){
            if(!read){
                openFileWrite(finame);
            } else{
                openFileRead(finame);
            }
        }
    }

    ~gymfile(){
        closeFile();
    }
};
#endif

Ответы (2 шт):

Автор решения: KoVadim

Первая ошибка здесь

resize(strlen(dt));
for(int i=0;i<=(strlen(dt));i++){
    rawdata[i]=dt[i];
}

либо в resize(strlen(dt)); на одиницу больше, либо цикл исправьте.

Во вторых - инициализируйте свои переменные. Всегда. Потому что fclose, который получил шальной указатель, не будет работатать

he behavior is undefined if the value of the pointer stream is used after fclose returns.

А также, fclose не любит nullptr.

Вывод - используйте плюсовые классы и функции и будет и понятнее, и проще.

→ Ссылка
Автор решения: Никита Самоуков

Этот код врятли удастся заставить работать когда-либо. В нём почти в каждой строке есть ошибка.

Причём некоторые специально добавлены: for(int i=0; i<=1024; i++)

Вот списочек, и это только то, что смог найти сам компилятор.

Серьезность Код Описание    Проект  Файл    Строка  Состояние подавления
Предупреждение  C26447  Функция объявлена как "noexcept", но вызывает функцию "closeFile()", которая может порождать исключения (f.6).  Test    F:\f_prog\repos\Test\Test\Test.cpp  134 Активные
Предупреждение  C26440  Функция "main" может быть объявлена как "noexcept" (f.6).   Test    F:\f_prog\repos\Test\Test\Test.cpp  138 Активные
Предупреждение  C26440  Функция "gymfile::sync" может быть объявлена как "noexcept" (f.6).  Test    F:\f_prog\repos\Test\Test\Test.cpp  114 Активные
Предупреждение  C26440  Функция "gymfile::openFileRead" может быть объявлена как "noexcept" (f.6).  Test    F:\f_prog\repos\Test\Test\Test.cpp  64  Активные
Предупреждение  C26440  Функция "gymfile::getFileStartAddr" может быть объявлена как "noexcept" (f.6).  Test    F:\f_prog\repos\Test\Test\Test.cpp  38  Активные
Предупреждение  C26440  Функция "gymfile::getFileEndAddr" может быть объявлена как "noexcept" (f.6).    Test    F:\f_prog\repos\Test\Test\Test.cpp  42  Активные
Предупреждение  C26440  Функция "gymfile::getData" может быть объявлена как "noexcept" (f.6).   Test    F:\f_prog\repos\Test\Test\Test.cpp  91  Активные
Предупреждение  C26440  Функция "gymfile::closeFile" может быть объявлена как "noexcept" (f.6). Test    F:\f_prog\repos\Test\Test\Test.cpp  72  Активные
Предупреждение  C26440  Функция "gymdata::gymdata" может быть объявлена как "noexcept" (f.6).   Test    F:\f_prog\repos\Test\Test\Test.cpp  22  Активные
Предупреждение  C26440  Функция "gymdata::getName" может быть объявлена как "noexcept" (f.6).   Test    F:\f_prog\repos\Test\Test\Test.cpp  23  Активные
Предупреждение  C26440  Функция "gymdata::getData" может быть объявлена как "noexcept" (f.6).   Test    F:\f_prog\repos\Test\Test\Test.cpp  25  Активные
Предупреждение  C26440  Функция "gymdata::getArraySize" может быть объявлена как "noexcept" (f.6).  Test    F:\f_prog\repos\Test\Test\Test.cpp  24  Активные
Предупреждение  C26495  Переменная "gymfile::files" не инициализирована. Всегда инициализируйте переменную-член (type.6).   Test    F:\f_prog\repos\Test\Test\Test.cpp  118 Активные
Предупреждение  C26455  Конструктор по умолчанию не может выдавать исключения (throw). Объявите его как "noexcept" (f.6).   Test    F:\f_prog\repos\Test\Test\Test.cpp  118 Активные
Предупреждение  C26477  Используйте "nullptr" вместо 0 или NULL (es.47).    Test    F:\f_prog\repos\Test\Test\Test.cpp  23  Активные
Предупреждение  C26477  Используйте "nullptr" вместо 0 или NULL (es.47).    Test    F:\f_prog\repos\Test\Test\Test.cpp  53  Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  40  Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  44  Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  49  Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  66  Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  86  Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  87  Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  88  Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  89  Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  97  Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  101 Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  102 Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  102 Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  105 Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  105 Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  106 Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  106 Активные
Предупреждение  C26446  Использовать gsl::at() вместо непроверенного оператора с нижним индексом (bounds.4).    Test    F:\f_prog\repos\Test\Test\Test.cpp  107 Активные
Предупреждение  C6201   Индекс "1024" находится вне диапазона от "0" до "1023" для буфера "this->files", возможно, размещенного в стеке.    Test    F:\f_prog\repos\Test\Test\Test.cpp  49  Активные
Предупреждение  C6201   Индекс "1024" находится вне диапазона от "0" до "1023" для буфера "this->files", возможно, размещенного в стеке.    Test    F:\f_prog\repos\Test\Test\Test.cpp  66  Активные
Предупреждение  C26432  Если вы определяете или удаляете какие-либо операции по умолчанию в типе "class gymfile", определите или удалите их все (c.21). Test    F:\f_prog\repos\Test\Test\Test.cpp  133 Активные
Предупреждение  C26485  Выражение "this->files": не допускайте вырождения массива в указатель (bounds.3).   Test    F:\f_prog\repos\Test\Test\Test.cpp  69  Активные
Предупреждение  C26485  Выражение "this->files": не допускайте вырождения массива в указатель (bounds.3).   Test    F:\f_prog\repos\Test\Test\Test.cpp  116 Активные
Предупреждение  C26485  Выражение "filname": не допускайте вырождения массива в указатель (bounds.3).   Test    F:\f_prog\repos\Test\Test\Test.cpp  82  Активные
Предупреждение  C26485  Выражение "filname": не допускайте вырождения массива в указатель (bounds.3).   Test    F:\f_prog\repos\Test\Test\Test.cpp  88  Активные
Предупреждение  C26485  Выражение "filname": не допускайте вырождения массива в указатель (bounds.3).   Test    F:\f_prog\repos\Test\Test\Test.cpp  89  Активные
Предупреждение  C26482  В качестве индексов массивов используйте только константные выражения (bounds.2).   Test    F:\f_prog\repos\Test\Test\Test.cpp  40  Активные
Предупреждение  C26482  В качестве индексов массивов используйте только константные выражения (bounds.2).   Test    F:\f_prog\repos\Test\Test\Test.cpp  44  Активные
Предупреждение  C26482  В качестве индексов массивов используйте только константные выражения (bounds.2).   Test    F:\f_prog\repos\Test\Test\Test.cpp  49  Активные
Предупреждение  C26482  В качестве индексов массивов используйте только константные выражения (bounds.2).   Test    F:\f_prog\repos\Test\Test\Test.cpp  66  Активные
Предупреждение  C26482  В качестве индексов массивов используйте только константные выражения (bounds.2).   Test    F:\f_prog\repos\Test\Test\Test.cpp  97  Активные
Предупреждение  C26482  В качестве индексов массивов используйте только константные выражения (bounds.2).   Test    F:\f_prog\repos\Test\Test\Test.cpp  101 Активные
Предупреждение  C26482  В качестве индексов массивов используйте только константные выражения (bounds.2).   Test    F:\f_prog\repos\Test\Test\Test.cpp  102 Активные
Предупреждение  C26482  В качестве индексов массивов используйте только константные выражения (bounds.2).   Test    F:\f_prog\repos\Test\Test\Test.cpp  105 Активные
Предупреждение  C26482  В качестве индексов массивов используйте только константные выражения (bounds.2).   Test    F:\f_prog\repos\Test\Test\Test.cpp  106 Активные
Предупреждение  C26482  В качестве индексов массивов используйте только константные выражения (bounds.2).   Test    F:\f_prog\repos\Test\Test\Test.cpp  107 Активные

Вывод: Использование в С++ функций из C не привело ни к чему хорошему.

→ Ссылка