#arrays #c
Вопрос:
Как говорится в названии, я пытаюсь транспонировать 2-мерную матрицу, вызывая по ссылке. Я прикрепил свой код ниже. Когда я запускаю код, 2-мерный массив остается неизменным.
#include <stdio.h>
#define SIZE 4
void transpose2D(int ar[][SIZE], int rowSize, int colSize);
int main()
{
int testArr[4][4] = {
{1, 2, 3, 4},
{5, 1, 2, 2},
{6, 3, 4, 4},
{7, 5, 6, 7},
};
transpose2D(testArr, 4, 4);
// print out new array
for (int i = 0; i < 4; i )
{
for (int j = 0; j < 4; j )
{
printf("%d ", testArr[i][j]);
}
printf("n");
}
return 0;
}
void transpose2D(int ar[][SIZE], int rowSize, int colSize)
{
for (int i = 0; i < rowSize; i )
{
for (int j = 0; j < colSize; j )
{
int temp = *(*(ar i) j);
*(*(ar i) j) = *(*(ar j) i);
*(*(ar j) i) = temp;
}
}
}
Застряли на пару часов, любая помощь очень ценится, спасибо!
Комментарии:
1. Для любого указателя или массива
ar
и индексаi
выражение*(ar i)
в точности равноar[i]
. Так что вместо*(*(ar i) j)
тебя можно использоватьar[i][j]
.2. Я нахожу это немного сложным для понимания. Есть ли какая-то особая причина, по которой вы используете
*(*(ar i) j)
вместо более простогоar[i][j]
?3. Его для назначения, и они указали, чтобы использовать указатели..
4. Оба выражения абсолютно равны, не имеет значения, является ли
ar
это указатель или массив. В вашем случае, потомуar
что это указатель,ar[i][j]
будут использоваться указатели.5. Что касается вашей проблемы, вы, вероятно, меняете местами каждый элемент дважды . Используйте отладчик для пошагового выполнения кода и запишите на бумаге, какие элементы вы меняете местами.
Ответ №1:
Чтобы исправить вашу функцию, я предлагаю:
- переключите элемент только один раз, в предыдущей версии элементы поменялись местами на
i=a, j=b
иi=b,j=a
, поэтому матрица осталась неизменной - используйте общий
a[i][j]
синтаксис - пусть неквадратичная матрица будет встроена в большую матрицу, внутренние размеры которой установлены
stride
равными . - использование VLAs для придания интерфейсу немного более общего характера
void transpose2D(size_t rows, size_t cols, size_t stride, int ar[][stride]) {
assert(rows <= stride);
assert(cols <= stride);
for (size_t i = 0; i < rows; i ) {
for (size_t j = i 1; j < cols; j ) {
int tmp = ar[j][i];
ar[j][i] = ar[i][j];
ar[i][j] = tmp;
}
}
}
Примерное использование:
int testArr[4][4] = {
{1, 2},
{5, 1},
{6, 3},
};
transpose2D(3, 2, 4, testArr);
Алгоритм все еще очень неэффективен из-за ужасных ставок пропусков кэша при доступе a[j][i]
. Это можно исправить, выложив плитки и переместив блоки размером 8х8, но это тема для другого дня.
Комментарии:
1. Нет необходимости в том, чтобы матрица была квадратной, потому что в нее вложена подматрица большей матрицы, которая уже является квадратной, поэтому компоновка памяти в порядке. Внесение изменений, которые вы показываете, нарушает способность процедуры принимать неквадратичные матрицы.
2. Проблемы с кэшем выходят далеко за рамки этого задания и отвлекают здесь.
3. @EricPostpischil, судя по тому, как сформулирован вопрос, я почти уверен, что OP хочет перенести весь массив.
4.@EricPostpischil, и обратите внимание, что предлагаемый API требует, чтобы только первые измерения имели по крайней мере
size
элементы. Это может быть дольше, чем это5. Новый код может получить правильные результаты для прямоугольных матриц (встроенных в квадратные матрицы), но это бесполезно, поскольку элементы за пределами квадрата, которые являются общими для матрицы и ее транспонирования, нужно только перемещать, а не менять местами.