русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Передача матрицы в функцию


Дата добавления: 2015-06-12; просмотров: 5189; Нарушение авторских прав


 

Один из способов передачи матрицы в функцию был рассмотрен в первом семестре. Его недостаток в том, что в прототипе функции для матрицы необходимо было обязательно указывать вторую размерность матрицы, то есть количество элементов в строках. Здесь предлагается более профессиональный способ, основанный на понятиях указатель на указатель и динамические “матрицы”.

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

void FunArr1 (int *z, int , … );

или

void FunArr1 (int z[], int,… );

но в любом из вариантов мы передаём адрес начала массива.

Аналогично матрица как параметр функции объявляется в прототипе, например, одним из следующих способов:

void FunMatr (int **X, int , int );

или

void FunMatr (int *X[], int , int );

То есть если сравнивать с одномерным массивом, то просто вместо типа int, что означает числовой целочисленный массив, записали тип int *, что означает, что в функцию передаём адрес начала массива указателей. Как правило, в качестве параметров включаются и две размерности матрицы.

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

Для передачи матрицы в вызывающей функции создаём полностью динамическую или частично динамическую “матрицу”, а при вызове функции записываем её имя (см. дальше пример). Если продолжить аналогию с обычным одномерным числовым массивом, то в качестве первого параметра функции FunArr1 можно передать как статический массив:

int A[10]; FunArr1(A, 10,…);

так и динамический:

int *d; int n; cin>>n; d= new int[n]; FunArr1(d, n, …);



В случае с матрицей это не совсем так. Пусть объявлена статическая матрица

const Nc=5, Mc=10; int C[Nc][Mc];

Передать её в функцию нельзя, то есть вызов

FunMatr(C, Nc, Mc);

приведёт к ошибке компиляции.

Пример. (+).

Передача матрицы в функцию с помощью указателей. Кроме этого здесь дополнительно показано, как передать формат стандартной функции вывода printf в качестве параметра функции.

void MyFun1 (int **X, int , int ); // или void MyFun1 (int *X[],int , int );

void MyFun2 (int *X[],int , int ); //или void MyFun2 (int **X,int , int );

void MyPrint (int **X, int , int, int, char* );

int main()

{

/* Создание “полностью” динамической матрицы, которая объявляется как динами­ческий массив из N указателей. Обе размерности – переменные.*/

int ** A; int N=3, M=4;

A=new int *[N];

for (int i=0; i<N; i++) A[i]=new int [M];

/* В функцию передаём полностью динамическую матрицу. */

MyFun1(A,N,M);

/* Сначала выводим указанный текст, а затем матрицу A размерности N*M по формату “%5d” */

MyPrint(A,N,M,5,"\n The first test\n");

//Удаляем матрицу

for (int i=0;i<N;i++) delete[]A[i];

delete[]A;

/* Создание “частично” динамической матрицы, которая объявляется как статический массив указателей фиксированной размерности Nconst. Другими словами, количество “строк” фиксировано (Nconst), а количество элементов в строке произвольное: M2 – не константа, а переменная (см. 5.3) */

const Nconst=8; int M2=6;

int *B[Nconst];

/* Для такой полудинамической матрицы B=new int *[Nconst]; не надо. Будет ошибка!!!!!!! */

for (int i=0; i<Nconst; i++)

B[i]=new int [M2];

/* Передаём полудинамическую матрицу */

MyFun2(B,Nconst,M2);

MyPrint(B,Nconst,M2,3,"\n \nThe second test\n");

//Удаляем матрицу B

for (int i=0;i<Nconst;i++)

delete[]B[i];

getch(); return 0;

}

void MyFun1 (int **X, int n, int m)

// или void MyFun1 (int *X[], int n, int m)

{

for (int i=0; i<n; i++)

for (int j=0;j<m;j++)

X[i][j]=(i+1)*(j+1);

// Перестановка 0-й и (n-1)-й строк

int* t;

t=X[0]; X[0]=X[n-1]; X[n-1]=t;

}

void MyFun2 (int *X[], int n, int m)

