Pointers C ++. Teil 1





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

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

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

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

Lassen Sie uns, в программе нам необходимо создать целочисленный массив, точный размер которого нам не известен до начала работы программы. То есть мы не знаем какое количество чисел понадобится пользователю внести в этот массив. natürlich, мы можем подстраховаться и объявить массив на несколько тысяч элементов (beispielsweise auf 5 000). Этого (по нашему субъективному мнению) должно хватить пользователю для работы. dass – действительноэтого может быть достаточно. Но не будем забывать, что этот массив займет в оперативной памяти много места (5 000 * 4 (тип int) = 20 000 Byte). Мы то подстраховались, а пользователь будет заполнять только 10 элементов нашего массива. Es stellt sich heraus,, что реально 40 байт в работе, und 19 960 байт напрасно занимают память.

В стандартную библиотечную функцию Größe von() передаем объявленный массив arrWithDigits Reihe 10. Она вернёт на место вызова размер в байтах, который занимает этот массив в памяти. На вопросСколько чисел вы введете в массив?” ответим – 10. On line 15, выражение Menge * Größe von(int) wäre gleichbedeutend mit 10 * 4, так как функция Größe von(int) Rückkehr 4 (размер в байтах типа int). Далее введем числа с клавиатуры и программа покажет их на экран. Es stellt sich heraus,, что остальные 4990 элементов будут хранить нули. Так что нет смысла их показывать.

C ++ Zeiger, c ++ Zeiger, neu, löschen

Главная информация на экране: массив занял 20 000 Byte, а реально для него необходимо 40 Byte. Как выйти из этой ситуации? vielleicht, кому-то захочется переписать программу так, чтобы пользователь с клавиатуры вводил размер массива и уже после ввода значения объявить массив с необходимым количеством элементов. Но это невозможно реализовать без указателей. Wie Sie erinnern sich vielleicht, – размер массива должен быть константой. То есть целочисленная константа должна быть инициализирована до объявления массива и мы не можем запросить её ввод с клавиатуры. Поэкспериментируйтепроверьте.

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

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

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

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

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

В следующем коде мы будем использовать указатель и новые для вас операторы neu (выделяет память) und löschen (освобождает память).

Пользователь вводит значение с клавиатуры – Reihe 12. Ниже определён указатель: int* arrWithDigits Dieser Eintrag bedeutet,, dass arrWithDigits это указатель. Он создан для хранения адреса ячейки, в которой будет находиться целое число. In diesem Fall arrWithDigits будет указывать на ячейку массива с индексом 0. Знак * тот же что применяется при умножении. По контексту компиляторпоймет”, что это объявление указателя, а не умножение. Далее следует знак = и оператор neu, который выделяет участок памяти. Мы помним, что у нас память должна быть выделена под массив, а не под одно число. Запись neu int [sizeOfArray] можно расшифровать так: neu (выдели память) int (Lagerung ganzen Zahlen) [sizeOfArray] (в количестве sizeOfArray).

Таким образом в строке 16 был определён dynamisches Array. Das heisst, что память под него выделится (или не выделится) во время работы программы, а не во время компиляции, как это происходит с обычными массивами. То есть выделение памяти зависит от развития программы и решений, которые принимаются непосредственно в её работе. In diesem Fall – зависит от того, что введёт пользователь в переменную sizeOfArray

On line 25 применяется оператор löschen. Он освобождает выделенную оператором neu память. Als neu выделил память под размещение массива, то и при её освобождении надо дать понять компилятору, что необходимо освободить память массива, а не только его нулевой ячейки, на которую указывает arrWithDigits. Поэтому между löschen и именем указателя ставятся квадратные скобки [] – löschen [] arrWithDigits; Следует запомнить, что каждый раз, когда выделяется память с помощью neu, необходимо эту память освободить используя löschen. natürlich, по завершении программы память, занимаемая ей, будет автоматически освобождена. Но пусть для вас станет хорошей привычкой использование операторов neu und löschen в паре. Ведь в программе могут располагаться 5-6 массивов например. И если вы будете освобождать память, каждый раз, когда она уже не потребуется в дальнейшем в запущенной программепамять будет расходоваться более разумно.

Допустим в нашей программе мы заполнили массив десятью значениями. Далее посчитали их сумму и записали в какую-то переменную. И всёбольше мы с этим массивом работать уже не будем. Программа же продолжает работу и в ней создаются новые динамические массивы для каких-то целей. В этом случае целесообразно освободить память, das belegt die erste Reihe. Тогда при выделении памяти под остальные массивы эта память может быть использована в программе повторно.

Рассмотрим использование указателей, как параметров Funktion. Für den Anfang, наберите и откомпилируйте следующий код. В нем функция получает две переменные и предлагает внести изменения в их значения.

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

C ++ Zeiger, c ++ Zeiger, neu, löschen

Wie Sie erinnern sich vielleicht,, функция работает не на прямую с переменными, а создает их точные копии. Эти копии уничтожаются после выхода из функции. То есть функция получила в виде параметра какую-то переменную, создала её копию, поработала с ней и уничтожила. Сама переменная останется при этом неизменной.

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

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

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

C ++ Zeiger, c ++ Zeiger, neu, löschen

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

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

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

По возможности посмотрите видео об указателях (mit einer 12-minütigen):

Parameter (Argumente) Funktion:




Abonnieren Sie neue Beiträge auf unserer Seite Ankündigung:


Ich bin damit einverstanden, Nachrichten zu empfangen von purecodecpp.com auf meine E-Mail

Datum
Seite
Pointers C ++. Dynamische Arrays C ++
Wertung
5

7 Gedanken zu "Pointers C ++. Teil 1

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

    für (int i = 0;ich!=M;i ++)
    {
    d[ich] = i;
    cout <<d[ich]<<endl;
    }

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

    1. Вы могли бы и не присваивать M=N, а просто написать: int d[N].
      Но это не противоречит ничему сказанному – Das расширение стандарта C++, пришедшее из стандарта C99 языка C (wie Sie sehen können, всё это стандарты самых последних лет!), и называется это VLA (Variable Legth Array).
      Это расширение позволяет создавать локальные внутри функции массивы с динамически определяемыми размерами. При этом массив создаётся в стеке вызываемой функции. Im Prinzip, в C был и раньше скрытый способ делать то же самое с помощью вызова:

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

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

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

    #einschließen
    #einschließen

    using namespace std;

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

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

    für (int i = 0; ich < SizeOfArray; i ++)
    {
    cout << ich + 1 <> arrWithDigits[ich];
    }
    cout << endl;

    für (int i = 0; ich < SizeOfArray; i ++)
    {
    cout << setw(3) << arrWithDigits[ich] << " |";
    }
    cout << endl;
    Rückkehr 0;
    }

    Programm, в которой работаю 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 zweite(s))
    0 Fehler(s), 0 warning(s) (0 minute(s), 0 zweite(s))

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

Hinterlasse eine Antwort

Platz Code in Tags: <pre class="lang:c ++ dekodieren:true ">DEIN CODE</Vor>