как более эффективно печатать матрицу с отрицаемой строкой

#c #multidimensional-array #printf #pointer-arithmetic #function-definition

#c #многомерный массив #printf #указатель-арифметика #функция-определение

Вопрос:

Я написал следующую функцию:

 void negate_row(const int n, const int r, int *a)
{
    if (r == 0)
    {
        printf("Matrix with negated row: ");
        printf("n");
        for (int y = 0; y < 3; y  )
        {
            *(a   3 * r   y) = *(a   3 * r   y) *(-1);
            printf("%d ", *(a   3 * r   y));
        }
        printf("n");

        for (int y = 0; y < 3; y  )
        {
            *(a   3 * r   y) = *(a   3 * r   y) *(-1);
            printf("%d ", *(a   3 * (r   1)   y));
        }
        printf("n");

        for (int y = 0; y < 3; y  )
        {
            *(a   3 * r   y) = *(a   3 * r   y) *(-1);
            printf("%d ", *(a   3 * (r   2)   y));
        }
        printf("n");
    }
 

Итак, в основном, что здесь происходит, так это то, что моя функция принимает матрицу n X 3 и отрицает определенную строку, используя арифметику указателей. Я смог добиться этого, я также смог выяснить, как напечатать ту же самую матрицу с отрицаемой строкой. Просто то, как я это делаю, совсем неэффективно. Мне пришлось бы написать оператор if для каждой строки, например, если r == 0,1,2,3,4 и т.д. … есть ли какой-нибудь способ сделать это более эффективно?

Некоторые пояснения: const int n определяет размер матрицы (n x 3), const int r решает, какая строка отрицается ( 0 <= r < n ).

Ответ №1:

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

 for (int y = 0; y < 3; y  )
{
    for (int x = 0; x < 3; x  )
    {
        printf("%d ", *(a   3 * (r   x)   y));
    }

    printf("n");
}
 

Комментарии:

1. у него есть n столбцы, так что это x < n

2. x Цикл должен быть внешним циклом.

3. ДА. Вы, ребята, правы. Я просто обращаюсь к вопросу о том, как уменьшить дублирующийся код в его одном цикле. Похоже, в этом и заключается вопрос.

4. Спасибо за этот ответ, и он действительно работает. Но есть проблема, с которой я столкнулся, и почему я сделал то решение, которое я сделал. В зависимости от того, какая строка вводится для отрицания, эта строка будет напечатана как первая строка матрицы. Теперь так и должно быть, выбранная строка должна оставаться в исходном месте. Например, если выбрана строка 2, она не должна становиться строкой 0, она должна оставаться на своем месте в строке 2.

Ответ №2:

Частный случай (3 строки):

 int mul = 1, y = 0;
for (int x = 0; x < n; x  ) {
    mul = x == r ? -1 : 1;
    y = (a   3 * x);
    printf("%d ", (*y) * mul);
    printf("%d ", (*y   1) * mul);
    printf("%d ", (*y   2) * mul);
    printf("n");
}
 

Более общий ( m строки):

 int mul = 1;
for (int x = 0; x < n; x  ) {
    mul = x == r ? -1 : 1;
    for (int y = 0; y < m; y  ) {
      printf("%d ", ((*(a   m * x   y)) * mul);
    }
    printf("n");
}
 

Примечание: В новых компиляторах также нет разницы в скорости между синтаксисом массива или указателя.

Ответ №3:

Вы могли бы написать функцию, которая принимает одномерный массив (строку вашей матрицы), а затем, используя эту функцию, вы могли бы в цикле выводить все ее строки или выводить выбранную строку.

Вот демонстрационная программа.

 #include <stdio.h>

void negate_row( const int *a, size_t n, int width )
{
    if ( width < 1 ) width = 1;
    
    for ( const int *p = a; p != a   n;   p )
    {
        printf( "%*d ", width, -*p );
    }
    putchar( 'n' );
}

int main(void) 
{
    enum { M = 3, N = 4 };
    int matrix[M][N] =
    {
        { 0,  1,  2,  4 },
        { 5,  6,  7,  8 },
        { 9, 10, 11, 12 }
    };
    
    for ( int ( *p )[N] = matrix; p != matrix   M;   p )
    {
        negate_row( *p, N, 3 );
    }
    
    return 0;
}
 

Вывод программы

   0  -1  -2  -4 
 -5  -6  -7  -8 
 -9 -10 -11 -12 
 

Поскольку вы показали код, в котором вы используете указатели для вывода элементов массива, то в этой демонстрационной программе я также использую указатели везде для доступа к элементам массива.

Третий параметр функции задает ширину поля для выводимого значения.

Для вывода матрицы в обратном порядке строк вы можете использовать цикл, показанный в программе blow.

 #include <stdio.h>

void negate_row( const int *a, size_t n, int width )
{
    if ( width < 1 ) width = 1;
    
    for ( const int *p = a; p != a   n;   p )
    {
        printf( "%*d ", width, -*p );
    }
    putchar( 'n' );
}

int main(void) 
{
    enum { M = 3, N = 4 };
    int matrix[M][N] =
    {
        { 0,  1,  2,  4 },
        { 5,  6,  7,  8 },
        { 9, 10, 11, 12 }
    };
    
    for ( int ( *p )[N] = matrix   M; p != matrix;  )
    {
        negate_row( *--p, N, 3 );
    }
    
    return 0;
}
 

Вывод программы

  -9 -10 -11 -12 
 -5  -6  -7  -8 
  0  -1  -2  -4 
 

Ответ №4:

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

 #include <stdio.h>

void negate_row(const int n, const int r, int *a) {
    if (r >= 0 amp;amp; r < n) {
        // negate row r
        for (int col = 0; col < 3; col  ) {
            *(a   3 * r   col) *= -1;
        }
    }
}

void print_matrix(const int n, int *a, const char *title) {
    if (title) {
        printf("%s:n", title);
    }
    for (int row = 0; row < n; row  ) {
        for (int col = 0; col < 3; col  ) {
            printf("%d ", *(a   3 * row   col));
        }
        printf("n");
    }
    printf("n");
}

int main() {
    int matrix[5 * 3] = {
        0, 1, 2,
        3, 4, 5,
        6, 7, 8,
        9, 10, 11,
        12, 13, 14,
    };
    print_matrix(5, matrix, "Matrix");
    negate_row(5, 0, matrix);
    print_matrix(5, matrix, "Matrix with negated row");
    negate_row(5, 3, matrix);
    print_matrix(5, matrix, "Matrix with two negated rows");
    negate_row(5, 0, matrix);
    negate_row(5, 3, matrix);
    print_matrix(5, matrix, "Matrix back to origin");
    return 0;
} 
 

Вывод:

Матрица:
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14

Матрица с отрицаемой строкой:
0 -1 -2
3 4 5
6 7 8
9 10 11
12 13 14

Матрица с двумя отрицаемыми строками:
0 -1 -2
3 4 5
6 7 8
-9 -10 -11
12 13 14

Матрица обратно в исходное положение:
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14