第 5 集 · B1 · 7 分钟

C 语言 · 第5集 · 数组怎么建起来

从 Hello World、循环、递归讲到汉诺塔和动态规划,句子短,适合跟读。 开头:存储元素的类型,

C 语言 · 第5集 · 数组怎么建起来

中俄字幕

  1. тип хранимого элемента,

    存储元素的类型,

  2. выбрать какое- то имя для массива.

    为数组选择一个名称。

  3. Оно должно также, как и для переменной, состоять из латинских букв, может быть

    它和变量名一样,必须由英文字母组成,也可以包含

  4. цифры, подчёркивания.

    数字和下划线。

  5. дальше в квадратных скобках указать

    接着在方括号中指定

  6. число количество хранимых элементов, а индексы автоматически будут от нуля до не

    元素数量,而索引将自动从零开始,到该数值(含)为止。

  7. включительно этого числа.

    (即该数值)

  8. Можем ли мы использовать переменный размер у массива?

    数组能否使用可变大小?

  9. и да, и нет, переменной в том смысле, что при входе внутрь функции это число уже

    答案既是肯定的,也是否定的:所谓‘变量’是指,在进入函数时,该数值

  10. должно быть известно.

    必须已知。

  11. Или на момент объявления вот тут число, которое сюда подставлю, некоторое n, оно

    或者在声明时,此处要代入的数字(即某个n)

  12. должно быть уже заранее.

    必须事先确定。

  13. известно. И компилятор постарается выделить соответствующее количество памяти под n

    编译器会尝试为n个元素分配相应大小的内存。

  14. количество ячеек.

    个内存单元。

  15. Индексы элементов будут от нуля до n не включительно.

    元素的索引范围是从0到n(不包括n)。

  16. А вот что будет храниться в этих элементах?

    那么这些元素中究竟存储着什么?

  17. Ну вот если мы возьмем и просто распечатаем содержимое этого массива, выделив

    如果我们直接打印出已分配内存的该数组内容,让我们来看一下。

  18. память, давайте посмотрим.

    我们来看一看。

  19. Давайте взглянем.

    我们来看一下。

  20. Итак, вот перед вами программа, в которой я создаю массив из n элементов, перебираю

    现在您看到的是一个程序:我创建了一个包含n个元素的数组,并遍历它。

  21. все индексы, и для каждого индекса я достаюсь к ячейке а и той и распечатываю ее на

    所有索引,对每个索引,我访问数组a的对应单元并将其打印出来。

  22. экран. Пробелами обрамляю, чтобы это дело

    用空格包围,使输出更清晰。

  23. выглядело. Что мы смотрим?

    我们在看什么?

  24. Что мы видим? мы видим, что там какие- то странные числа, неадекватные, мы таких

    我们看到了什么?我们看到一些奇怪、不合理的数字,而我们并未向其中存入过这些数字。

  25. чисел туда не закладывали.

    我们从未将这些数字存入其中。

  26. Что это такое?

    这是什么?

  27. Это, ну, в каком- то смысле сырая память, то есть что- то, что жило на стэке до

    这在某种意义上是原始内存,即数组创建之前栈上已存在的数据。

  28. того, как там создали массив.

    也就是说,在该数组被创建之前,栈上原本就存在的内容。

  29. Если компилятор принял решение этот конкретный массив запихать в

    如果编译器决定将这个特定数组放入data段(静态数据段),

  30. data, статические данные, ну, вряд ли, конечно, он это сделал, глядя на вот это вот,

    当然,它几乎不可能仅凭这段代码就做出这种决定。

  31. потому что в статических данных я бы наблюдал скорее нули.

    因为静态数据中我更可能看到的是零。

  32. В общем, шанс на то, что там будут нули, есть, но на самом деле мы не можем

    总之,那里出现零是有可能的,但实际上我们不能

  33. положиться на начальное состояние массива, и мы должны его инициализировать.

    依赖数组的初始状态,而必须对其进行初始化。

  34. Как это сделать?

    如何实现?

  35. Мы можем явным образом задать значения, которые мы хотим.

    我们可以显式地指定想要的值。

  36. Да, вот беру шесть элементов у меня, да, n равно шести.

    是的,我这里有六个元素,没错,n 等于六。

  37. Я сейчас это n записал в константы этапа компиляции.

    我现在把 n 定义为编译期常量。

  38. То есть вот то, что сейчас написано, это макрос препроцессора, который отдельно

    也就是说,当前所写的这段内容是一个独立的预处理器宏,

  39. стоящую буковку.

    一个单独的字母。

  40. n текстовую, ее нельзя назвать переменной.

    这个 n 是文本形式的,不能称其为变量。

  41. Это текстовая подстановка, он будет заменять до компиляции на циферку 6.

    这是一个文本替换,编译前会被替换成数字6。

  42. ну в итоге у меня получается что везде где написано n будет на самом деле во время

    最终结果是,所有写有n的地方,在实际运行时

  43. компиляции стоять шестерка массив из шести элементов так вот в этом случае понятное

    编译时被替换为数字6,即一个包含6个元素的数组。因此在这种情况下,很明确的是

  44. дело я увижу состояние да вот они 1 2 3 4 5 6

    我看到的状态就是:1、2、3、4、5、6,

  45. ровно то что я туда заложил но если представить себе что это n большое то это не

    这正是我预先设定的内容。但如果设想n是一个很大的数,这种做法

  46. очень удачно. Чаще всего бывает нужно заполнить массив нулями.

    就不太合适了。通常,我们更需要将数组全部初始化为零。

  47. Если я этот список инициализации сделаю покороче, вот так, например, 1 2 3, то я

    如果我把这个初始化列表写得短一些,比如只写1、2、3,那么我将发现

  48. замечу, что все остальные элементы у меня заполняются автоматически нулями.

    其余所有元素会自动被填充为零。

  49. То есть инициализация все- таки произошла, и вот эти дикие числа, они стерты не

    也就是说,初始化确实发生了,而那些原本不可预测的数值,不仅在我指定的那三个单元格中

  50. только из тех трех ячеек, про которые я сказал.

    被清除了,而是整个数组都被清除了。

  51. Вот я могу свести так к самому простому случаю, да, вот 1 и все остальное, да, и

    我可以将其简化为最简单的情况,对,就是1,其余的都这样,对,而且

  52. сказать, а почему тогда не ноль?

    然后问:那为什么不是零呢?

  53. Давайте вот так вот сделаем.

    我们就这样来做。

  54. И вот это самый простой способ обнулить ваш массив, то есть инициализировать его.

    这是清空(即初始化)数组的最简单方法。

  55. нулями. Вот, двигаемся дальше.

    用零来初始化。好了,继续往下。

  56. Хотелось бы теперь научиться инициализировать массив не нулями, а чем- то другим.

    现在,我们还想学会用非零值来初始化数组。

  57. Для этого придется делать это вручную.

    为此,必须手动操作。

  58. Точно такой же перебор индексов понадобится, как это при распечатке.

    需要像打印时那样,逐个遍历所有索引。

  59. То есть вот я пробегаю все индексы от нуля до n не включительно,

    也就是说,我遍历从0到n(不包括n)的所有索引,

  60. и заполняю, соответственно, в a[ i] какое- то значение.

    并相应地将某个值填入a[i]中。

  61. Ну, давайте туда положим i.

    好吧,我们在这里放上 i。

  62. В чем преимущество?

    优势是什么?

  63. Что у нас теперь вот это вот действие будет работать не только для массива из шести

    现在,这个操作不仅适用于我手动编写的包含六个元素的数组,

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

    而且即使我修改了这里的 n,它也能正常工作。

  65. изменю. Давайте изменим это n, просто напишем сюда, например, там 10 или 20, и

    让我们修改这个 n,比如直接在这里写上 10 或 20,

  66. пожалуйста, у меня сразу вся программа, она перевычислена, перекомпилирована с этим

    然后,我的整个程序会立即根据这个新数值重新计算、重新编译。

  67. числом. Это очень удобно, потому что вы, наверное, видели, что у меня n не в одном

    这非常方便,因为您可能已经注意到,我的 n 并非只出现在一个地方,

  68. месте, а в целых уже трех местах.

    而是出现在整整三个地方。

  69. Если бы я шестерку туда вписал жестко, захардкодил ее, так говорят, захардкодил, то

    如果我把数字 6 直接硬编码进去,那么

  70. мне было бы неудобно переписывать это при другом n, а так я легко меняю этот

    当 n 变化时,我就得费力地到处修改;而现在,我只需轻松更改这个值即可。

  71. параметр, и у меня такой- то другой массив, другой его параметр размера.

    一个参数,而我有另一个数组,它的另一个尺寸参数。

  72. Давайте вернемся к шестерке.

    让我们回到第六个元素。

  73. и сделаем другое заполнение этого массива.

    并对该数组进行另一种填充。

  74. Кроме заполнения в прямыми индексами, просто индексами, мне хотелось бы добиться

    除了用直接索引(即普通索引)填充外,我还希望实现

  75. заполнения в обратку: 5, 4, 3, 2, 1, 0.

    反向填充:5、4、3、2、1、0。

  76. В этом случае мне потребуется.

    在这种情况下,我需要

  77. следующая формула заполнения в нулевом индексе пятерка, в первом четверка, во втором

    以下填充公式:零索引处填5,第一索引处填4,第二索引处填

  78. тройка. И мне очевидно.

    3。显然,

  79. что нужно вычитать из пятёрки.

    需要从5中减去某个值。

  80. Но если я хочу сделать так, чтобы это работало не только для массива размера 6, а

    但如果我希望它不仅适用于大小为6的数组,而是

  81. для любого массива размера n,

    对于任意大小为 n 的数组,

  82. то мне нужно придумать формулу.

    那么我需要想出一个公式。

  83. И я пытаюсь это сделать.

    我正在尝试这样做。

  84. Я говорю: давайте n минус i будет формула заполнения.

    我说:让 n 减 i 作为填充的公式。

  85. а нет, не получается.

    啊,不行,这样行不通。

  86. 6 минус 0- это получается у нас 6.

    6 减 0 等于 6。

  87. Значит, мне нужно еще сделать минус 1 оттуда.

    所以,我还需要再减去 1。

  88. Вот n минус i минус 1 даст мне то, что нужно.

    那么 n 减 i 再减 1 就能得到我需要的结果。

  89. Давайте посмотрим на это дело.

    我们来看看这个。

  90. n минус i. Минус один.

    n 减 i,再减 1。

  91. Поехали. 5 4 3 2 1 0.

    开始。5、4、3、2、1、0。

  92. Вот оно благополучно у нас посчиталось.

    好了,我们已成功完成计算。

  93. Так, теперь следующая задачка.

    好,接下来是下一道题。

  94. Я хотел бы это же заполнение реализовать иначе.

    我想用另一种方式实现相同的填充操作。

  95. смотрите, я могу пробегать этот массив и заполнять его в обратном порядке.

    请看,我可以遍历这个数组,并以逆序方式填充它。

  96. Для этого я сейчас вот этот вот n минус i минус 1

    为此,我现在将这里的 n 减 i 减 1

  97. поставлю внутрь квадратных скобок, а заполнять буду индексами.

    放入方括号内,然后用索引进行填充。

  98. Чем будет отличаться это заполнение?

    这种填充方式有什么不同?

  99. На первой итерации тогда, когда i равно нулю, я вычисляю ячейку, в которую я буду

    在第一次迭代时,也就是当 i 等于 0 时,我先计算要写入的单元格位置,

  100. класть, и туда кладу ноль.

    然后把 0 放进去。

  101. на второй итерации i равняется единице я вычисляю четверку это ячейка в которую я

    在第二次迭代中,i 等于 1,我计算四元组,即我要写入的单元格。

  102. буду класть и туда кладу единицу то есть мой массив в этом случае будет заполняться

    我会放进去,那里放1,也就是说,我的数组在这种情况下会被填充。

  103. справа налево.

    从右到左。

  104. а не слева направо.

    而是从右到左。

来源:Тимофей Хирьянов · CC BY 3.0

同系列