Указатели в C++

Указателят е специален вид променлива, предназначена да съхранява адреса на паметта на друга променлива. Декларирането на указател е толкова просто, колкото декларирането на всяка друга променлива, но е трудно да се борави с него. И така, ето един въпрос към вас: Как да подадете 2D масив във функция, ако параметрите на масива не са декларирани глобално? Изберете вашия отговор от дадените опции на изображението по-долу. Освен това предложете в коментара, ако имате друг подход.

Висящи указатели в C++

Указател, сочещ към място в паметта, което е изтрито/отменено или е извън обхвата, се нарича висящ указател. Причини за висящи показалци:

  • Указател към паметта, която сте изтрили.
int main()
{
    int num = 47;
    int *ptr = #
    
    free(num);
    //ptr is pointing to a de-allocated memory
    //dangling pointer
    cout<< ptr << endl;
}
  • Връща локална променлива при извикване на функция.
int *fun()
{
    int num = 47;
    return &num;
}
int main()
{
    int *ptr = fun();
    //ptr falls out of scope
    //dangling pointer
    cout<< ptr << endl;
}
  • Посочване на променлива, която е извън обхвата.
int main()
{
    int *ptr;
    {
        int num = 47;
        ptr = &num;
    }
    // ptr goes out of scope
    // dangling pointer
    cout<< ptr << endl;
}

Ето няколко въпроса, върху които да помислите!

  1. Какво е въздействието на наличието на висящи указатели в нашата програма?
  2. Как можем да избегнем висящите указатели в нашата програма?

Изтичане на памет в C++

Изтичане на памет възниква, когато ресурсите на паметта са разпределени и не са освободени правилно, след като вече не са необходими, често въведени чрез лоши практики за кодиране. Ако дадена програма има изтичане на памет, нейното използване на памет се увеличава и тъй като всички системи имат ограничена памет, това може да създаде проблеми.

Ето няколко въпроса, върху които да помислите!

  1. Какви са въздействията на изтичането на памет в нашата програма?
  2. Как можем да избегнем изтичане на памет?

Лош указател в C++

Когато указател е разпределен за първи път, той няма pointee, т.е. указателят е „неинициализиран“ или „лош“. Дереферираща операция върху лош указател е сериозна грешка по време на изпълнение. Кодът ще се компилира добре, но по време на изпълнение всяко дереференциране с лош указател ще повреди паметта по някакъв начин. В резултат на това програмата рано или късно ще се срине. Отговорността на програмиста е да гарантира, че на всеки указател е присвоен указател, преди да бъде използван.

Дерефериране на стойността на указателя, след като е бил освободен

Да предположим, че заделяме указател и освобождаваме свързаната памет, след като го използваме. Ако се опитаме да използваме показалеца отново, това ще завърши с недефинирано поведение: може би ще възникне срив, който зависи от състоянието на системата/платформата. Така че идеята би била никога да не се използва указател, след като е бил освободен. Дори добра практика е да зададете показалеца на 𝗡𝗨𝗟𝗟, след като е бил освободен, така че нарушаването на достъпа да улавя всеки опит за повторно използване.

И така, ето някои критични въпроси за изследване:

  1. Има ли начин отново да използвате показалеца? Мисля!
  2. Как системата се справя със статичното и динамично разпределяне и освобождаване на памет?

Статична памет в C++

Стекът е област в паметта на компютъра, която отговаря за съхраняването на 𝘁𝗲𝗺𝗽𝗼𝗿𝗮𝗿𝘆 𝘃𝗮𝗿𝗶𝗮𝗯𝗹𝗲𝘀. По време на изпълнение променливите се декларират, съхраняват и инициализират в стека. Тъй като стекът е временно хранилище на паметта, паметта на променливите се изтрива автоматично, след като изчислителната задача приключи.

Опит за освобождаване на памет в стека с помощта на функцията 𝗳𝗿𝗲𝗲() ще изведе 𝗮𝗰𝗰𝗲𝘀𝘀 𝘃𝗶𝗼𝗹𝗮𝘁𝗶𝗼𝗻. Управлението на паметта в стека (променливи без указател) се извършва имплицитно от системата.

Ето някои критични въпроси за изследване:

  1. Какъв е обхватът на променливите, съхранявани в Stack Memory?
  2. Как стекът разпределя паметта, използвана от временни променливи?

Динамично разпределение на паметта в C++

𝗛𝗲𝗮𝗽 памет, известна още като 𝗱𝘆𝗻𝗮𝗺𝗶𝗰 памет, е алтернатива на локалната стекова памет. Локалната памет е доста автоматична: тя се разпределя автоматично при извикване на функция и се освобождава автоматично, когато функция излезе.

Heap паметта е различна във всяко отношение. Програмистът трябва изрично да поиска разпределянето на памет 𝗯𝗹𝗼𝗰𝗸 с определен размер и блокът продължава да се разпределя, докато програмистът изрично не поиска да бъде освободен. 𝗛𝗲𝗿𝗲 𝗮𝗿𝗲 𝘀𝗼𝗺𝗲 𝗰𝗿𝗶𝘁𝗶𝗰𝗮𝗹 𝗾𝘂𝗲𝘀𝘁𝗶𝗼𝗻𝘀 𝘁𝗼 𝗲𝘅𝗽𝗹𝗼𝗿𝗲:

  1. Как разпределянето на памет на стек е предимство пред разпределянето на памет на стек?
  2. Добра практика ли е повторното използване на указателя след освобождаване на динамично разпределената памет?

Знаков масив и символен указател

Можем да инициализираме низ в C++ по различни начини, като масив от знаци или указател на знаци. Всеки един от тях има своите плюсове и минуси.

Ето някои критични въпроси за изследване:

  1. Намерете приликите и разликите между тях?
  2. Как системата разпределя памет във всеки случай?
  3. Кой от тях да предпочетем и защо?

Референтна променлива в C++

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

Операторът „&“ винаги ли е необходим при преминаване през референция?

Когато предава по референция, повикващият не винаги трябва да използва оператора „&“, за да изчисли нов указател към стойността, която представлява интерес. Понякога повикващият вече има указател към стойността, която представлява интерес, така че не се изисква ново изчисление на указателя. Указателят към стойността на интереса може да бъде прекаран непроменен.

Ключовата дума const в C++

В C++ const се използва, за да направи някои стойности постоянни в цялата програма, или с други думи, променливите, декларирани с ключовата дума const, стават константи и не могат да бъдат променяни от програмата.

Указателите могат да бъдат декларирани и с помощта на ключовата дума const. Когато използваме const с указатели, можем да го направим по два начина, или можем да приложим const към това, към което сочи указателят, или можем да направим самия указател константа.

Променливата ключова дума в C++

В езика за програмиране C/C++ променлива или обект, деклариран с ключовата дума volatile, обикновено има специални свойства, свързани с оптимизирането на обекти, които могат да се променят по начини, които компилаторът не може да определи.

Оптимизациите се извършват чрез кеширане на променливи в регистрите. Ключовата дума volatile е предназначена да попречи на компилатора да приложи каквито и да било оптимизации върху кода, които приемат, че стойностите на променливите не могат да се променят „сами по себе си“.

Ключовата дума volatile е предназначена да се използва в комбинация с променливи, които са достъпни и модифицирани в различни нишки. По принцип, без volatile, или писането на многонишкови програми става трудно, или компилаторът губи огромни възможности за оптимизация.

Шаблони в C++

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

Идеята на C++ шаблоните е проста: можем да направим код зависим от параметри, така че да може да се използва в различни ситуации, като инстанцираме параметрите според нуждите. Във всички езици за програмиране най-основната форма на код, който приема параметър, е функция.

Приятно учене, приятно програмиране!