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



 

В случае двумерных массивов нужно точно соблюдать совпадение типов фактических и формальных параметров функции.

Примеры.

1. Функция находит максимальный элемент в массиве

int max(int A[][100], int KolStroc, int KolStolb);

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

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

int A[][100] = {{1,3,5}, {15,2,3}};

int res = max( A, 2, 3);

2. Функция находит сумму элементов двумерного массива

При передаче двумерного массива здесь использовано явное преобразование типа двумерного массива к типу одномерного массива. Это позволяет вызывать функцию для любых двумерных массивов.

int sum(int A[], int KolStroc, int KolStolb)

{

int s= 0;

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

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

s += A[i* KolSolb + j];

return s;

};

void main()

{

int B[2][3]={{1,4,2}, {4,1,2}};

int res = sum((int *)A, 2, 3);

printf(“%d”, s);

}

Тип и базовый тип указателя

 

Определение. Указателем называется переменная, объявленная следующим образом

type *имя_указателя;

Определение. Типом указателя называется type*.

Определение. Базовым типом указателя называется тип type данного, на который указывает указатель.

 

Примеры.

1. Одинарный указатель int *pi имеет тип int* и базовый тип int.

2. Одинарный указатель struct date *pd имеет тип date* и базовый тип date.

3. Двойной указатель float **ppf имеет тип float** и базовый тип float*.

4. Редкий тройной указатель char ***pppc имеет тип char *** и базовый тип char **.

Наиболее часто используются одинарные и двойные указатели, крайне редко тройные указатели. Указатели с 4 звездочками - признак ошибочной ситуации.

 

Правила определения типа указателей

 

· Применение к любой переменной name операции взятия адреса &name добавляет к типу результата одну *.

· Применение к любому указателю ptr операции разыменования *ptr удаляет из типа результата одну *.

· Применение к любому указателю ptr операции индексации ptr[0] удаляет из типа результата одну *.

Примеры.

int **ptr; // тип ptr – это int **

// тип *ptr – это int *

// тип **ptr – это int

// выражение ***ptr ошибочно

// тип ptr[0] – это int *

// тип ptr[3][5] – это int

// выражение ptr[1][1][1] ошибочно

// тип *ptr[0] – это int

// тип &(*ptr[0]) – это int*

 

Указатель на void

 

Указатель типа void * не имеет базового типа и для дальнейшей работы с ним к нему надо применить операцию явного преобразования типа.

Указатель типа void * указывает на все, что угодно. Ключевому слову void здесь приписывается не значение “ничего”, а противоположное значение ”все, что угодно”. Под слово void подпадают базовые типы, пользовательские типы, любые указатели: одинарные, двойные и т.д.

Таким образом, объявление void **ptr не имеет смысла, хотя и не будет являться логической ошибкой. Надо писать void *ptr.

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

int i=5, *pi = &i;

void *ptr;

ptr = pi;

//pi = ptr; ошибка

pi = (int *)ptr; // правильно

 

Константные указатели

 

При объявлении указателей можно использовать зарезервированное слово const. В отличие от обычных констант и макроподстановок константные объекты размещаются в памяти, но не являются объектами Lvalue, то есть не могут стоять в левой части операции присваивания.

Пример 1.

int *Arr = {1,3,2,4,5}, *B = {1,1};

При данном определении допустимы следующие два оператора

Arr[0]=100;

Arr = B;

Пример 2.

const int *Arr = {1,3,2,4,5}, *B = {1,1};

// Arr[0]=100; ошибка

Arr = B;

Пример 3.

int *const Arr = {1,3,2,4,5}, *B = {1,1};

Arr[0]=100;

//Arr = B; ошибка

Пример 4.

const int *const Arr = {1,3,2,4,5}, *B = {1,1};

//Arr[0]=100; ошибка

//Arr = B; ошибка

 

Обычно константные указатели используют для строк

const char* str = “Hello”;

В этом случае защищается содержимое текстовых строк.

Адресная арифметика

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

Пример.

1. int *A = (int *)malloc(20);

2. int **A; char *c; A = (int **)c;

Операция разыменования * возвращает значение, хранящееся в ячейке по адресу, содержащемуся в указателе.

Пример.

int i = 5, *pi = &i;

*pi = 10;// i =10

Получение адреса указателя. Подобно любым переменным, переменная типа указатель имеет адрес и значение. Операция & сообщает нам, где находится сам указатель.

Операция & добавляет к типу результата одну *.

Пример.

int n=20, *pn = &n, **ppn;

ppn = &pn;

Увеличение указателя. К указателю ptr можно прибавлять и вычитать любое целое число n. При этом указатель изменяется на количество байт равное n, умноженному на размер в байтах базового типа указателя ptr.

Соответственно, к указателям применимы операции инкремента ++ и декремента --.

Пример.

int n=20, *pn = &n, **ppn;

pn = pn + 5;

// базовый тип pn – int, занимает 2 байта, поэтому pn увеличится на 10 байт.

ppn = &pn+5;

// базовый тип выражения &pn – int*, занимает 4 байта для модели large, поэтому pn увеличится на 20 байт.

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

Разность указателей. Можно находить разность двух указателей одного типа. Результатом является количество элементов базового типа, находящимися между этими указателями. Результат имеет тип int для ближних указателей и тип long для дальних указателей.

Пример.

int A[10];

int *px = &A[1], *py = &A[9];

int n;

n = (int)(py - px); // n = 8

 


Дата добавления: 2020-01-07; просмотров: 164; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!