Този урок ще обедини натрупаните познания от предишните уроци, така че ако не сте прочели внимателно предишните уроци, най-добре го направете, преди да продължите с този урок.

Масиви и указатели – какво е общото?

В концепцията на масивите и указателите има доста общи неща. Всъщност идентификатора на масива е указател, сочещ към първия му елемент. Например следният код е валиден:

  1. int numbers [10];
  2. int * ptr;
  3. ptr = numbers;

След изпълнението на този код, адресът, към който сочат указателите ptr и numbers, ще бъде един и същ, с единствената разлика, че адресът, към който сочи ptr, може да бъде променен, докато numbers винаги ще сочи към първия елемент от масива. Поради тази причина numbers се нарича още константен указател (указател, който не може да бъде променян). Например следният израз е невалиден:

  1. numbers = ptr;


Друго много важно свойство на масивите е, че елементите им са разположени на съседни клетки в паметта. Тоест ако първият елемент от масива се намира на адрес 4312, то вторият елемент се намира на адрес (4312 + 1) или 4313, аналогично третият елемент от масива се намира на адрес (4312 + 2) и т.н. Същественото, което трябва да забележим в случая е, че ако имаме адреса на първия елемент от масива и дължината на масива, то можем да достъпим всеки един елемент от масива. Разгледайте и тествайте следната програма:

  1. #include <iostream>
  2. using namespace std;
  3. int main ()
  4. {
  5.      int numbers[7];
  6.      int * ptr;
  7.      ptr = numbers;
  8.      *ptr = 0;
  9.     ptr++;
  10.     *ptr = 1;
  11.     ptr++;
  12.     *ptr = 2;
  13.     ptr = numbers + 3;
  14.     *ptr = 3;
  15.     ptr = numbers;
  16.     *(ptr+4) = 4;
  17.     *(ptr+5) = 5;
  18.     ptr = &numbers[6];
  19.     *ptr = 6;
  20.     for (int n=0; n<7; n++)
  21.     cout << numbers[n] << “ „;
  22.     return 0;
  23. }

 

0 1 2 3 4 5 6

В урока за масиви използвахме квадратни скоби ([]), за да определим индекса на елемент от масива, към който искаме да се обърнем. Както се вижда от горния пример, има и друг начин за това:

  1. numbers[9] = 0;
  2. *(numbers+9) = 0;

Двата израза са напълно еквивалентни – присвояват стойността 0 на десетия елемент от масива (не забравяйте че се брои от 0, за това е 10-ти, а не 9-ти елемент).

Масив като параметър на функция

Сигурно вече се досещате, защо трябваше да научим всичко това, преди да пристъпим към тази част – функциите приемат указател към масива като параметър. Има два еквивалентни начина, по които можем да дефинираме параметъра на нашата функция:

  1. int sumarr(int arr[])

е еквивалентно на:

  1. int sumarr(int* arr)

След това можем да обработваме масива посредством указателя към него. А това става точно така, както бихме го правили и в главната main() функция, тъй като изразите

  1. arr[5] = 0;
  2. *(arr+5) = 0;

са еквивалентни.

Задача 1: Довършете sumarr функцията, така че да връща сумата от елементите в масива.

Ако искаме нашата функция да връща масив. То тогава е напълно еквивалентно – връщаме указател към масива. За целта трябва да си дефинираме функцията по следния начин:

  1. int* negative_arr(int arr[])

Задача 2: Довършете функцията negative_arr, така че да връща масив с всички отрицателни стойности на получения в параметъра масив. (Може да приемете, че полученият масив съдържа поне една отрицателна стойност). Примерна main() функция, която трябва да изведе в конзолата първата стойност на върнатия от функцията масив.

int main()

  1. int main()
  2. {
  3. int y[10];
  4. for(int i=0; i<10; i++)
  5. cin >> y[i];
  6. int *a = negative_arr(y);
  7. cout << a[0] << endl;
  8. }

Автор: Мартин Михайлов