2017-11-19 9 views
-1

クラス:Valgrindのの不正な書き込み

class Tile { 
public: 
    long long size, joint; 
}; 

私の主が持っている:ここ

int main() { 
    // 
    double minW, minL; 
    unsigned tileCap = 10, tileCount = 0; 
    bool wasTransformed = false; 
    auto *tiles = (Tile*)calloc(tileCap, sizeof(Tile)); 

    GetInput(&minW, &minL, &tiles, &tileCount, &wasTransformed); 

    //etc. 
} 

問題の関数はGetInput()です:

void GetInput(double *w, double *l, Tile **tiles, unsigned *tileCount, bool *needTransform) { 
    // 
    printf("Min dimensions:\n"); 

    if (scanf("%lf %lf", w, l) != 2) 
    BadInput(); 
    if (!CorrectSize(*w) || *w == 0) 
    BadInput(); 
    if (!CorrectSize(*l) || *w == 0) 
    BadInput(); 

    unsigned tileCap = 10; 
    *tiles = (Tile*)calloc(tileCap, sizeof(Tile)); 

    printf("Tiles:\n"); 
    double tileSize, tileJoint; 
    int argc; 

    do { 
    argc = scanf("%lf %lf", &tileSize, &tileJoint); 
    if(argc == EOF) { 
     break; 
    } 
    if (tileSize == 0 || !CorrectSize(tileSize) || !CorrectSize(tileJoint) || argc != 2) 
     BadInput(); 

    if(! *needTransform) { 
     *needTransform = HasFloatingPoint(tileSize) || HasFloatingPoint(tileJoint); 
     if(*needTransform) 
     TransformPrevious(*tiles, *tileCount); 
    } 
    if(*needTransform) { 
     //transform this 
     tileSize *= 10; 
     tileJoint *= 10; 
    } 

    (*tiles)[*tileCount].size = (long long)tileSize + (long long)tileJoint; 
    (*tiles)[*tileCount].joint = (long long)tileJoint; 

    *tileCount += 1; 
    if((*tileCount) == tileCap) { 
     DoubleArray(tiles, &tileCap); 
    } 
    } while(true); 
} 

そして、私のDoubleArray()

void DoubleArray(Tile **array, unsigned *cap) { 
    // 
    auto *tmp = (Tile*)realloc(*array, 2 * sizeof(Tile)); 

    if(tmp) { 
    *array = tmp; 
    *cap *= 2; 
    (*cap)--; 
    } else { 
    printf("Error allocating memory.\n"); 
    } 
} 

プログラムを実行するとエラーは表示されず、結果は正しいようです。たとえば、次のように12.3 0プリントInvalid write of size 8

360 217 
0.1 0.0 
0.2 0.0 
0.3 0.0 
0.4 0.0 
0.6 0.0 
0.8 0.0 
1.2 0.0 
2.4 0.0 
4.1 0.0 
8.2 0.0 
12.3 0.0 
16.4 0.0 
24.6 0.0 
32.8 0.0 
49.2 0.0 

Valgrindの。だから私は間違ってメモリを再割り当てしているようだ。しかしもし私がそうであれば、それらを印刷すると値が正常に読み込まれるのはなぜですか?つまり、すべての入力がアレイに正しくロードされます。

私は間違って何をしていますか? memsetを使用していますか? freeは正しくありませんか?

+1

あなたの質問はC++をタグ付けされている)あなたがmemsetをする必要があるかもしれないので、余分なメモリが初期化されていないことになる

*cap *= 2; auto *tmp = (Tile*)realloc(*array, *cap * sizeof(Tile)); 

(のようなものを書く必要がありますが、あなたは、Cライブラリ関数を集中的に使用してください。 'calloc'と' free'は通常の使用の場合には使用しないでください(あなたが専用のアロケータまたは 'operator new'関数を書いている場合を除きます)。とにかく、ポインタを再利用する前に割り当てられたメモリを解放することは決してありません。また、 'DoubleArray'では、配列の容量を倍増する前に元のサイズ*を割り当てるようです。簡単に言えば、 'std :: vector'を使うか、より簡単な例で低レベルのCの割り当て関数を使う方法を学んでください。 –

+0

@SergeBallestaなぜ私はそれを再利用しているときに配列をフリーズする必要がありますか?それまでは 'memset'を使って設定しました。それは間違っていますか? 'vector'は許されないのでCライブラリ関数を使っています。タグが修正されました。 –

+0

Cの場合は、[mallocをキャストしない](https://stackoverflow.com/q/605845/3545273)。あなたは 'tiles'とmainをcallocし、' GetInput'で再びcallocします。元のブロックはリークします。 –

答えて

2

メモリを誤って再割り当てしています。 std::mallocstd::callocおよびstd::reallocへのインターフェイスは、割り当てられるサイズに関して多少矛盾し、混乱します。 std::mallocstd::reallocは単一サイズの引数をとります。これは、オブジェクトのサイズにそのサイズを掛けた値になります。 std::callocは、オブジェクトの数と1つのオブジェクトのサイズの2つの引数をとります。

あなたがこの(再)

auto *tmp = (Tile*)realloc(*array, 2 * sizeof(Tile)); 

を呼び出すには、2枚のタイルのためのスペースを割り当てます。あなたはそれがとても0

-1
void DoubleArray(Tile **array, unsigned *cap) { 
    // 
    auto *tmp = (Tile*)realloc(*array, *cap); 

    if(tmp) { 
    *array = tmp; 
    *cap *= 2; 
    (*cap)--; 
    } else { 
    printf("Error allocating memory.\n"); 
    free(tmp); 
    } 
} 

tmpは(エラーのために)再割り当て、なぜfree()それされていませんか?

+1

'free()'は無意味ですが危険ではありません。標準では、 'NULL(NULL)'ポインタを 'free()'しようとすると問題は起こりません。 See:[ptrがNULLのメモリが空いています(ptr)]?](https://stackoverflow.com/questions/1938735/does-freeptr-where-ptr-is-null-corrupt-memory) OPに非標準のコンパイラがない限り、問題に答えることができますが、それについては誰が気にしますか?解決策を提供するのではなく質問するだけなので、実際にはコメントにしてください。 –

関連する問題