Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛекцииЛаб(Часть_1_Книги).doc
Скачиваний:
7
Добавлен:
03.05.2019
Размер:
1.04 Mб
Скачать

4.2. Указатель в качестве параметра цикла

Параметром цикла может быть переменная-указатель.

void MySum2(int* ar, unsigned size, int &S)

{ int *p=ar; S=0;

for ( ; p<= ar+(size-1); p++) S+=*p;

}

Если бы дополнительно указатель p для цикла не использовали, а ограничились бы только переменной ar, то мы потеряли бы доступ к началу массива, то есть его адрес. Более того, для статического массива адрес его начала (имя массива) компилятор не разрешит менять. Поэтому и в одном и в другом случаях надо объявить и использовать другой указатель (в функции таким является p) для использования его в цикле.

Можно цикл записать и так: for ( ; p<=&ar[size-1]; p++) S+=*p; Вариант, записанный в функции, лучше, так как мы “помогли компьютеру” найти адрес последнего элемента массива и не требуем, чтобы система преобразовывала индексное выражение. Можно объявить и проинициализировать ещё один указатель int *q=ar +size-1; и использовать его в заголовке цикла: for (; p<=q; p++) S+=*p;

Правильно будет работать и следующий вариант функции

void MySum3 (int *ar, unsigned size, int *uS)

{ int *p, *q=&ar[0]+size-1;

for (*uS=0, p=ar; p<=q;p++) *uS+=*p;

}

Здесь начальное значение указателя p определили в заголовке цикла, который можно записать и так: for ( *uS=0, p=&ar[0]; p<=q; p++) … Но вариант в функции компьютеру больше понравится. Подумайте, почему. Кроме этого, результат функции получаем с помощью указателя uS. Поэтому в тексте функции для uS используется операция “*”.

Заметим, что во всех этих вариантах вместо условия p<= ar+size-1; в заголовке цикла можно записать p< ar+size; , и такой вариант будет правильно работать. Но так как ar+size — это адрес “не нашей”, то есть не принадлежащей нашему массиву ячейки, то первое условие в виде нестрогого неравенства предпочтительнее.

4.3. Использование указателя и индекса

Когда непросто определить условие выхода из цикла с помощью указателя, то в заголовке оператора цикла можно использовать как переменную-указатель, так и индекс.

void MySum4 (int *ar, unsigned size, int *uS)

{ int *p=ar; unsigned i;

for (*uS=0, i=0; i<size; p++, i++) *uS+=*p;

}

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

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

void MyInp ( int *ar, unsigned size)

{ int *p=ar;

for (int i=0; i<size; i++) *(p+i)=random(20)-10;

}

void MyOut ( int *ar, unsigned size)

{ int *q=ar+size-1; cout<<endl;

for (; ar<=q;ar++) cout<<(*ar)<< " ";

cout<<endl;

}

int main()

{ // a) Работа со статическим массивом

const n=5; int a[n] ={1,2,3,4,5}, S2, S3;

cout<<MySum0(a,n)<<" "<<MySum1(a, n)<< endl;

MySum2(a,n, S2); cout<<S2<<" ";

MySum3(a,n, &S3); cout<<S3<<" ";

int *S4= new int;

MySum4(a,n, S4); cout<<*S4<<" "<< endl;

// b) Использование функций для динамического массива

randomize();

unsigned N; N=random(10)+2;

int *aD=new int[N];

MyInp(aD, N); MyOut(aD,N);

cout<<MySum0(aD,N)<<" "<<MySum1(aD, N)<< endl;

MySum2(aD,N, S2); cout<<S2<<" ";

MySum3(aD,N, &S3); cout<<S3<<" ";

MySum4(aD,N, S4); cout<<*S4<<" ";

getch(); return 0;

}

Обратите внимание на вызов функций MySum3 и MySum4. Особенности их вызова по сравнению с MySum2 связаны не с тем, как организован цикл в этих функциях, а с тем, что одно целочисленное значение возвращается из функции с помощью указателя, а не с помощью переменной ссылочного типа. Для лучшего понимания этих вариантов повторите § 3 главы 1.