Ошибка неверного указателя в C ++ при компиляции с g ++ в Linux, но не в CLion в Windows - PullRequest
0 голосов
/ 07 марта 2019

У меня довольно странная проблема.Я написал программу, которая для каждого значения n от 2 до 100 генерирует два идентичных массива случайных чисел c-типа и передает один в алгоритм сортировки слиянием, а другой - в алгоритм сортировки выбора.Он запускает 10 000 тестов с каждым и определяет число операций для каждого из худших сценариев для каждого значения n из 10000 тестов.Затем он записывает каждое значение n вместе с наихудшим числом операций алгоритма сортировки слиянием и наихудшим числом операций сортировки выбора в файл .csv.

Моя проблема заключается в следующем:Я собираю / компилирую и запускаю код в CLE IDE (в Windows 10), он отлично работает и заканчивается кодом завершения 0.

Когда я использую FTP для копирования файлов в linuxсервер и попробуйте скомпилировать и запустить все, он компилируется нормально, но я получаю ошибку во время выполнения о недопустимом указателе.

Я компилирую код с помощью g++ -std=c++14 -Wall main.cpp SortFunctions.cpp -o program3.out.

Вот скриншот моего сообщения об ошибке: error message

Вот мой файл main.cpp:

#include <iostream>
#include <string>
#include <cstdlib>          // FOR RANDOM NUMBER GENERATION
#include <ctime>            // FOR SEEDING RANDOM NUMBER GENERATION
#include "SortFunctions.h"
#include <fstream>

using std::cout;
using std::cin;
using std::endl;
using std::string;
using std::ofstream;
using std::ios;


int main() {

    // CREATE ARRAYS TO STORE NUMBER OF WORSE-CASE OPERATIONS
    long long int worst_case_merge_operations[99]; // 99
    long long int worst_case_selection_operations[99]; // 99

    // FOR ALL VALUES OF n BETWEEN 2 AND 100, INCLUSIVE
    for (int n = 2; n <= 100; n++){

        cout << "Trial with n = " << n << endl;

        // VARIABLES TO STORE THE VALUE UNTIL ADDED TO THE ARRAY
        long long int worst_num_merge_operations = 0;
        long long int worst_num_selection_operations = 0;
        // FOR EACH
        for (int i = 1; i <= 10000; i++) {

            if (i % 100 == 0){
                cout << "Beginning test " << i << " of 10,000 for n = " << n << endl;
            }

            // CREATE ARRAYS (OF LENGTH N)TO POPULATE WITH RANDOM NUMBERS
            int array1[n];
            int array2[n];



            // POPULATE ARRAYS WITH RANDOM NUMBERS
            for (int k = 0; k < n; k++) {

                // GENERATE A RANDOM INTEGER IN THE RANGE [1,1000]
                int rand_num = (rand() % 1000) + 1;

                // ADD THE NUMBER TO EACH ARRAY, THUS MAKING THE ARRAYS IDENTICAL
                array1[k] = rand_num;
                array2[k] = rand_num;

            }

            // CALL MERGE SORT WITH THE ARRAY, INDEX OF FIRST ELEMENT, AND INDEX OF LAST ELEMENT

            long long int merge_ops = MergeSort(array1, 0, n - 1);
            if (merge_ops > worst_num_merge_operations){
                worst_num_merge_operations = merge_ops;
            }


            // CALL SELECTION SORT, COUNTING OPERATIONS
            long long int selection_ops = SelectionSort(array2, n);

            if (selection_ops > worst_num_selection_operations){
                worst_num_selection_operations = selection_ops;
            }


            // NOTE: DO NOT FORGET TO DELETE THE ARRAYS/POINTERS, OTHERWISE YOU'LL HAVE A MEMORY LEAK!!!
            delete[] array1;
            delete[] array2;


            if (i % 100 == 0){
                cout << "Completed test " << i << " of 10,000 for n = " << n << endl;
            }

        }

        // ADD WORST-CASE NUMBER OF OPERATIONS OF EACH TO THEIR REPSECTIVE ARRAY
        worst_case_merge_operations[n - 2] = worst_num_merge_operations;
        worst_case_selection_operations[n - 2] = worst_num_selection_operations;
    }

    // PERFORM FILE IO TO CSV FILE
    // COLUMNS: [N] [WORST CASE MERGE] [WORST CASE SELECTION]
    cout << endl << "Attempting to perform file IO" << endl;
    ofstream data_file("algorithm_data.csv");

    // CHECK IF FILE IS OPEN
    if(!data_file.is_open()){
        cout << "Unable to open data file algorithm_data.csv" << endl;
        return -1;
    } else {
        cout << "Data file opened" << endl;
    }

    // WRITE HEADER ROW FOR FILE
    data_file << "n,worst case merge operations,worst case selection operations" << endl;
    cout << "Header row written, attempting to write data rows" << endl;

    // WRITE VALUES TO THE FILE
    for (int i = 0; i < 98; i++){

        //WRITE N (= I+2),WORST_CASE_MERGE,WORST_CASE_SELECTION \n
        data_file << i+2 << "," << worst_case_merge_operations[i] << "," << worst_case_selection_operations[i] << endl;
    }

    cout << "Data rows written, attempting to close the file" << endl;

    // CLOSE THE FILE
    data_file.close();
    cout << "Data file closed" << endl;


    return 0;
}

Вот мойФайл SortFunctions.cpp:



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

using namespace std;

/*
 * NOTE: MERGE SORT ALGORITHM
 */

