memcpy () для переменных размеров трехмерного массива - PullRequest
0 голосов
/ 04 января 2019

У меня есть функция concat для объединения матрицы mat1 в форму mat2. Здесь mat1 и mat2 используют фиксированные размеры (то есть DIM1 = 2, DIM2 = 2, DIM3 = 3, DIM1_1 = 4), но на практике мне нужно, чтобы они имели переменные размеры, поэтому я объявил размер трехмерного массива в максимальный размер, как указано в моем коде ниже (т.е. DIM2 = 20, DIM3 = 30), но программа выдает значение мусора, когда я делаю это. Может кто-нибудь посоветовать, как использовать трехмерные массивы переменного размера без использования malloc ()?

#include <stdio.h>
#include <string.h>

//!< Dimensions of a 3d array
#define DIM1     2
#define DIM2     2
#define DIM3     3
#define DIM1_1   4


void Concat(int (*mat1)[DIM2][DIM3], int (*mat2)[DIM2][DIM3], int len);
// void Concat(int (*mat1)[20][30], int (*mat2)[20][30], int len);

int main()
{
    int mat1[DIM1][DIM2][DIM3] = {{{1,2,3},{4,5,6}},{{1,2,3},{4,5,6}}};
    int mat2[DIM1_1][DIM2][DIM3];

    Concat(mat1,mat2,2);

    return 0;
}
// void Concat(int (*mat1)[20][30], int (*mat2)[20][30], int len){
void Concat(int (*mat1)[DIM2][DIM3], int (*mat2)[DIM2][DIM3], int len){  
    /*concatenate mat1 to mat2 */
    memcpy(mat2[0], mat1, DIM1*DIM2*DIM3 * sizeof mat1);
    memcpy(mat2[0+len], mat1, DIM1*DIM2*DIM3 * sizeof mat1);
}

Ответы [ 2 ]

0 голосов
/ 04 января 2019

Я объявил размер трехмерного массива максимальным, как прокомментировано в моем коде ниже (т.е. DIM2 = 20, DIM3 = 30), но программа выдает значение мусора, когда я делаю это.

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

В любом случае параметры вашей функции Concat() являются указателями на двумерные массивы определенных размеров. Если фактические аргументы являются указателями на что-то другое, даже на массивы другого измерения, то неудивительно, что результаты плохие. Фактически это приводит к нарушению так называемого «правила строгого алиасинга», и поэтому его поведение не определено.

Может, кто-нибудь посоветует, как использовать трехмерные массивы переменного размера без использования malloc ()?

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

  • Если ваша реализация поддерживает VLA (обязательный в C99, но необязательный, начиная с C11), вы можете использовать их для поддержки вашей функции Concat(). Подобные вещи - одно из моих любимых применений для VLA, поскольку оно обходит большую практическую проблему их использования, которая связана с пространством, доступным для их автоматического распределения. Такой подход может выглядеть так:

    void Concat(size_t dim1, size_t dim2, size_t dim3 int (*source)[dim2][dim3],
            int (*dest)[dim2][dim3]) {
        size_t source_size = dim1 * sizeof(*source);
    
        memcpy(dest, source, source_size);
        memcpy(dest + dim1, source, source_size);
    }
    

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

    int mat1[DIM1][DIM2][DIM3] = /* ... */
    int mat2[DIM1 * 2][DIM2][DIM3];
    
    Concat(DIM1, DIM2, DIM3, mat1, mat2);
    

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

  • Если вы не можете или не хотите полагаться на VLA , тогда вашей лучшей альтернативой может быть простая адаптация вышеприведенного к этому случаю, например:

    void Concat(size_t dim1, size_t dim2, size_t dim3, void *source, void *dest) {
        size_t source_size = dim1 * dim2 * dim3 * sizeof(int);
    
        memcpy((char *) dest, source, source_size);
        memcpy((char *) dest + source_size, source, source_size);
    }
    

    Вы можете вызвать эту функцию так же, как и предыдущую.

  • Если вы хотите быть еще более общим и в то же время предоставить более простую сигнатуру функции, вы можете преобразовать вышеприведенное для объединения произвольных объектов:

    void Concat(size_t source_size, void *source, void *dest) {
        memcpy((char *) dest, source, source_size);
        memcpy((char *) dest + source_size, source, source_size);
    }
    

    Это обеспечивает полную общность, возлагая на вызывающего оператора ответственность за вычисления и передачу размера исходного объекта в байтах, хотя это не обязательно является большой проблемой. Например,

    int mat1[DIM1][DIM2][DIM3] = /* ... */
    int mat2[DIM1 * 2][DIM2][DIM3];
    
    Concat(sizeof(mat1), mat1, mat2);
    
0 голосов
/ 04 января 2019

Извините, но это невозможно сделать (не зная заранее максимальной длины). Когда ваша функция набирает mat1, она резервирует для массива ровно 2*2*3 int с памяти в стеке и прикрепляет каждый подмассив рядом друг с другом. Если статически распределено, то нет возможности изменить это после того, как это было сделано.

Однако ... с динамическим выделением памяти (т. Е. malloc и друзьями) это можно сделать. В частности, использование realloc для выделения дополнительного пространства.

К сожалению.

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