// или void MyFun2 (int **X, int n, int m)

/* Определяем элементы матрицы. */

{

for (int i=0; i<n; i++)

for (int j=0;j<m;j++)

if (i%2) X[i][j]=(i+1)-(j+1);

else X[i][j]=(i+1)+(j+1);

}

void MyPrint (int **X, int n , int m, int L, char* t )

{

// Формируем формат “%Ld”, где L – переданное в функцию целое число…

char AnyFormat[10],

StrL[3];

/* … для хранения переведенного в строку c помощью встроенной функции itoa целого числа L */

strcpy(AnyFormat, "%");

strcat(AnyFormat,itoa(L,StrL,10));

strcat(AnyFormat,"d");

puts(t);

for (int i=0; i<n; i++)

{

for (int j=0;j<m;j++)

printf(AnyFormat,X[i][j]);

cout<<endl;

}

}

§5. Динамический массив строк (+).

 

По аналогии с динамической матрицей можно создать динамический массив строк. Для этого объявляем динамический массив указателей как указатель на указатель символа:

char **s;

Объявляем и определяем количество строк:

int n; cin>>n;

Аналогично резервируем память для массива указателей на строки

s=new char*[n];

В цикле резервируем память для каждой строки. Размер её определяем с помощью вспомогательной строки t, длина которой, а, значит и длина каждой строки, не более 40 символов:

char *t; t=new char[40];

for(int i=0; i<n; i++)

{ gets(t);

s[i]=new char[strlen(t)];

strcpy(s[i], t);

}

Работу с таким массивом рассмотрим на примере сортировки массива строк.

for(int j=0; j<n; j++)

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

if (s[i][0]>s[i+1][0]) //Сравнение первых символов строк

//if (strcmp(s[i],s[i+1])>0) // или сравнение двух строк

{ // Перестановка двух строк

strcpy(t,s[i]); // копирование s[i] в t

strcpy(s[i],s[i+1]);

strcpy(s[i+1],t);

}

for(int i=0;i<n;i++) puts(s[i]); // Вывод строк

//Освобождение памяти особенностей не имеет.

for (int i=0; i<n;i++)

delete []s[i]; // Удаление каждой строки из памяти

delete []s; // Удаление массива указателей из памяти

delete []t; // Удаление вспомогательной строки из памяти

В качестве повторения заметим, что два варианта сравнения

if (s[i][0]>s[i+1][0])

и

if(strcmp(s[i],s[i+1])>0) …

выполняются по-разному. В первом случае сравниваются только первые символы соседних в массиве строк и независимо от результата следующие символы в сравнении не участвуют. С помощью функции strcmp выполняется сравнение так, как было описано в теме “строки” (см. §5 главы 2).

 

Упражнения, тесты.

1. Дан код:

const n=5; int * ap[n];

int v; ap[1]=&v; //1

ap[2]= v; //2

int * p; p= new int; ap[3]=*p; //3

int *q; q=new int[10]; ap[9]=q; //4

ap[4]=new int; //5

ap[4]=new int[6]; //6

unsigned m=10; ap[7]=new int[m]; //7

const k=10; int a[k]; ap[8]=a; //8

В каких строках (//1—//8) нет ошибок? Что означают правильные операторы? Объяснить ошибки.

2. Дан код:

const п=5, m=10; int M [n][m], *p, *ap[n];

int k1=0, k2=n-1;

p=M[k1]; //1

M[k1]=M[k2]; //2

M[k2]=p; //3

for (int i=0; i<n; i++) ap[i]=M[i]; //4

int i1=0, i2=m-1;

p=ap[i1]; //5

ap[i1]=ap[i2]; //6

ap[i2]=p; //7

В каких строках (//1—//7) есть ошибки? Объяснить их.

3. Как будет работать следующий фрагмент программы

void MyOut(int *u, int size)

{ cout<<endl;

for (int i=0; i<size;i++) cout<<u[i]<<" ";

}

int main()

{ const n=5;

int ar1[n]={10, -2, 33, 4},

ar2[n]={111, -222, 333, 0, 555};

int *t, *t1, *t2; t1=ar1; t2=ar2;

t=t1; t1=t2; t2=t;

MyOut(ar1,n); MyOut(ar2,n);

MyOut(t1,n); MyOut(t2,n);

return 0; getch();

}

Зачем объявили и использовали указатели t1 и t2? Почему не использовали операции new и delete для t, t1 и t2?

4. Что означает цикл for (int I=0; w[I]; I++); если 1) w – числовой одномерный массив, 2) w -- строка; 3) w – массив указателей.

