. Указатели в C/C++ для новичков (Часть 1)
Указатели в C/C++ для новичков (Часть 1)

Указатели в C/C++ для новичков (Часть 1)

Указатели в C/C++ сложная вещь для новичков. Без указателей программировать серьезные программы на С/С++ просто нельзя. Кроме того, указатели помогут понять как устроена память в компьютере, и как с ней работает процессор.Поэтому я сегодня попытаюсь объяснить вам доходчиво как они работают и зачем нужны. Прошу под кат. В первой части я расскажу об общем устройстве указателей, как они работают и зачем нужны.И так, начнем с базовой теории. Указатель это переменная указывающая на область памяти. Немножко кода:

С синтаксисом все понятно, достаточно просто поставить звездочку после типа данных. Возникает вопрос, а на что указывает указатель? Ответ прост — не на что. Почему? Потому, что мы его только объявили, но не указали на что ему указывать. Как все запутанно, правда? Когда мы объявляем переменную компьютер выделяет память для этой переменной в стеке. То есть код:

Указывает компьютеру, что нужно выделить память для переменной myVar1 типа int. Размер памяти выделяемой для нее зависит от самого компьютера. Например на 32-х разрядном компьютере он равен 4 байтам(32 бит). Когда мы пишем:

Компьютер значение 25 записывает по адресу выделенном для переменной myVar1; Когда мы пишем например:

Компьютер обращается по адресу переменной myVar1, берет оттуда значение и выводит его на экран.

Указатель же — это тоже переменная. И компьютер так же выделяет для нее память. Но в ней хранится адрес памяти. Что бы это проверить, сделаем следующее:

Программа объявляет указатель, а потом выводит его содержимое.Формат «%p» выводит на экран адрес памяти. Пока что, указатель указывает на случайный адрес, так как мы только создали, но не объявили ему на что указывать.

Примечание: при создании любых переменных(и указателей в том числе) в них находится мусор, так как компьютер не занимается очисткой области памяти, которая отводиться для переменных.

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

NULL — это так называемый «нулевой» указатель. Это поможет избежать ошибок. Так как в случайном адресе может храниться все что угодно. Кстати, для условных операторов NULL означает ложь. Напишем две программы. Первая будет выглядеть так:

А вторая так же, только заменим строку объявления указателя:

Откомпилируйте и запустите. В первом случае на экран выведеться адрес памяти, а во втором «Указатель не определен». Такое простое правило, как инициализация указателей NULL’ом и проверка через if(или любой другой условный оператор) помогает избежать ошибок.

Примечание: не ициализированный указатель содержит в себе мусор, так же как и не инициализированная переменная. Но он намного опаснее. К примеру, по адресу который случайно попал в не инициализированный указатель может лежать какая нибудь системная информация, и попытка с помощью указателя ее изменить может привести к непредвиденным последствиям, в плоть до краха ядра ОС.

Раз указатель указывает на переменную, то есть хранит в себе ее адрес памяти, значит можно как то получить ее адрес? Да, все верно. Адрес переменной получается с помощью символа «&», например:

При выполнении этого кода, выведется в консоль адрес переменной var1. Как вы уже наверно догадались, в указатель можно записать адрес переменной. Например так:

Программа выведет на экран:

Примечание: у вас будут другие значения адресов, так как они выделяются во время работы ОС и программы, вероятность того, что мой компьютер сделает это так же, как и ваш стремится к нулю!

Что нам это дает? Ну есть у нас указатель на переменную, там ее адрес памяти, что с ним делать? С помощью указателя, мы можем изменить саму переменную, например так:

Программа выведет на экран:

Как видите, переменной можно управлять с помощью указателя. И кстати, количество указателей не ограничено. Можно хоть сотню создать и все они могут указывать на одну и туже переменную. Указатели начинают приносить пользу, когда функция должна изменить значение какой-то переменной, переданной ей в качестве аргумента. Например наша функция func будет принимать 3 аргумента, первые два складывает, а значение записывает в третий, функция main создаст 3 переменные и передаст их функции:

Компилируем, запускаем. Наш ждет разочарование:

Попробуем найти ошибку. Добавим пару printf функций в нашу программу:

Компилируем, запускам, получается:

А все потому, что функция во время передачи ей переменных, просто создала копии. То есть a копия var1, b копия var2, ну и sum копия mySum. После выхода из функции переменные a, b, sum просто уничтожаются. Что же делать? Выход есть! Изменим нашу функцию:

Теперь наша функция принимает два аргумента типа int, а третий указатель на тип int. Функцию main изменим вот так:

Откомпилируем и запустим:

И так, подведем итоги:

  1. Указатель — это переменная, хранящая адрес памяти;
  2. Указатель может хранить адрес другой переменной, с его помощью можно менять значение переменной. Если быть более точным, меняется значение лежащее по указанному адресу;
  3. Указатели при создании желательно инициализировать либо NULL либо необходимым адресом;
  4. Указатели могут быть опасны для программы/системы, если с ними работать невнимательно.

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

📎📎📎📎📎📎📎📎📎📎