Как поменять строки матрицы местами c
Перейти к содержимому

Как поменять строки матрицы местами c

  • автор:

Как поменять строки матрицы местами c

Написать программу с использованием динамических переменных, в которой данные сначала из файла считываются в память, потом обрабатываются и записываются в файл. Использовать динамическое создание массивов.

В матрице поменять местами i-ю и j-ю строки.

Попыталась написать программу со статическим массивом, не очень получилось, данные берутся из файла (запись пока не делала), а даже на экран результат не выходит (где-то напортачила)
Помогите найти ошибку и подскажите пожалуйста как сделать динамический массив и с памятью динамической

#include "stdafx.h" #include #define size 100 void inputsize(int *_n, int *_m); int openf_and_mass(int _mass[size][size], int _n, int _m); void change(int k, int l, int _m, int _mass[size][size]); void print(int _mass[size][size], int _n, int _m); int main(void) < setlocale(LC_ALL, "Russian"); int mass[size][size]; int i=0,j=0,k,l; //FILE *fp; /*исходный файл*/ //FILE *fo; int n, m; inputsize(&n, &m); openf_and_mass(mass, n, m); printf("Введите номера строк, которые нужно поменять\n "); printf("i = "); scanf("%d", &k); printf(" j = "); scanf("%d\n", &l); change(k, l, m, mass); print(mass, n, m); return 0; >/*подпрограмма ввода количества элементов матрицы*/ void inputsize(int *_n, int *_m) < printf("Введите количество строк n/*подпрограмма открытия файла и считывания массива*/ int openf_and_mass(int _mass[size][size], int _n, int _m) < int i, j; FILE *fp; /*исходный файл*/ fp = fopen("C://Users//Ekaterina//Desktop//int.txt", "r"); if (fp == NULL) < perror("Error opening file"); return 0; >else < for (i = 0; i> for (i = 0; i < _n; i++) < printf("\n"); for (j = 0; j < _m; j++) printf("%4d", _mass[i][j]); >printf("\n"); > return 0; > void change(int k, int l, int _m, int _mass[size][size]) < int i, j,d; for (j = 0; j < _m; j++) < d = _mass[k][j]; _mass[k][j] = _mass[l][j]; _mass[l][j] = d; >> void print(int _mass[size][size], int _n, int _m) < int i, j; for (i = 0; i < _n; i++) < for (j = 0; j < _m; j++) < printf("%4d", _mass[i][j]); //printf("\n"); >> >
int.txt (302 байт, 124 просмотров)

Обмен местами строк матрицы

Необходимо поменять местами две строки матрицы. Нашел в интернете несколько примеров в которых используется поэлементный обмен. Мне такой код не очень нравится, поэтому я написал свой вариант обмена строк матрицы с использованием ссылочных переменных и указателей, но вот беда — я сам не до конца понимаю как он работает ( он работает, проверял на произвольных матрицах ). Объясните, пожалуйста. (В данном конкретном случае меняю местами строки в зависимости от четности индекса)

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

Практическим путем выяснил что » *matrix[i] » возвращает значение первого элемента i-ой строки. Честно говоря, не понятно почему так. Знаю, что имя массива это указатель на его первый элемент, видимо, это как-то связано, но точную логическую цепочку не получается провести. Ссылочная переменная » temp » получает адрес этого первого элемента i-ой строки. Как работает » matrix[i+1] = &temp; » не очень понятно.

Отслеживать
28.1k 3 3 золотых знака 27 27 серебряных знаков 40 40 бронзовых знаков
задан 14 янв 2019 в 0:16
toopeachok toopeachok
13 1 1 серебряный знак 5 5 бронзовых знаков

Зачем вы писали это T &temp = *matrix[i]; — совершенно не понятно. Это лишь запутывает код. Можно было просто написать T *temp = matrix[i]; matrix[i] = matrix[i+1]; matrix[i+1] = temp; . А у вас получился просто кусок кода с «четным количеством несуразностей», в результате чего они компенсируют друг друга.

14 янв 2019 в 1:21

Да, я уже после сделал так, как вы написали. Буду использовать именно такую версию, но все равно интересно получить объяснение на то, как работает код с ссылочными переменными. Си изучаю недавно, поэтому некоторые нюансы работы с ссылками\указателями не понятны.

14 янв 2019 в 2:02
@toopeachok, судя по тому, что функция является шаблонной, это C++ , но не C .
14 янв 2019 в 4:04

4 ответа 4

Сортировка: Сброс на вариант по умолчанию

Необходимо поменять местами две строки матрицы.