5. Дана программа.

void MyFun1 (float **X, int , int );

void MyOut (float *X[], int, int);

int main()

{ int ** A; int N=6, M=4; A=new float [M];

for (int i=0; i<N; i++) A[i]=new float* [N];

MyFun1(A,N,M); MyOut(A,N,M);

delete[]A; for (int i=0;i<N;i++) delete[]A[i];

getch(); return 0; }

void MyFun1 (float *X[], int n, int m)

// В динамической “матрице” размерности n* m надо поменять местами первую по порядку и последнюю строки, не перемещая их физически в памяти.

{ for (int i=0; i<n; i++)

for (int j=0;j<m;j++)

X[i][j]=(i+1)*(j+1);

int t; t=X[0]; X[0]=X[n-1]; X[n-1]=t;

}

void MyOut (float **X, int n, int m)

// Вывод динамической “матрицы” размерности n* m

{ for (int i=0; i<n; i++)

{ cout<<endl;

for (int j=0;j<m;j++) printf("%7.2f", X[i][j]);

} }

Найти ошибки, объяснить их и исправить.

7. Почему не работает следующий фрагмент программы?

const n=5; int ar1[n]={10, -2, 33, 4},

ar2[n]={111, -222, 333, 0, 555};

int *t; t=ar1; ar1=ar2; ar2=t;

Как её изменить, чтобы “переставить” местами два массива, не перемещая их элементы “физически” в памяти ? Как это сделать для динамических массивов?

8. Дан код

const n=3; char *S[n],

*t=new char[10]; //1

for(int i=0;i<n;i++)

{ gets(t); S[i]=t; //2

}

for(int i=0;i<n;i++) printf(“%s ”, S[i]);

Что будет выведено, если последовательно введём:

Иванов

Петров

Сидоров?

Варианты ответов:

1) Иванов Петров Сидоров

2) Сидоров Петров Иванов

3) Иванов Иванов Иванов

4) Сидоров Сидоров Сидоров

5) Ошибка в //1

6) Ошибка в //2: нет new для S[i].

9. Дан заголовок функции:

void FunMatr (int **X, int , int );

Какой из следующих вызовов правильный?

/*1*/ const Nc=5, Mc=10; int C[Nc][Mc]; FunMatr(C, Nc, Mc);

/*2*/ int ** A; int N=6, M=4; A=new float [N];

for (int i=0; i<N; i++) A[i]=new float* [M];

FunMatr(C, Nc, Mc);

Варианты ответов:

1) только /*1*/ ; 2) только /*2*/ ; 3) /*1*/ и /*2*/ ; 4) нет правильного.

10. Дан заголовок функции:

void FunArr1 (int *z, int );

Какой из следующих вызовов правильный?

int A[10]; FunArr1(A, 10); //1

int *d; int n; cin>>n; d= new int[n]; FunArr1(d, n); //2

Варианты ответов:

1) только //1; 2) только //2; 3) //1 и //2; 4) нет правильного.

11. Пусть объявлены следующие переменные: int x=10, *p, **q;

Какие из следующих операторов синтаксически правильные?

1) p=x; 2) p=&x; 3) q=p; 4) q=&p; 5) q=&(&p); 6) q=&x; 7) q=&(&x);

12. Пусть объявлена переменная int **u2;

Какие из следующих последовательностей операторов синтаксически правильные?

1) u2=new *int; *u2=new int; cin>>(**u2);

2) u2=new *int; *u2=new int; cout>>(**u2);

3) u2=new *int; cin>>*u2;

4) u2=new *int; cout>>*u2;