long long int Merge(int numbers[], int i, int j, int k) {

    // COUNT OPERATIONS
    long long int operations = 0;

    // INCREMENT OPERATIONS
    operations += 1;

    // ALGORITHM
    int mergedSize;                            // Size of merged partition
    int mergePos;                              // Position to insert merged number
    int leftPos;                               // Position of elements in left partition
    int rightPos;                              // Position of elements in right partition
    int* mergedNumbers = nullptr;

    mergePos = 0;
    mergedSize = k - i + 1;
    leftPos = i;                               // Initialize left partition position
    rightPos = j + 1;                          // Initialize right partition position
    mergedNumbers = new int[mergedSize];       // Dynamically allocates temporary array
    // for merged numbers

    // Add smallest element from left or right partition to merged numbers
    while (leftPos <= j && rightPos <= k) {

        // INCREMENT OPERATIONS
        operations += 1;

        if (numbers[leftPos] < numbers[rightPos]) {
            mergedNumbers[mergePos] = numbers[leftPos];
            ++leftPos;
        }
        else {
            mergedNumbers[mergePos] = numbers[rightPos];
            ++rightPos;

        }
        ++mergePos;
    }

    // If left partition is not empty, add remaining elements to merged numbers
    while (leftPos <= j) {

        // INCREMENT OPERATIONS
        operations += 1;

        mergedNumbers[mergePos] = numbers[leftPos];
        ++leftPos;
        ++mergePos;
    }

    // If right partition is not empty, add remaining elements to merged numbers
    while (rightPos <= k) {

        // INCREMENT OPERATIONS
        operations += 1;

        mergedNumbers[mergePos] = numbers[rightPos];
        ++rightPos;
        ++mergePos;
    }

    // Copy merge number back to numbers
    for (mergePos = 0; mergePos < mergedSize; ++mergePos) {

        // INCREMENT OPERATIONS
        operations += 1;

        numbers[i + mergePos] = mergedNumbers[mergePos];
    }

    return operations;
}

long long int MergeSort(int numbers[], int i, int k) {

    // COUNT OPERATIONS
    long long int operations = 0;

    // INCREMENT OPERATIONS
    operations += 1;

    //ALGORITHM
    int j;

    if (i < k) {
        j = (i + k) / 2;  // Find the midpoint in the partition

        // Recursively sort left and right partitions
        operations = operations + MergeSort(numbers, i, j);
        operations = operations + MergeSort(numbers, j + 1, k);

        // Merge left and right partition in sorted order
        operations = operations + Merge(numbers, i, j, k);
    }

    return operations;
}

/*
 * NOTE:SELECTION SORT ALGORITHM
 */

long long int SelectionSort(int numbers[], int numbersSize) {

    // CREATE COUNTER
    long long int counter = 0;

    // INCREMENT COUNTER
    counter += 1;

    int i;
    int j;
    int indexSmallest;
    int temp;      // Temporary variable for swap

    for (i = 0; i < numbersSize - 1; ++i) {

        // INCREMENT COUNTER
        counter += 1;
        // Find index of smallest remaining element
        indexSmallest = i;
        for (j = i + 1; j < numbersSize; ++j) {

            // INCREMENT COUNTER
            counter += 1;
            if ( numbers[j] < numbers[indexSmallest] ) {
                indexSmallest = j;
            }
        }

        // Swap numbers[i] and numbers[indexSmallest]
        temp = numbers[i];
        numbers[i] = numbers[indexSmallest];
        numbers[indexSmallest] = temp;
    }
    return counter;
}

И, наконец, мой файл SortFunctions.h:


#ifndef PROGRAM_3_SORTFUNCTIONS_H
#define PROGRAM_3_SORTFUNCTIONS_H
//code here


long long int SelectionSort(int numbers[], int numbersSize);
long long int MergeSort(int numbers[], int i, int k);

#endif //PROGRAM_3_SORTFUNCTIONS_H

Я относительно новичок в указателях и был бы признателен, если бы кто-то мог помочь.Я провел час в Google, пытаясь найти решение безрезультатно.

1 Ответ

3 голосов
/ 07 марта 2019

Составлено с -Wall -Wextra -Werror

> g++ -Wall -Wextra -Werror main.cpp 
main.cpp:72:13: error: cannot delete expression of type 'int [n]'
            delete[] array1;
            ^        ~~~~~~
main.cpp:73:13: error: cannot delete expression of type 'int [n]'
            delete[] array2;
            ^        ~~~~~~

Похоже, в вашем коде есть две ошибки.

Поскольку оба этих массива объявлены как автоматические переменные:

        int array1[n];
        int array2[n];

Ошибка вызывать delete для них (автоматические переменные никогда не должны передаваться для удаления). Поэтому удалите две строки с помощью delete.

Вы должны быть в состоянии обновить CLion, чтобы рассматривать ваши ошибки как предупреждения:

Как включить все предупреждения компилятора в CLion?
https://www.jetbrains.com/help/clion/configuring-inspection-severities.html

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

Примечание 1:

Вы должны вызывать delete только для переменных, которые были сгенерированы с новым.
Вы должны вызывать delete [] только для переменных, которые были сгенерированы с new []

Примечание 2:

В современном C ++ очень необычно видеть голое новое / удаление в коде. Это не исключительное исключение и, следовательно, обычно заключено в класс. См. Примечание 4, чтобы справиться с большинством ситуаций, когда необходима динамическая память.

Примечание 3:

Динамически размещаемые объекты обычно управляются с помощью интеллектуальных указателей. В то время как группы объектов обычно контролируются через std :: Containers (обычно std::vector, когда вы не знаете, что использовать).

Примечание 4:

Массивы переменной длины VLA технически не являются стандартной частью языка. Некоторые компиляторы их поддерживают, но обычно лучше использовать std::vector

int                array1[n];  // Non standard if n is not a compile time constant.
std::vector<int>   array1(n);
...