You forgot one thing!
If arr1 is 1,2,3 and arr2 is 4,5,6. Then you will only copy arr1 into arr3. You need to do the loop you have written; BUT then when you exit the loop one of the arrays will have items still left to copy and you simply need to copy the remaining elements.
void merge(int arr1[], int n, int arr2[], int m, int arr3[])
{
    int i = 0, j = 0;
    int k = 0;
    while (i < n && j < m)
    {
        if(arr1[i] < arr2[j]){
            arr3[k++] = arr1[i++];
        }
        else{
            arr3[k++] = arr2[j++];
        }
    }
    // Copy any remaining elements.
    // Note: Only one of these loops will do any work
    //       The other loop is a noop.
    while (i < n) {
        arr3[k++] = arr1[i++];
    }
    while (j < m) {
        arr3[k++] = arr2[j++];
    }    
}
We can simplify a couple of things:
        if(arr1[i] < arr2[j]){
            arr3[k++] = arr1[i++];
        }
        else{
            arr3[k++] = arr2[j++];
        }
        // Could be written as:
        arr3[k++] = (arr1[i] < arr2[j]) ? arr1[i++] : arr2[j++];
The tertiary operator is a shortcut operator and only one side is evaluated.
Other things to note about C++
merge(arr1, 5, arr2, 3, arr3);
This would be better written as:
// Do not hard code the length of the array.
// Somebody in the future will come along and change the
// array and not look to where it is used and thus cause
// an error. Use `std::size()` to get the length of the array.
merge(arr1, std::size(arr1), arr2, std::size(arr2), arr3);
I would also change the operation to use iterators. This makes it easier to use some of the standard functions.
template<typename I1, typename I2, typename I3>
void merge(I1 b1, I1 e1, I2 b2, I2, e2, I3 dst)
{
    while (b1 < e1 && b2 < e2)
    {
        *dst++ = (*b1 <= *b2) ? *b1++ : *b2++;
    }
    dst = std::copy(b1, e1, dst);
    dst = std::copy(b2, e2, dst);
}
Then you can use it like:
merge(std::begin(arr1), std::end(arr1),
      std::begin(arr2), std::end(arr2),
      std::begin(arr3));