5) u2=new *int; *u2=new int; cout>>(**u2);

13. Как можно объявить D, чтобы D =new float *[n]; компилировалось и выполнялось? Выбери правильные варианты из предложенных:

1) const n=5; float *D;

2) const n=5; float **D;

3) int n; cin>>n; float *D;

4) int n; cin>>n; float **D;

5) int n; cin>>n; float f; float &D=f;

6) int n; cin>>n; float f; float &&D=f;

14. Что надо записать, чтобы было достаточно для того, чтобы

for (int i=0; i<n1; i++) D[i]=new int [n2];

компилировался и выполнялся? Выбери правильные варианты из предложенных:

1) const n1=5, n2=4; int *D[n1];

2) int n1=5; const n2=4; int *D[n1];

3) const n1=5; int n2=4; int *D[n1];

4) int n1=5, n2=4; int *D[n1];

5) const n1=5; int n2=4; int **D;

6) const n1=5; int n2=4; int **D; D=new int [n1];

7) const n1=5; const n2=4; int **D; D=new int [n2];

15. Пусть const n=5, m=6; int A[n][m]; В каких строках есть ошибки?

1) for (int i=0; i<n; i++) delete [] A[i]; delete [] A;

2) delete [] A; for (int i=0; i<n; i++) delete [] A[i];

3) for (int i=0; i<n; i++) delete [m] A[i]; delete [n] A;

4) for (int i=0; i<n; i++) for (int j=0; j<m; j++) delete A[i][j];

5) for (int i=0; i<n; i++) delete [] A[i]; delete A;

16. Дан код:

const n=5; char t[20]; char **S; S=new *char [n];

for (int i=0; i<n; i++)

{gets(t); S[i]=new char [strlen(t)];

//оператор1

… }

Какие из следующих операторов на месте оператора “оператор1” формально синтаксически правильные, хотя выполняют не обязательно одно и тоже и могут не иметь практического значения? Выбери правильные варианты из предложенных:

1) strcpy(S[i],t); 2) strcpy(S[i],t[i]); 3) strcpy(S, t); 4) S[i]=t;

5) t=S[i]; 6) S[i]=t[i]; 7) S[i][0]=t[0];

8) for (int j=0; j<strlen(t); j++) S[i][j]=t[j];

9) for (int j=0; j<=20; j++) S[i][j]=t[j];

17. Пусть const n=5, m=6; int A[n][m]; В каких строках есть ошибки?

1) int S[n]; for(int i=0; i<n; i++) S[i]=A[i];

2) int *S[n]; for(int i=0; i<n; i++) { S[i]=new int [m]; A[i]=S[i]; }

3) int **S; S=new *int [n]; for(int i=0; i<n; i++) S[i]=A[i];

4) int *S; S= A[0]; A[0]=A[n-1]; A[n-1]=S;

5) int S; S= A[0]; A[0]=A[n-1]; A[n-1]=S;

6) int S;for(int j=0; j<m; j++) {S=A[0][j]; A[0][j]=A[n-1][j];A[n-1][j]=S; }

18. Дан код.

const n=5; int * M[n]; //1

int arr_of_size[n];

for (int i=0; i<n; i++) cin>>arr_of_size[i];

for (int i=0; i<n; i++)

M[i]= new int[arr_of_size[i]]; //2

for (int i=0; i<n; i++)

for (int j=0; j<n; j++)

M [i][j]=i*j; //3

При каких значениях введённых элементов массива arr_of_size будет правильно работать приведённый фрагмент программы?

Варианты ответов:

1) При любых целых положительных значениях.

2) При любых значениях.

3) Если введём пять значений, каждое из которых равно 5.

4) Ошибка компиляции строки //1, так как n не должна быть константой.

5) Ошибка компиляции строки //2, так как в new нельзя использовать элемент массива.

6) Ошибка компиляции строки //3, так как для M нельзя использовать два индекса, это одномерный массив.

 



<== предыдущая лекция | следующая лекция ==>
Динамические “матрицы”. | Лабораторная работа 3.


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.266 сек.