9

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
        }
    }
2
  • just loop on the first array using i and j. The indexes z and k for the second array must be evaluated from i and j, do not loop over z and k. Commented Mar 25, 2016 at 9:48
  • Since an array is contiguous in memory, the arrays are nearly the same in the way they are stored. The question is, which level of checking do you need in your function. What do you want under the condition that the destination is smaller than the source? And as already mentioned below, does it need to run only for arrays or also for an array of pointers? Because if the data is contiguous in memory you can do it in one or two lines. Commented Mar 25, 2016 at 10:18

6 Answers 6

8

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));
Sign up to request clarification or add additional context in comments.

2 Comments

That's 8 rows and 2 columns ;)
This solution would not work in the OP example, where he has a pointer, not an array, and your solution relies in the knowledge of the array size at compile time.
7

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;
            }
        }
    }
}

Comments

6

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();
        }
}

Comments

4

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

Comments

3

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];

Comments

3

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.