Moe diev
Moe diev

Reputation: 113

Copy two dimensional array elements to another two dimensional array with another size

i was trying to copy two dimensional array to another array with another size. For example: first array with 4 rows and 4 columns:

1 2 3 4
5 6 7 8
9 0 1 2
3 4 5 6

second array with 2 rows and 8 columns:

1 2 3 4 5 6 7 8
9 0 1 2 3 4 5 6

and if there are in the new array more elements than first one then the function will fill it with 0

this is the function i made, but the problem with indexes. How to write it in the right way?

void changearr(int **ppm, int size1, int size2, int size_1, int size_2)
{
    int **temp = new int*[size_1];
    for (int i = 0; i < size_1; i++)
        temp[i] = new int[size_2];  
    int z = 0;
    for (int i = 0; i < size_1; i++, z++)
    {
        for (int j = 0, k = 0; j < size_2; j++, k++)
        {
            if (i < size_1 || j < size_2)
            {
                temp[i][j] = ppm[z][k];
            }
            else
                temp[i][j] = 0
        }
    }

Upvotes: 9

Views: 8693

Answers (6)

Vaughn Cato
Vaughn Cato

Reputation: 64308

Here is a pretty simple way:

void
   changearr(
     int **in,int in_size1,int in_size2,
     int **out,int out_size1,int out_size2
   )
{
  int in_n = in_size1*in_size2;
  int out_n = out_size1*out_size2;
  int n = min(in_n,out_n);
  int i = 0;

  for (; i!=n; ++i) {
    out[i/out_size2][i%out_size2] = in[i/in_size2][i%in_size2];
  }

  for (; i!=out_n; ++i) {
    out[i/out_size2][i%out_size2] = 0;
  }
}

The idea is just to iterate through the indices linearly and calculate the coresponding indices for the input and output arrays as needed.

Upvotes: 3

AnatolyS
AnatolyS

Reputation: 4319

As you know C/C++ n-dimensional arrays have linear representation on the memory. So if you will switch on such representation you get the following benefit:

std::vector<int> v1{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
for(size_t r = 0; r < 4; r++) 
for(size_t c = 0; c < 4; c++) 
    std::cout << v1[r*4+c];
std::vector<int> v2(v1);
for(size_t r = 0; r < 2; r++) 
for(size_t c = 0; c < 8; c++) 
    std::cout << v2[r*8+c];

Upvotes: 3

Serge Ballesta
Serge Ballesta

Reputation: 149175

A 2D array is not the same thing a pointer to pointer is! As a 2D array simply store rows one after the other, you only have to copy elements:

#include <iostream>

void trans(int* orig, int rows1, int cols1, int *resul, int rows2, int cols2) {
    int tot1 = rows1 * cols1;
    int tot2 = rows2 * cols2;
    int tot = tot1;
    if (tot2 < tot) tot = tot2;
    // copy the smallest size from both arrays
    for(int i=0; i<tot; i++) {
        resul[i] = orig[i];
    }
    // eventually add 0 to fill resul array
    for(int i=tot; i<tot2; i++) {
        resul[i] = 0;
    }
}
int main() 
{ 
    int orig[4][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6};
    // control initial array
    for (int i=0; i<4; i++) {
        for (int j=0; j<4; j++) {
            std::cout << orig[i][j];
        }
        std::cout << std::endl;
    }
    int resul[2][8];
    // pass arrays as 1D array pointers!
    trans(reinterpret_cast<int *>(&orig), 4, 4, reinterpret_cast<int *>(&resul), 2, 8);
    // control converted array
    for (int i=0; i<2; i++) {
        for (int j=0; j<8; j++) {
            std::cout << resul[i][j];
        }
        std::cout << std::endl;
    }
    return 0;
}

It gives as expected:

1234
5678
9012
3456
12345678
90123456

Upvotes: 4

user1095108
user1095108

Reputation: 14603

Ohhhhh, what a nice programming puzzle. My solution is to flatten both arrays and copy them.

template <typename T>
static constexpr T* begin(T& value) noexcept
{
  return &value;
}

template <typename T, ::std::size_t N>
static constexpr typename ::std::remove_all_extents<T>::type*
begin(T (&array)[N]) noexcept
{
  return begin(*array);
}

template <typename T>
static constexpr T* end(T& value) noexcept
{
  return &value + 1;
}

template <typename T, ::std::size_t N>
static constexpr typename ::std::remove_all_extents<T>::type*
end(T (&array)[N]) noexcept
{
  return end(array[N - 1]);
}

int a[4][4];
int b[2][8];

::std::copy(begin(a), end(a), begin(b));

Upvotes: 8

xinaiz
xinaiz

Reputation: 7788

You could use simple temporary container:

#include <iostream>
#include <deque>
#include <array>

int main()
{
    std::array<std::array<int,4>,4> first {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; //4x4
    std::array<std::array<int,8>,2> second; //2x8
    std::deque<int> temp; //temporary container

    for(auto x : first)
        for(auto y : x)
            temp.push_back(y); //push everything from first to deque

    for(auto& x : second)
        for(auto& y : x)
        {
            y = temp.front(); //move from deque to second and pop()
            temp.pop_front();
        }
}

Upvotes: 6

Anmol Singh Jaggi
Anmol Singh Jaggi

Reputation: 8576

Why not to make a temporary linear array from the input matrix and then use that to fill the output matrix:

void changearr ( int** ppm, int old_row, int old_col, int new_row, int new_col )
{
    int* temp_linear = new int[old_row * old_col];

    int k = 0;
    for ( int i = 0; i < old_row; i++ )
    {
        for ( int j = 0; j < old_col; j++ )
        {
            temp_linear[k++] = ppm[i][j];
        }
    }

    int** temp = new int* [new_row];
    for ( int i = 0; i < new_row; i++ )
    {
        temp[i] = new int[new_col];
    }

    k = 0;
    for ( int i = 0; i < new_row; i++ )
    {
        for ( int j = 0; j < new_col; j++ )
        {
            if ( k < old_row * old_col )
            {
                temp[i][j] = temp_linear[k++];
            }
            else
            {
                temp[i][j] = 0;
            }
        }
    }
}

Upvotes: 7

Related Questions