Повреждение кучи в простой программе на C ++ - PullRequest
1 голос
/ 08 марта 2019

Я написал простую программу на C ++, вот код:

// Вариант 72, задача 2.18
#include <iostream>

#define lint long long int

using std::cin;
using std::cout;

void input(lint arr[], lint arrLen) {
    for (lint i = 0; i < arrLen; ++i) {
        cout << "arr[" << i << "] = ";
        cin >> arr[i];
    }
}

void output(lint arr[], lint arrLen) {
    for (lint i = 0; i < arrLen; ++i) {
        cout << "newArr[" << i << "] = " << arr[i] << '\n';
    }
}

bool isNumberInArray(const lint arr[], lint arrLen, lint number) {
    bool isNumberPresent = false;
    for (lint i = 0; i < arrLen; ++i) {
        if (arr[i] == number) isNumberPresent = true;
    }
    return isNumberPresent;
}

void process(const lint arr[], lint arrLen, lint newArr[], lint &newArrLen, lint m, lint M) {
    newArrLen = 0;
    for (lint i = M; i >= m; --i) {
        if (!isNumberInArray(arr, arrLen, i)) {
            newArr[newArrLen] = i;
            ++newArrLen;
        }
    }
}

int main() {
    lint arrLen, m, M;

    cout << "Enter m\n> ";
    cin >> m;
    cout << "Enter M\n> ";
    cin >> M;
    cout << "Enter array length\n> ";
    cin >> arrLen;

    lint *arr = new lint[arrLen];

    cout << "Enter array elements:\n";
    input(arr, arrLen);

    lint *newArr = new lint[arrLen], newArrLen;

    process(arr, arrLen, newArr, newArrLen, m, M);

    cout << "\nResults:\n";
    output(newArr, newArrLen);

    delete[] arr;
    delete[] newArr;
    return 0;
}

Когда я компилирую его с помощью MSVC (x86 | Debug) и запускаю его, он обычно работает и дает желаемый результат, но после выполнения выдает следующую ошибку: HEAP CORRUPTION DETECTED

Я попытался скомпилировать программу под WSL с использованием g ++ и отладить ее с помощью Valgrind. Вот что я получил:

root@seiba-laptop : /mnt/c/Users/saber-nyan/source/repos/Project1/Project1
[130] # g++ ./main.cpp -O0 -ggdb -o ./main

root@seiba-laptop : /mnt/c/Users/saber-nyan/source/repos/Project1/Project1
[0] # valgrind ./main
==316== Memcheck, a memory error detector
==316== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==316== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==316== Command: ./main
==316==
==316== error calling PR_SET_PTRACER, vgdb might block
Enter m
> 1
Enter M
> 5
Enter array length
> 2
Enter array elements:
arr[0] = 4
arr[1] = 2
==316== Invalid write of size 8
==316==    at 0x1093A4: process(long long const*, long long, long long*, long long&, long long, long long) (main.cpp:34)
==316==    by 0x1094E4: main (main.cpp:57)
==316==  Address 0x4d60560 is 0 bytes after a block of size 16 alloc'd
==316==    at 0x483850F: operator new[](unsigned long) (vg_replace_malloc.c:423)
==316==    by 0x1094BA: main (main.cpp:55)
==316==

Results:
newArr[0] = 5
newArr[1] = 3
==316== Invalid read of size 8
==316==    at 0x1092B7: output(long long*, long long) (main.cpp:18)
==316==    by 0x10950A: main (main.cpp:60)
==316==  Address 0x4d60560 is 0 bytes after a block of size 16 alloc'd
==316==    at 0x483850F: operator new[](unsigned long) (vg_replace_malloc.c:423)
==316==    by 0x1094BA: main (main.cpp:55)
==316==
newArr[2] = 1
==316==
==316== HEAP SUMMARY:
==316==     in use at exit: 0 bytes in 0 blocks
==316==   total heap usage: 5 allocs, 5 frees, 74,784 bytes allocated
==316==
==316== All heap blocks were freed -- no leaks are possible
==316==
==316== For counts of detected and suppressed errors, rerun with: -v
==316== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

В чем проблема и как ее исправить?

Ответы [ 2 ]

5 голосов
/ 08 марта 2019

Насколько я понимаю, вы пытаетесь создать новый массив, содержащий значения, отсутствующие в исходном.В вашем случае вы сначала собрали [4,2] и попытались построить [5,3,1], потому что значения между M = 5, m = 1, которых нет в [4,2], равны [5,3,1].

Ваша проблема в том, что вы сначала создали newArr как массив длины 2 (такой же длины, как arr).Но вы не можете поместить 3 значения в массив размером 2.

==316== Invalid write of size 8
==316==    at 0x1093A4: process(long long const*, long long, long long*, long long&, long long, long long) (main.cpp:34)
==316==    by 0x1094E4: main (main.cpp:57)
==316==  Address 0x4d60560 is 0 bytes after a block of size 16 alloc'd
==316==    at 0x483850F: operator new[](unsigned long) (vg_replace_malloc.c:423)
==316==    by 0x1094BA: main (main.cpp:55)

Invalid write of size 8 означает, что вы пытались записать long long int по какому-то неверному адресу.

Address 0x4d60560 is 0 bytes after a block of size 16 alloc'dозначает, что valgrind обнаружил, что ваша плохая запись была в конце фрагмента памяти размером 16, точно размером с массив из двух long long int s.

0 голосов
/ 08 марта 2019

Проблема в том, что у вашего newArr не обязательно достаточно места для хранения всех длинных длинных целых;Это зависит от значений M и m, которые определяют, сколько итераций будет проходить для цикла for в процессе (...), и от значений, хранящихся в arr.

Чтобы исправить это, в этой строке здесь:

  • lint * newArr = new lint [arrLen], newArrLen;

Вместо arrLen количество новых линтов выделяется (M - m + 1).

Вы также должны убедиться, что M> m

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...