Во-первых, надо определиться, каким образом объявляется матрица.

Самый простой подход — это объявить матрицу в виде двумерного массива. Например,

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

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

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

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

Теперь указатель a можно передать в вашу функцию в качестве первого аргумента.

Внутри этой функции обмениваются соседние элементы динамически созданного массива a , которые являются указателями на первые элементы других выделенных динамически массивов, как

int **a = new int *[N]; 
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; >> 

Здесь выражение matrix[i] дает значение элемента, то есть значение указателя, в i-ом элементе массива matrix . Этот указатель содержит адрес первого элемента i-го динамически выделенного массива.

объявляет ссылку на этот первый элемент i-го . Поэтому если взять адрес этого первого элемента, используя ссылку

matrix[i+1] = &temp; 

то значение выражения &item будет равно значению, хранящемся в выражении matrix[i] .

Эквивалентный код может выглядеть следующим образом

if ( i % 2 == 0 )

Имейте в виду, что есть стандартная функция std::swap , объявленная в заголовке . которая выполняет данную операцию. С помощью этой функции вы могли бы просто написать

if ( i % 2 == 0 )

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

#include #include template void swapRows( T ( &a )[N][N] ) < for ( size_t i = 0; i + 1 < N; i += 2 ) < std::swap( a[i], a[i + 1] ); >> template 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 std::cout std::cout << '\n'; swapRows( a, N ); for ( size_t i = 0; i < N; i++ ) < for ( size_t j = 0; j < N; j++ ) < std::cout std::cout std::cout < 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 std::cout std::cout << '\n'; swapRows( a ); for ( const auto &row : a ) < for ( const auto &item : row ) < std::cout std::cout std::cout return 0; > 

Вывод программы на консоль:

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 

Отслеживать
ответ дан 14 янв 2019 в 9:50
Vlad from Moscow Vlad from Moscow
44.8k 3 3 золотых знака 39 39 серебряных знаков 90 90 бронзовых знаков

Указатель matrix содержит адрес указателья(является указателем на указатель). matrix[i] это указатель (matrix + i) , *matrix[i] это первый элемент в массиве(строке) matrix + i .

означает, что первому элементу i — той строки придаем имя temp

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

теперь matrix[i] указывает на начало того же массива, что и matrix[i + 1]

matrix[i+1] = &temp; теперь i + 1 — тый указатель получает значение: адрес первого элемента i — той строки, равно, указывает на строку i

Практически вы могли бы написать функцию проще:

template void swapRows(T **matrix, int rowsQuantity)

Отслеживать
ответ дан 14 янв 2019 в 7:57
AR Hovsepyan AR Hovsepyan
15.9k 3 3 золотых знака 14 14 серебряных знаков 30 30 бронзовых знаков

В представленном коде происходит следующее:

template void swapRows(T **matrix, int rowsQuantity)  

Эта шаблонная функция первым аргументом принимает указатель на указатель на какой-то тип. Судя по всему, предполагается, что этот тип является элементарным. Например, int , float , double .

Исходя из того, что matrix - это указатель на указатель, ваша матрица представлена как массив, в котором хранятся указатели на массивы (строки), в которых хранятся сами элементы:

введите сюда описание изображения

Где matrix - это указатель, в котором хранится адрес массива ABC ;

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

Происходит обход всей матрицы по строкам. Здесь сразу видны две проблемы:

  1. Нет контроля значения переменной rowsQuantity ;
  2. Переменная типа int не вполне подходит для адресации элементов массива. Переменная типа size_t подойдет гораздо лучше.
if ( i % 2 == 0 )  

Действия выполняются при посещении каждой строки, чей индекс кратен двум (0, 2, 4, и пр.). И действия, соответственно, выполняются попарно над строками 0-1, 2-3, 4-5.Это не совсем рационально, потому что такой подход выполняет в два раза больше инкрементов переменной i , в два раза больше делений с остатком и в два раза больше сравнений, чем реально необходимо.

Гораздо рациональнее было бы выполнять i += 2 , вообще отбросив деление с остатком и проверку. Но такой подход потребует выполнение проверки целочисленного переполнения переменной i .

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

На первый взгляд, это довольно идиоматическая запись, необходимая для классического обмена местами двух значений с использованием промежуточной переменной:

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

Но не совсем. Я не уверен до конца, что происходит в недрах компилятора, и что по этому поводу говорит Стандарт .

matrix[i] - получает значение указателя на строку матрицы (адрес массива со значениями строки). * - разыменовывает данный адрес, получая значение (значения) всей строки. По всей видимости, значение строки помещается в ссылочную переменную temp .

