Как скопировать элементы из двумерного массива в одномерный массив с помощью указателей C ++ - PullRequest
0 голосов
/ 11 сентября 2018

у меня есть функция

double* get_row(double *the_array, int row_num, int col_size)    

, где the_array - это двумерный массив, row_num - номер строки в двумерном массиве, из которого я хочу скопировать значения, а col_size - размер столбца двумерного массива.

Реализация функции

double* get_row(double *the_array, int row_num, int col_size) {

    double* row = new double[col_size];

    for (int i = 0; i < col_size; i++) {

        *row = *(*(the_array + row_num) + i);
        row++;
    }

    delete[] row;

    return row;
}

я пытаюсь скопировать значения из строки row_num 2D-массива the_array в 1D-массив row, но компилятор выдает ошибку в строке *row = *(*(the_array + row_num) + i); который я использовал для копирования элементов из одного массива в другой, как правильно выполнить эту задачу.

Кстати, ошибка, которую я получаю от visual studio: операнд '*' должен быть указателем.

спасибо за вашу помощь.

Ответы [ 4 ]

0 голосов
/ 11 сентября 2018

Если get_row не требует от вас выделения новой памяти обратно вызывающей стороне, тогда решением будет просто

double* get_row(double *the_array, int row_num, int col_size) 
{
    return the_array + (row_num * col_size);
}

Если ожидается, что вызывающая сторона выделит новую память для возвращаемой строки, тогда

double* get_row(double *the_array, int row_num, int col_size) 
{
    double* row = new double[col_size];
    for(int i = 0; i < col_size; i++)
        row[i] = *(the_array + (row_num * col_size) + i);
    return row;
}

будет работать.

В первом решении идея состоит в том, чтобы использовать row_num * col_size, чтобы перейти к правильной строке и просто вернуть местоположение адреса в качестве результата. Во втором решении мы сначала объявляем новую строку. А затем используйте i, чтобы проиндексировать каждый отдельный элемент в этой строке и скопировать каждый элемент из the_array в этой строке, индексированной как the_array + (row_num * col_size).

0 голосов
/ 11 сентября 2018

Я предполагаю, что "col_size" - это на самом деле "количество столбцов", чтобы решить эту проблему.И что данные расположены в главном порядке строки.

Тогда начало строки N находится в the_array + row_num*col_size.

Я бы начал с этой вспомогательной функции:

inline double* view_row_n( double* array, int row, int num_cols ) {
  return array+row*num_cols;
}

тогда я бы написал буфер копирования:

 std::unique_ptr<double[]> copy_buffer( double const* in, int count ) {
   double* retval = new double[count];
   std::memcpy( retval, in, sizeof(double)*count );
   return std::unique_ptr<double[]>( retval );
 }

, теперь я бы использовал их вместе:

double* get_row( double* the_array, int row_num, int col_size) {
  auto retval = copy_buffer( view_row_n( the_array, row_num, col_size), col_size );
  return retval.release();
}

и покончил бы с этим.

Я бы также изменил:

double* get_row( double const* the_array, int row_num, int col_size) {

и даже:

std::unique_ptr<double[]> get_row( double const* the_array, int row_num, int col_size) {

, но это выходит за рамки вашей проблемы.

0 голосов
/ 11 сентября 2018
double* get_row(double *the_array, int row_num, int col_size) {
    double* row = new double[col_size];

    for (auto i = 0; i < col_size; ++i) {
        row[i] = the_array[row_num * col_size + i];
    }

    // If the return isn't assigned, the program will leak!
    return row;
}

void row_test() {
    double two_d[15];

    const auto row = get_row(two_d, 2, 5);

    // ...
    // Be sure to delete row afterwards
    delete[] row;
}
0 голосов
/ 11 сентября 2018

Это не современный C ++, и, очевидно, вам не следует удалять возвращаемое значение.

я пытаюсь скопировать значения из строки row_num двумерного массива the_array в 1D массив

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

ошибка, которую я получаю [...]: операнд '*' должен быть указателем

Хорошо, вот эта строка:

*row = *(*(the_array + row_num) + i);

это беспорядок. Я думаю, я вижу, куда вы шли с этим, но посмотрите, вы разыменовываете (используя * слева от выражения) дважды без причины, что BTW вызывает Ошибка. Помните, что мы сказали, что the_array - это необработанный указатель , который рассматривается как одномерный массив. Следовательно, вы можете использовать этот тип арифметики с указателями, скажем, внутри скобок, а затем разыменовать его только один раз. Ваше выражение выше берет результирующий адрес (the_array + row_num), разыменовывает его, чтобы получить double в пределах этой ячейки массива, а затем добавляет i к самому значению double и затем пытается разыменуйте эту сумму double и int i - которая является временной переменной типа double, а не указателем. Это, вероятно, линия, к которой вы стремились:

*row = *(the_array + row_num * col_size + i);

Поскольку двумерные данные заразно распространяются в памяти, строка за строкой, последовательно , вам необходимо умножить индекс строки, подобный этому, на размер строки (который также является числом столбцов, и Я полагаю, что col_size на самом деле так, иначе у вас нет возможности перемещаться между строками), чтобы «пропустить между строками» и, наконец, добавить индекс текущей ячейки i, чтобы добраться до конкретной ячейки внутри строки , Затем, как мы уже говорили, разыменовываем все это.

Помимо расчета проблемы компиляции и адреса, вы должны по крайней мере сохранить адрес row, прежде чем увеличивать его в цикле, чтобы вы могли возвращать его, а не указатель за концом строки. В максимально возможной степени сохраняя исходную функцию, вы можете сделать это с помощью второго указателя , например:

double* get_row(double *the_array, int row_num, int col_size) {

    double* row = new double[col_size];
    double* rowPtr = row;

    for (int i = 0; i < col_size; i++) {
        *rowPtr = *(the_array + row_num * col_size + i);
        rowPtr++;
    }

    return row;
}

Я стараюсь сделать это как можно ближе к вашей версии, чтобы вы могли увидеть разницу с тем, что вы сделали. Многие вещи лучше сделать по-другому, например, , почему бы сначала не использовать оператор [], такой как row[i] = *(the_array + row_num * col_size + i);, а затем вообще избавиться от второго указателя? Нет реальной необходимости делать ++ там в качестве второй строки цикла, если вы перебираете i как есть. Другой пример: Вы должны были выделить или просто вернуть указатель на существующий массив , но в нужном месте?

Слишком важно не упомянуть здесь, что почти в любом сценарии вам действительно не следует возвращать необработанный указатель , как это, поскольку это может слишком легко привести к неясным намерениям в коде относительно того, кто владеет распределением (и в конечном итоге отвечает за его удаление) и ставит вопрос о том, как предотвратить утечку памяти в случае исключения? Предпочтительным решением является использование интеллектуальных указателей, , таких как std::unique_ptr, экземпляр которого оборачивает необработанный указатель и делает его таким, что вам придется быть очень явным, если вы захотите просто бросить этот кусок памяти небезопасным способом.

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