Pointeurs C ++. partie 1





указатели с++, указатели c++, new delete c++

Собирая информацию для написания этой статьи, вспомнилось мне моё первое знакомство с указателямигрусть-печаль былаПоэтому после прочтения нескольких разделов по этой теме из разных книг о программировании на C++, было решено пойти иным путем и изложить тему Указатели C++ в той последовательности, в которой я считаю нужным. Сразу дам вам короткое определение и будем рассматривать указатели в работена примерах. В следующей статье (Pointeurs C ++. partie 2) будут изложены нюансы, применение указателей со строками в стиле Си (символьными массивами) и основное, что следует запомнить.

Указатель в С++ – variable, которая в себе хранит адрес данных (sens) в памяти, а не сами данные.

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

LET, в программе нам необходимо создать целочисленный массив, точный размер которого нам не известен до начала работы программы. То есть мы не знаем какое количество чисел понадобится пользователю внести в этот массив. Bien sûr, мы можем подстраховаться и объявить массив на несколько тысяч элементов (par exemple sur 5 000). Этого (по нашему субъективному мнению) должно хватить пользователю для работы. que – vraiment – этого может быть достаточно. Но не будем забывать, что этот массив займет в оперативной памяти много места (5 000 * 4 (тип int) = 20 000 octet). Мы то подстраховались, а пользователь будет заполнять только 10 элементов нашего массива. Il se trouve, что реально 40 байт в работе, et 19 960 байт напрасно занимают память.

В стандартную библиотечную функцию taille de() передаем объявленный массив arrWithDigits rangée 10. Она вернёт на место вызова размер в байтах, который занимает этот массив в памяти. На вопросСколько чисел вы введете в массив?” ответим – 10. En ligne 15, expression montant * taille de(int) Cela équivaudrait à 10 * 4, так как функция taille de(int) retour 4 (размер в байтах типа int). Далее введем числа с клавиатуры и программа покажет их на экран. Il se trouve, что остальные 4990 элементов будут хранить нули. Так что нет смысла их показывать.

C ++ pointeurs, c ++ pointeurs, Nouveau, effacer

Главная информация на экране: массив занял 20 000 octet, а реально для него необходимо 40 octet. Как выйти из этой ситуации? peut-être, кому-то захочется переписать программу так, чтобы пользователь с клавиатуры вводил размер массива и уже после ввода значения объявить массив с необходимым количеством элементов. Но это невозможно реализовать без указателей. Comme vous pouvez rappeler – размер массива должен быть константой. То есть целочисленная константа должна быть инициализирована до объявления массива и мы не можем запросить её ввод с клавиатуры. Поэкспериментируйтепроверьте.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

указатели с++, указатели c++, new, delete
Тут нам подсвечивает красным оператор >> так как изменять константное значение нельзя.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

указатели с++, указатели c++, new, delete
Тут нас предупреждают о том, что размером массива НЕ может быть значение обычной переменной. Необходимо константное значение!

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

В следующем коде мы будем использовать указатель и новые для вас операторы Nouveau (выделяет память) et effacer (освобождает память).

Пользователь вводит значение с клавиатуры – rangée 12. Ниже определён указатель: int* arrWithDigits Cette entrée signifie, que arrWithDigits – un pointeur. Он создан для хранения адреса ячейки, в которой будет находиться целое число. Dans ce cas, arrWithDigits будет указывать на ячейку массива с индексом 0. Знак * тот же что применяется при умножении. По контексту компилятор “comprendront”, что это объявление указателя, а не умножение. Далее следует знак = и оператор Nouveau, который выделяет участок памяти. Мы помним, что у нас память должна быть выделена под массив, а не под одно число. Запись Nouveau int [sizeOfArray] можно расшифровать так: Nouveau (выдели память) int (entiers de stockage) [sizeOfArray] (в количестве sizeOfArray).