Я не специалист по C++ , но мне данный код кажется очень странным. По логике, ссылка является сущностью времени компиляции, иначе говоря - это просто всевдоним для чего-то. То есть, эти три странные строчки можно свести к двум:

x = y; y = x; 

В результате чего и в x , и в y будет находится изначальное значение y . Но, по-видимому, компилятор в принципе понимает, что вы от него хотите. А может быть, это неопределенное поведение. Точно сказать не могу, потому что текущий стандарт C++ занимает почти 2000 страниц.

matrix[i+1] = &temp; 

Здесь происходит использование адреса данных, связанных со ссылкой temp .

PS. Я бы рекомендовал как можно реже и меньше смешивать C++ с его C подмножеством. Не потому, что C плохо, а потому что такое смешивание имеет ряд существенных минусов.

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

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

Поменять местами строки матрицы

Дана матрица (двумерный массив). Поменять местами две любые ее строки.

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

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

const N = 7; M = 5; var arr: array[1..N,1..M] of byte; i,j,a,b,buff: byte; begin randomize; for i:=1 to N do begin for j:=1 to M do begin arr[i,j] := random(20); write(arr[i,j]:3); end; writeln; end; write('Какие строки обменять: '); readln(a,b); for j:=1 to M do begin buff := arr[a,j]; arr[a,j] := arr[b,j]; arr[b,j] := buff; end; for i:=1 to N do begin for j:=1 to M do write(arr[i,j]:3); writeln; end; end.

Пример выполнения кода:

 18 11 5 4 11 18 1 6 7 2 2 14 14 10 12 13 5 11 19 19 6 6 13 13 16 0 17 14 6 0 14 0 2 11 7 Какие строки обменять: 2 7 18 11 5 4 11 14 0 2 11 7 2 14 14 10 12 13 5 11 19 19 6 6 13 13 16 0 17 14 6 0 18 1 6 7 2

Как поменять местами первую строчку и столбец матрицы в ассемблере?

Здравствуйте! Проблема такая: Задали задание, нужно написать программу, в которой главный модуль находится в языке С С++, а дополнительный модуль в языке Ассемблера. Программа обязательно должна состоять из 2 раздельный файлов, т.е Нельзя встроить код ассемблера в код С++. Из главного модуля передаю количество элементов матрицы, и указатель на первый елемент матрицы.

В ассемблере нужно: поменять местами элементы первого столбца и первой строчки в матрице, если сумма первого столбца = сумме первой строки.

Код написанный на С++:

#include #include #include #include #include //extern "C" void asm_proc(int **a, int, int); // описание прототипа ASM-подпрограммы using namespace std; void Input(int** a, int n); void Output(int** a, int n); void Delete(int** a, int n); void Obm (int** a, int n); int main() < setlocale(LC_ALL, "russian"); srand(time(0)); // генерация случайных чисел int** a = new int* [3]; // 3 строки в массиве for (int count = 0; count < 3; count++) a[count]= new int[3]; // и 3 столбцов cout void Obm(int** a, int n) < int str = 0, stb = 0, d, i= 0, j =0; va: str += a[0][i]; stb += a[i][0]; i++; if (i != n) goto va; if (str == stb) < vb: d = a[0][j]; a[0][j] = a[j][0]; a[j][0] = d; j++; if (j != n) goto vb; >> void Input(int **a, int n)//функция заполнения массива с входными параметрами: массив и ограничение < for (int i = 0; i < n; i++) < for (int j = 0; j < n; j++) cin >> a[i][j] ; // заполняем случайными числами > > void Output(int** a, int n)//функция вывода массива в консоль < for (int i = 0; i < n; i++) < for (int j = 0; j < n; j++) cout > void Delete(int** a, int n)

Помогите, пожалуйста написать код на Ассемблере. Что-то начала писать, но не знаю как должно это выглядеть и запуталась:

.586 .model flat, stdcall option casemap : none .data A dd 1,2,3,11,12,13,21,22,23 len_str dd 0 n_str dd 3 n_colum dd 3 .code start: mov eax,n_colum shl eax,2 mov len_str,eax Xor esi,esi Mov ecx,n_str m2: Xor edi,edi Push ecx Mov ecx, n_colum m1: Mov eax, A[esi][edi*4] Inc edi Loop m1 add esi,len_str Pop ecx Dec ecx Jnz m2 end start

Или хотя бы напишете как должно выглядеть передача массива с С++ в ассемблер и возврат обратно отредактированного. Обработку напишу сама

  • Вопрос задан более трёх лет назад
  • 1446 просмотров

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *