It is necessary to swap two rows of the matrix. Found on the Internet several examples in which element-by-element exchange is used. I don’t really like this code, so I wrote my own way of exchanging matrix rows using reference variables and pointers, but the trouble is I don’t fully understand how it works (it works, tested on arbitrary matrices).

Explain, please.

(In this particular case, changing the line depending on the parity of the index)

template <typename T> void swapRows(T **matrix, int rowsQuantity) { for ( int i = 0; i < rowsQuantity - 1; i++) { if ( i % 2 == 0 ) { T &temp = *matrix[i]; matrix[i] = matrix[i+1]; matrix[i+1] = &temp; } } } 

Practically found that "* matrix [i]" returns the value of the first element of the i-th row. Honestly, it is not clear why. I know that the name of the array is a pointer to its first element, apparently, it is somehow connected, but the exact logical chain cannot be drawn.

The reference variable "temp" gets the address of this first element of the i-th line.

How "matrix [i + 1] = & temp;" works is not very clear.

  • one
    Why did you write this T &temp = *matrix[i]; - absolutely not clear. This only confuses the code. You could just write T *temp = matrix[i]; matrix[i] = matrix[i+1]; matrix[i+1] = temp; T *temp = matrix[i]; matrix[i] = matrix[i+1]; matrix[i+1] = temp; . And you just got a piece of code with an "even number of absurdities", as a result of which they compensate each other. - AnT
  • Yes, I did it the way you wrote it. I will use just such a version, but it's still interesting to get an explanation of how the code works with reference variables. I have been studying C recently, so some of the nuances of working with links / pointers are not clear. - toopeachok
  • @toopeachok, judging by the fact that the function is a template, this is C++ , but not C - MGNeo

4 answers 4

The matrix pointer contains the pointer address (is a pointer to a pointer). matrix[i] is a pointer (matrix + i) , *matrix[i] is the first element in the array (row) matrix + i .

 T &temp = *matrix[i]; 

means that the first element of the i - той line is given the name temp

 matrix[i] = matrix[i+1]; 

now matrix[i] points to the beginning of the same array as matrix[i + 1]

matrix[i+1] = &temp; now i + 1 - th pointer gets the value: the address of the first element of i - that line, is equal to, indicates the line i

Practically you could write a function easier:

 template <typename T> void swapRows(T **matrix, int rowsQuantity) { for ( int i = 0; i < rowsQuantity - 1; i += 2) std::iter_swap(matrix[i], matrix[i + 1]); } 

    It is necessary to swap two rows of the matrix.

    First, you need to decide how the matrix is ​​declared.

    The simplest approach is to declare the matrix as a two-dimensional array. For example,

     const size_t N = 3; int a[N][N] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; 

    In this case, the function you give is not suitable, that is, it will not work, since it takes a pointer to a pointer as an argument, and not a two-dimensional array.

    For your function, the matrix is ​​most likely determined dynamically (although in the particular case it may be a local array) as a pointer to a dynamically allocated one-dimensional array, whose elements in turn are pointers to dynamically allocated one-dimensional arrays.

    For example,

     const size_t N = 3; int **a = new int *[N]; int value = 1; for ( size_t i = 0; i < N; i++ ) { a[i] = new int[N] { value++, value++, value++ }; } 

    Now pointer a can be passed to your function as the first argument.

    Inside this function, adjacent elements of a dynamically created array a are swapped, which are pointers to the first elements of other dynamically allocated arrays, like

     int **a = new int *[N]; 

    in the following way

     for ( int i = 0; i < rowsQuantity - 1; i++) { if ( i % 2 == 0 ) { T &temp = *matrix[i]; matrix[i] = matrix[i+1]; matrix[i+1] = &temp; } } 

    Here, the expression matrix[i] gives the element value, that is, the pointer value, in the i-ом element of the matrix array. This pointer contains the address of the first element of the i-го dynamically allocated array.

    Announcement

     T &temp = *matrix[i]; 

    announces a link to this first element of the i-го . Therefore, if you take the address of this first element using the link

     matrix[i+1] = &temp; 

    then the value of the expression &item will be equal to the value stored in the expression matrix[i] .

    The equivalent code might look like this.

     if ( i % 2 == 0 ) { T *temp = matrix[i]; matrix[i] = matrix[i+1]; matrix[i+1] = temp; } 

    Keep in mind that there is a standard std::swap function declared in the <utility> header. which performs this operation. With this function you could just write

     if ( i % 2 == 0 ) { std::swap( matrix[i], matrix[i+1] ); } 

    Below is a demonstration program that uses two approaches to matrix definition: the first is in the form of an array and the second is in the form of a set of dynamic arrays.

     #include <iostream> #include <utility> template <typename T, size_t N> void swapRows( T ( &a )[N][N] ) { for ( size_t i = 0; i + 1 < N; i += 2 ) { std::swap( a[i], a[i + 1] ); } } template <typename T> void swapRows( T **a, size_t n ) { for ( size_t i = 0; i + 1 < n; i += 2 ) { std::swap( a[i], a[i + 1] ); } } int main() { { const size_t N = 3; int **a = new int *[N]; int value = 1; for ( size_t i = 0; i < N; i++ ) { a[i] = new int[N] { value++, value++, value++ }; } for ( size_t i = 0; i < N; i++ ) { for ( size_t j = 0; j < N; j++ ) { std::cout << a[i][j] << ' '; } std::cout << '\n'; } std::cout << '\n'; swapRows( a, N ); for ( size_t i = 0; i < N; i++ ) { for ( size_t j = 0; j < N; j++ ) { std::cout << a[i][j] << ' '; } std::cout << '\n'; } std::cout << '\n'; } { const size_t N = 3; int a[N][N] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; for ( const auto &row : a ) { for ( const auto &item : row ) { std::cout << item << ' '; } std::cout << '\n'; } std::cout << '\n'; swapRows( a ); for ( const auto &row : a ) { for ( const auto &item : row ) { std::cout << item << ' '; } std::cout << '\n'; } std::cout << '\n'; } return 0; } 

    The output of the program to the console:

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

      In the presented code, the following happens:

      one)

       template <typename T> void swapRows(T **matrix, int rowsQuantity) { 

      This template function takes the first argument to a pointer to a pointer to some type. Apparently, it is assumed that this type is elementary. For example, int , float , double .

      Based on the fact that matrix is a pointer to a pointer, your matrix is ​​represented as an array, which stores pointers to arrays (strings), in which the elements themselves are stored:

      enter image description here

      Where matrix is a pointer that stores the address of the ABC array;

      2)

       for (int i = 0; i < rowsQuantity - 1; i++) { 

      The whole matrix is ​​traversed by rows. Two problems are immediately visible here:

      1. There is no control over the value of the rowsQuantity variable;
      2. A variable of type int not quite suitable for addressing the elements of an array. A variable of type size_t fits much better.

      3)

       if ( i % 2 == 0 ) { 

      Actions are performed when посещении each line whose index is a multiple of two (0, 2, 4, etc.). And the actions, respectively, are performed in pairs over the lines 0-1, 2-3, 4-5. This is not entirely rational, because this approach performs twice the increments of the variable i , twice the number of divisions with the remainder and twice more comparisons than is really necessary.

      It would be much more rational to perform i += 2 , generally discarding the division with the remainder and checking. But this approach will require checking the integer overflow of variable i .

      four)

       T &temp = *matrix[i]; matrix[i] = matrix[i+1]; matrix[i+1] = &temp; 

      At first glance, this is a rather idiomatic notation necessary for the classical exchange of places of two values ​​using an intermediate variable:

       temp = x; x = y; y = temp; 

      But not really. I'm not sure until the end what is happening in the depths of the compiler, and what the Стандарт says about this.

      matrix[i] - gets the value of the pointer to the matrix row (the address of the array with the string values). * - dereference of the given address, getting the value (s) of the entire line. Apparently, the value of the string is placed in the reference variable temp .

      I am not a C++ expert, but this code seems to me very strange. Logically, a link is the essence of compile time, in other words, it is just an all-name for something. That is, these three strange lines can be reduced to two:

       x = y; y = x; 

      As a result, both in x and y will be the original value of y . But, apparently, the compiler basically understands what you want from it. Or maybe this is an indefinite behavior. I can't say for sure, because the current C++ takes up almost 2000 pages.

      five)

       matrix[i+1] = &temp; 

      This is where the data address associated with the temp link is used.

      Ps. I would recommend mixing C++ with its C subset as rarely as possible. Not because C bad, but because such mixing has a number of significant drawbacks.

      First, low-level C explicitness is incompatible with high-level implicit C++ . This is guaranteed to lead to difficult to understand errors, even in a completely trivial code. It will also force you to write even more code than using C alone - this is a paradox.

      Secondly, the mixing of links with pointers, templates with macros, and exceptions with return codes leads to situations that cannot be analyzed, because the named elements are inconsistent in details, although they seem superficially very similar.

      • In the part where you yourself do not know well (are presenting), it is better not to try to explain ... - AR Hovsepyan

      matrix is of type pointer to pointer to T , which can also be treated as an array of pointers to T The rowQuantity argument most likely contains the number of elements in this array. I will add a little code:

       T &temp = *(matrix[i]); matrix[i] = matrix[i + 1]; matrix[i + 1] = &temp; 

      matrix[i] returns the total element of the array of pointers to T , then *(итый указатель) dereferences the total pointer and returns a reference to the first element of the final line, the resulting link is named temp . matrix[i] = matrix[i + 1] This element is assigned the total plus one element, now they contain the same pointers. matrix[i + 1] = &temp , here &temp returns a pointer to what temp refers to, namely the first element of the last line, the resulting address is placed in the total plus one element of the array.

      Here is the equivalent and more understandable code:

       T * temp = matrix[i]; matrix[i] = matrix[i + 1]; matrix[i + 1] = temp;