Таким образом в строке 16 был определён tableau dynamique. cela signifie que, que la mémoire est allouée pour elle (ou est mis en évidence) au cours du programme, plutôt que lors de la compilation, comme cela est le cas avec les matrices conventionnelles. То есть выделение памяти зависит от развития программы и решений, которые принимаются непосредственно в её работе. Dans ce cas, – зависит от того, что введёт пользователь в переменную sizeOfArray

En ligne 25 применяется оператор effacer. Он освобождает выделенную оператором Nouveau память. depuis Nouveau выделил память под размещение массива, то и при её освобождении надо дать понять компилятору, что необходимо освободить память массива, а не только его нулевой ячейки, на которую указывает arrWithDigits. Поэтому между effacer и именем указателя ставятся квадратные скобки [] – effacer [] arrWithDigits; devraient se rappeler, что каждый раз, когда выделяется память с помощью Nouveau, необходимо эту память освободить используя effacer. Bien sûr, по завершении программы память, занимаемая ей, будет автоматически освобождена. Но пусть для вас станет хорошей привычкой использование операторов Nouveau et effacer в паре. Ведь в программе могут располагаться 5-6 массивов например. И если вы будете освобождать память, каждый раз, когда она уже не потребуется в дальнейшем в запущенной программепамять будет расходоваться более разумно.

Допустим в нашей программе мы заполнили массив десятью значениями. Далее посчитали их сумму и записали в какую-то переменную. И всёбольше мы с этим массивом работать уже не будем. Программа же продолжает работу и в ней создаются новые динамические массивы для каких-то целей. В этом случае целесообразно освободить память, qui occupe la première rangée. Тогда при выделении памяти под остальные массивы эта память может быть использована в программе повторно.

Рассмотрим использование указателей, как параметров fonction. pour un début, наберите и откомпилируйте следующий код. В нем функция получает две переменные и предлагает внести изменения в их значения.

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

C ++ pointeurs, c ++ pointeurs, Nouveau, effacer

Comme vous pouvez rappeler, функция работает не на прямую с переменными, а создает их точные копии. Эти копии уничтожаются после выхода из функции. То есть функция получила в виде параметра какую-то переменную, создала её копию, поработала с ней и уничтожила. Сама переменная останется при этом неизменной.

Используя указатели, мы можем передавать в функцию адреса переменных. Тогда функция получит возможность работать непосредственно с данными переменных по адресу. Внесём изменения в предыдущую программу.

В заголовке (rangée 27) и прототипе функции (rangée 5), добавляем операцию * перед именами параметров. Это говорит о том, что функция получит адреса, а не значения переменных. При вызове функции из Principal() добавляем перед именами передаваемых переменных операцию & (Ampersand – Décalage + 7). & означает взятие адреса. Вы помните, что указатель хранит адрес. Поэтому мы не можем передать обычное значение, если в заголовке указано, что функция примет указатель. Используя & перед именами переменных, функция получит их адреса.

В теле функции, при вводе значений в переменные, необходимо использовать разыменование указателей. Делается это с помощью всё той же операции * : gin >> *varForCh1; Так мы внесем изменения в значения переменных, а не в адреса. Проверим работу программы:

C ++ pointeurs, c ++ pointeurs, Nouveau, effacer

Всё получилосьзначения переменных были изменены в функции.

Такой способ (передача параметров в функцию через указатель) широко использовался в программировании на C. В C++ всё чаще используют передачу параметров в функцию по ссылке. Там отпадает необходимость использовать разыменование * и взятие адреса & les variables. Поэтому использовать передачу параметров по ссылке удобней. Этот способ мы с вами рассмотрим в следующих уроках.

Не переживайте, если что-то не совсем понятно. Вы получили много новой информации в этом урокеи это вполне нормально, что не всё воспринялось сразу. Понимание указателей придет с практикой. Мы еще поговорим об указателях во второй части к этой статье et порешаем задачи. Так что все будет нормально.

