第 9 集 · B1 · 7 分钟
C 语言 · 第9集 · 指针和地址
从 Hello World、循环、递归讲到汉诺塔和动态规划,句子短,适合跟读。 开头:基本上,我们已经结束了关于学校算法和C语言语法的讨论。

中俄字幕
в принципе завершили разговор о школьных алгоритмах, о синтаксисе языка Си в рамках
基本上,我们已经结束了关于学校算法和C语言语法的讨论。
школьных алгоритмов.
学校算法。
Но я хочу немножко ввести вас во взрослый разговор о программировании на Си.
但我想稍微带你们进入关于C语言编程的成人级讨论。
Дело в том, что переменная представляет из себя, как я уже говорил, ячейку в памяти.
事实上,正如我之前所说,变量本质上是内存中的一个单元。
Да, вот если я заведу какую- нибудь переменную, и у нее есть какое- то место в
是的,如果我声明某个变量,它在进程内存中就占据某个位置。
памяти процесса.
进程内存。
это место характеризуется адресом.
这个位置由地址来表征。
Соответственно, у этой ячейки есть адрес.
因此,该内存单元具有一个地址。
Адрес этих нескольких байт, которые занимает переменная
变量i所占用的这几个字节的地址
i, является числом.
i是一个数字。
Понятно, да? То есть, соответственно, вот это имя, вот это имя i, оно соответствует
明白了吗?也就是说,这个名称,即这个变量名 i,对应于
некоторому адресу, да?
某个内存地址,对吗?
Оно эквивалентно некоторому адресу.
它等价于某个内存地址。
В то же время этот адрес нам неизвестен.
但该地址对我们而言是未知的。
Мы когда пишем программу, мы пользуемся символьным именем.
我们编写程序时,使用的是符号名称。
Компилятор же, он использует и то и другое.
而编译器则同时使用符号名和地址。
Он как раз связывает имя переменной и адрес, потому что на машинных кодах имен у
编译器正是将变量名与内存地址关联起来,因为机器码中并不存在变量名。
переменных не существует.
变量名在机器码中并不存在。
Только адреса, вот мы обращаемся к этому реальному адресу в памяти, как- то ее
只有内存地址;我们通过访问内存中的这个实际地址来操作数据,以某种方式对其进行解释。
интерпретируем.
我们以某种方式对其加以解释。
Понятно? То есть есть реальный адрес, адрес указывает на ячейку, а имя, когда я
明白了吗?也就是说,存在一个真实的地址,这个地址指向一个内存单元,而当我
показывал, что имя.
展示名称时,
переменной указывает на ячейку, это не совсем правда.
变量名指向内存单元——这种说法并不完全准确。
Это наша человеческая логическая связка.
这其实是人类逻辑上的一种关联。
Соответственно, за каждой реальной переменной, которую мы называем lvalue, да,
因此,每一个我们称之为左值(lvalue)的真实变量——是的,
lvalue, то есть та, в которую можно присваивать, та, за которой стоит реальная
即可以赋值给它的变量,其背后对应着一个真实的
ячейка памяти, да, так вот, у нее есть адрес.
内存单元——是的,它拥有一个地址。
Этот адрес можно узнать.
这个地址可以被获取。
Можно узнать этот адрес.
我们可以获取这个地址。
Для этого в языке Си есть вот такая вот
在C语言中,为此提供了这样一个
инструкция, вот такая операция.
指令,就是这样的操作。
Унарная операция, ей не нужен никакой бинарный сюда.
一元操作,它不需要任何二元操作参与。
напарник. Соответственно, я могу реально взять и получить вот это вот число.
搭档。因此,我实际上可以取到这个数。
Какого типа будет это число?
这个数是什么类型?
Вот эта штуковина, вот эта штуковина, она имеет особенный тип.
这个东西,这个东西,它具有特殊的类型。
У нее тип. если i это int, например, ну мне так удобно будет, да, то у нее будет тип
它有类型。例如,如果 i 是 int 类型,这样写对我更方便,那么它的类型就是
int звездочка.
int*。
Ну, чтобы было понятно, что эта звездочка является неотъемлемым именем этого типа, я
为了清楚表明这个星号是该类型名称不可分割的一部分,我
в скобочки возьму.
会把它括起来。
не обязательно.
这不是必须的。
Тип он и так вот такой.
这种类型本来就是这样的。
Но просто я подчеркну, да, что вот int вместе со звездочкой- это тип
但我再强调一下,带星号的 int 就是这个地址的类型。
этого адреса. Вопрос: а если адрес- это число?
问题来了:如果地址本身是一个数字呢?
значит это число можно сохранить,
那么这个数字就可以被保存下来,
правильно? то есть вот этот адрес можно положить в соответствующую переменную,
对吧?也就是说,这个地址可以存入对应的变量中,
правда? для этого мне достаточно создать таковую переменную.
对吧?为此,我只需创建这样一个变量即可。
int* p_i назову я такой
我将这种变量命名为 int* p_i。
переменной. int* pi и положу туда адрес i.
int* pi,并把 i 的地址存入其中。
точка с запятой.
分号。
Я прям это при инициализации сделал, это не имеет значения.
我是在初始化时直接这么做的,这并不影响结果。
что это за переменная?
这是什么变量?
Вот такая переменная адресного типа, потому что это адресный тип.
这是一个地址类型变量,因为它的类型就是地址类型。
адресный тип, да?
地址类型,对吗?
А это, соответственно, переменная адресного типа.
相应地,这也是一个地址类型变量。
в которую мы адрес сохранили.
我们把地址保存到了这个变量中。
Да, так вот эта переменная адресного типа называется указатель.
是的,这种地址类型变量就叫指针。
Понятно? То есть у нее прям так и говорят, это указатель.
明白了吗?也就是说,它就直接被称为指针。
А теперь смотрите.
现在请看。
Фактически, если я говорю про то, что у меня появилась переменная адресного типа.
实际上,如果我说我创建了一个地址类型变量。
Раз у меня есть переменная, то это что значит?
既然我有了一个变量,这意味着什么?
Что есть ячейка, в которой хранится этот адрес.
存储该地址的单元格是什么?
Это какое- то число.
这是一个数字。
Я ж не буду пытаться там нолики и единички, я, знаете, я просто напишу сюда такую
我不会去尝试写那些0和1,你知道的,我就直接在这里写一个
звёздочку. И покажу, что эта звёздочка, она фактически указывает мне вот туда.
星号,并表明这个星号实际上指向这里。
Я взял вот этот адрес и сохранил его вот сюда.
我取了这个地址,并把它存到了这里。
И, соответственно, я могу, вот этот адрес, он характеризует мне местоположение вот
相应地,这个地址标示了
этой. ячейке, которая соответствует первой переменной i.
这个单元格,它对应于第一个变量i。
Понятно, да? А теперь давайте продолжим эту историю.
明白了吗?现在我们继续讲下去。
Дело в том, что этот.
事实上,这个
указатель, являясь переменной, сам имеет соответствующий ему адрес.
指针作为一种变量,自身也有对应的地址。
правда? А что если я возьму.
真的吗?如果我取呢。
адрес этого указателя.
这个指针的地址。
адрес этой переменной.
这个变量的地址。
Почему же? Но он есть этот адрес.
为什么呢?但这个地址确实存在。
Есть, он реально вот как раз и отвечает за эту ячейку на самом же деле, имя просто
确实存在,它实际上就对应着这个内存单元,而名称只是
связано с адресом.
与地址相关联。
значит у этого значения, у вот этого числа
也就是说,这个值、这个数字
тоже будет адресный тип, но другой.
也会有地址类型,但类型不同。
у него будет тип int**.
它的类型将是 int**。
Пусть вас не пугает.
请不要被吓到。
Ну, можно, приписывая к любому типу справа звёздочку, мы получаем его
嗯,可以通过在任意类型右侧添加星号(*)来得到该类型的
адресный тип, то есть тип адреса на данную переменную.
指针类型,即指向该变量的地址类型。
Поэтому у меня получается int**.
因此我得到了 int**。
я назову такую переменную вот этого типа ppi pointer pointer int,
我将这种类型的变量命名为 ppi(即 int 指针的指针)
и положу ей вот это самое значение в качестве начального значения.
并将其初始值设为这个值。
да понятна логика то есть я что сделал я создал переменную ppi да
逻辑很清晰:我创建了一个名为 ppi 的变量,对吧?
то есть ячейку в памяти которая.
也就是内存中的一块存储单元。
Теперь содержит адрес,
它现在存储一个地址,
указывающий мне на что?
这个地址指向什么呢?
Ну вот я взял вот этот вот адрес и запихал его сюда.
我把这个地址取出来,填入这里。
Он указывает мне на вот эту ячейку.
他指着这个单元格给我看。
Ясно, да? Вот такая вот интересная история.
明白了吗?就是这样一个有趣的故事。
При этом у этого PPI, естественно, как у ячейки памяти, у
同时,这个PPI自然也像内存单元一样,拥有
нее тоже есть собственный адрес какой- то, некий адрес, который ей соответствует.
它自己的某个地址,一个与之对应的地址。
если я захочу я могу создать ячейку пп
如果我想,我可以创建一个PP单元格。
来源:Тимофей Хирьянов · CC BY 3.0