По возможности посмотрите видео об указателях (avec 12 minutes):

paramètres (arguments) fonction:




Bulletin de nouvelles leçons sur la programmation:

Pointeurs C ++. partie 1
3.8 (75%) 8 votes

9 réflexions sur "Pointeurs C ++. partie 1

  1. Примерно на 45-ой минуте 8-го урока говорится, что если не использовать константу, то по любому только выделять память через new. Но во время этого я подумал, что дело решается ещё одной переменной.
    int N;
    gin>>N;
    const int M=N;
    int d[M];

    pour (int i = 0;je!=M;i ++)
    {
    ré[je] = i;
    cout <<ré[je]<<endl;
    }

    И это у меня вполне компилируется.

    1. Вы могли бы и не присваивать M=N, а просто написать: int d[N].
      Но это не противоречит ничему сказанному – il расширение стандарта C++, пришедшее из стандарта C99 языка C (comme vous pouvez le voir, всё это стандарты самых последних лет!), и называется это VLA (Variable Legth Array).
      Это расширение позволяет создавать локальные внутри функции массивы с динамически определяемыми размерами. При этом массив создаётся в стеке вызываемой функции. fondamentalement, в C был и раньше скрытый способ делать то же самое с помощью вызова:

      Пользоваться VLA нужно, тем не менее, с осторожностью:
      это компилируется только если у компилятора установлены опции на новые стандарты;
      это нововведение вызывает много споров, и может быть отменено в будущих стандартах.

      1. Спасибо за подробные разъяснения. Я присваивал М = N из-за того, что автор видео показал, как напрямую, если не использовать ключевое слово const, не компилируется. А я сразу решил проверить, но немного по другому. à propos, в компиляторе давно я указывал с++11.

    2. Массив ваш занимает память, динамический массив работает как обычный, вот только память потом очищается, в больших проектах очень полезно

      1. Очень сомнительное утверждение!
        Массив объявленный локально (в функции) размещается в стеке и очищается при завершении функции. Особенно результативно это после разрешения массивов с динамическими границами стандартом C++11.
        А использование динамически размещаемых массивов, при определённых достоинствах, имеет ещё больше недостатков.

  2. Парадокс!!!
    Компиляторcompiler: GNU GCC Compilerпринял следующий код:

    #comprendre
    #comprendre

    using namespace std;

    int main()
    {
    setlocale(LC_ALL, “russe”);

    int SizeOfArray;
    cout << "Сколько чисел вы введёте в массив? " <> SizeOfArray;
    int arrWithDigits[SizeOfArray] = {};

    pour (int i = 0; je < SizeOfArray; i ++)
    {
    cout << je + 1 <> arrWithDigits[je];
    }
    cout << endl;

    pour (int i = 0; je < SizeOfArray; i ++)
    {
    cout << setw(3) << arrWithDigits[je] << " |";
    }
    cout << endl;
    retour 0;
    }

    programme, в которой работаю Code::Block 16.01.
    ————– Build: Debug in Zadacha12 (compiler: GNU GCC Compiler)—————

    mingw32-g++.exe -Wall -g -c C:\2\codeblocks-16.01\Code\Zadacha12\Zadacha12.cpp -o obj\Debug\Zadacha12.o
    mingw32-g++.exe -o bin\Debug\Zadacha12.exe obj\Debug\Zadacha12.o
    Output file is bin\Debug\Zadacha12.exe with size 1,01 MB
    Process terminated with status 0 (0 minute(s), 0 seconde(s))
    0 Erreur(s), 0 warning(s) (0 minute(s), 0 seconde(s))

    1. Парадокс то в чём?
      Компилятор GCC намного совершеннее компилятора от Microsoft, и гораздо точнее в синтаксисе соответствует стандартам языка C++.

Laisser un commentaire

Votre adresse email ne sera pas publiée. les champs requis sont indiqués *