[Powered by Google Translate] [Часть 4 - более комфортной] [Rob Боуден - Гарвардский университет] [Это CS50. - CS50.TV] У нас есть тест завтра, в случае, если вы, ребята, не знаю, что. Это в основном все, что вы могли видеть в классе или должны были видеть в своем классе. Это включает в себя указатели, даже если они совсем недавно тема. Вы должны по крайней мере, понять высокого уровня из них. Все, что было перешли в класс вы должны понимать, для викторины. Так что если у вас есть вопросы по ним, вы можете задать их сейчас. Но это будет очень студента под руководством сессии, где вы, ребята, задавать вопросы, так что надеюсь, людям есть вопросы. У кого-нибудь есть вопросы? Да. >> [Студент] Можете ли вы перейти на указатели снова? Я пойду за указателями. Все ваши переменные обязательно жить в памяти, но обычно вы не волнуйтесь об этом, и вы просто говорите х + 2, у + 3 и компилятор будет выяснить, где живут вещи для вас. Когда вы имеете дело с указателями, теперь вы явно с помощью этих адресов памяти. Таким образом, одной переменной будет только когда жить по одному адресу в любой момент времени. Если мы хотим объявить указатель, то, что тип будет выглядеть? Я хочу объявить указатель р. Что же типа выглядят? [Студент] Int * р. >> Да. Так Int * р. А как сделать, чтобы она указывала на х? >> [Студент] Ampersand. [Боуден] Так амперсанд буквально называется адрес оператора. Поэтому, когда я говорю, и х он становится адрес памяти переменной х. Так что теперь у меня есть указатель р, и в любом месте в моем коде я могу использовать * р или я мог бы использовать х, и это будет одно и то же. (* Р). Что это делаешь? Что означает, что звезда в виду? [Студент] Это означает значение в этой точке. >> Да. Так, если мы смотрим на него, он может быть очень полезно, чтобы вытянуть диаграмм где это маленькая коробочка памяти для х, в котором есть значение 4, Затем у нас есть маленькая коробочка памяти для р, и так с точки х, так что мы рисуем стрелку от р х. Поэтому когда мы говорим * р мы говорим пойти в окно, р. Звезда следуйте за стрелкой, а затем делать все, что вы хотите с этой коробке прямо там. Поэтому я могу сказать * р = 7, и что пойдет на ящик, который является х и изменения, которые до 7. Или я мог бы сказать Int г = * р * 2; Это заблуждение, потому что это звезда, звезда. Одна звезда разыменования р, другая звезда умножением на 2. Обратите внимание, я мог бы с таким же успехом заменили * р с х. Вы можете использовать их таким же образом. А потом на меня может быть с точки на совершенно новую вещь. Я могу только сказать, р = &z; Так что теперь P больше не указывает на х; он указывает на г. И в любое время я * р это так же, как делал г. Таким образом, полезная вещь об этом как только мы начинаем получать по функциям. Это своего рода бесполезные объявить указатель, который указывает на то, а затем вы просто разыменования его когда вы могли бы использовать оригинальный переменную с самого начала. Но когда вы получаете в функции - так скажем, у нас есть некоторые функции, внутр Фу, , которая принимает указатель и просто делает * р = 6; Как мы видели раньше с подкачки, вы не можете сделать эффективный обмен и отдельные функции от просто проходили целые потому что все в C всегда проходящих по значению. Даже тогда, когда вы передаете указатель вы передаете по значению. Просто так получилось, что эти значения адресов памяти. Поэтому когда я говорю Foo (р); я передаю указатель в функции Foo , а затем Foo делает * р = 6; Таким образом, внутри этой функции, * р-прежнему эквивалентно х, но я не могу использовать х внутри этой функции, потому что это не областью в этой функции. Так * р = 6 является единственным способом я могу получить доступ из локальной переменной другую функцию. Или, хорошо, указатели являются единственным способом я могу получить доступ к локальной переменной из другой функции. [Студент] Допустим, вы хотели возвращать указатель. Как именно вы это сделали? [Боуден] Возвращает указатель, как в нечто вроде Int у = 3; возвращение & Y? >> [Студент] Да. [Боуден] Хорошо. Вы никогда не должны это делать. Это плохо. Я думаю, что я видел в эти лекции слайды вы начали видеть всю эту схему памяти где здесь у вас есть память адрес 0 и здесь у вас есть адрес памяти, 4 гигабайтами или от 2 до 32. Таким образом, то у вас есть некоторые вещи и некоторые вещи, а затем у вас есть свой стек и у вас есть ваша куча, которую вы только начали изучение, растет. [Студент] не является кучей над стеком? Да. Куча находится на вершине, не так ли? >> [Студент] Ну, он поставил 0 на вершине. [Студент] О, он поставил 0 на вершине. >> [Студент] О, все в порядке. Отказ от ответственности: Anywhere с CS50 вы увидите его таким образом. >> [Студент] Хорошо. Это только, что, когда вы впервые увидев стеки, нравится, когда вы думаете о стеке вы думаете укладки вещей друг на друга. Таким образом, мы, как правило, чтобы перевернуть эту вокруг так стек растет вверх, как это обычно стек вместо того, чтобы стек висит вниз. >> [Студент] Не кучи технически расти слишком, правда? Это зависит от того, что вы подразумеваете под расти. Стека и кучи всегда растут в противоположном направлении. Стек всегда растут в том смысле, что оно растет к более высоким адресам памяти, и куча растет вниз в том, что он растет в сторону меньших адресов памяти. Таким образом, верхний равен 0, а нижний является высокая адресов памяти. Они оба растет, только в противоположных направлениях. [Студент] Я просто имел в виду, что, поскольку вы сказали, положил стек на дно потому что кажется более интуитивным, поскольку для стека для запуска в верхней части кучи, куча находится на вершине самого тоже, так что that's - >> Да. Вы также думать о куче, как растут и больше, но в стеке больше. Таким образом, стек является тот, который мы как бы хотят показать растут. Но куда ни глянь в противном случае покажет адрес 0 в верхнем и самый высокий адрес памяти в нижней, так что это обычный вид памяти. У вас есть вопрос? [Студент] Можете ли вы рассказать нам больше о куче? Да. Я вернусь к этому в секунду. Во-первых, возвращаясь к возвращению и почему у плохая вещь, в стеке у вас есть куча кадров стека, которые представляют все функции которые были названы. Таким образом, игнорируя предыдущие вещи, в верхней части стека всегда будет главной функцией так как это первая функция, которая вызывается. А потом, когда вы звоните другую функцию, стек будет расти вниз. Так что, если я называю некоторые функции, Foo, и он получает собственный фрейм стека, он может вызвать некоторые функции, бар, он получает собственный фрейм стека. И бар может быть рекурсивной, и это может вызывать саму себя, и так, что второй вызов баре собирается получить свой фрейм стека. И поэтому то, что происходит в этих кадров стека являются все локальные переменные и все аргументы функции, что - Любые вещи, которые имеют локальную область действия этой функции перейдите в этих кадров стека. Таким образом, это означает, что, когда я сказал что-то вроде бара является функцией, Я просто хочу, чтобы объявить целое, а затем возвращает указатель на это число. Так где же у живете? [Студент] у живет в баре. >> [Боуден] Да. Где-то в этом маленьком квадрате памяти квадратных Литтлер, который имеет у в нем. Когда я вернусь, и у, я возвращаю указатель на этот небольшой блок памяти. Но потом, когда функция возвращается, его стек получает стека. И именно поэтому она называется стеком. Это как структуры данных стека, если вы знаете, что это такое. Или даже как стек лотков всегда, например, Основными собирается пойти на дно, то первая функция вы звоните собирается пойти на вершине, что, и вы не можете вернуться на главную, пока не вернетесь из всех функций, которые были призваны , которые были размещены на нем. [Студент] Так что если вы делали вернуться и у, что стоимость может быть изменена без предварительного уведомления. Да, it's - >> [студент] Это может быть перезаписана. >> Да. Это полностью - Если вы попробуете - Это также было бы Int бар *, потому что это возвращает указатель, так что его возвращение типа Int *. Если вы попытаетесь использовать возвращаемое значение этой функции, это неопределенное поведение потому что указатель указывает на плохую память. >> [Студент] Хорошо. Так что, если, например, вы заявили Int * у = таНос (SizeOf (INT))? Так-то лучше. Да. [Студент] Мы говорили о том, когда мы перетащить вещи в наши корзины они на самом деле не стираются, мы просто теряют свои указатели. Поэтому в данном случае мы на самом деле удалить значение или это еще там, в памяти? По большей части, это будет еще будет там. Но, допустим, мы, случается, называют некоторые другие функции, Баз. База собирается получить свой фрейм стека здесь. Это будет перезаписывать все эти вещи, , а затем, если вы позже попытаться использовать указатель, который вы получили раньше, это не будет то же значение. Это будет изменились только потому, что вы вызвали функцию Баз. [Студент] Но если бы мы не, мы бы до сих пор получить 3? [Боуден] По всей вероятности, вы бы. Но вы не можете полагаться на это. C просто говорит неопределенное поведение. [Студент] О, это так. Хорошо. Итак, когда вы хотите вернуть указатель, это где таНос приходит в использовании. Я пишу на самом деле просто вернуть таНос (3 * SizeOf (INT)). Мы пройдемся по таНос еще в секунду, но идея таНос это все локальные переменные всегда идут в стек. Ничего, что malloced идет по куче, и он будет вечно и всегда быть в куче пока вы явно освободить его. Таким образом, это означает, что когда вы таНос что-то, она собирается выжить после возврата из функции. [Студент] Будет ли она выжить после того, как программа останавливается? >> Нет. Ладно, так что это будет там, пока программа полностью не сделал работу. >> Да. Мы можем пойти на детали того, что происходит, когда программа останавливается. Вам может понадобиться, чтобы напомнить мне, но это отдельная вещь целиком. [Студент] Так таНос создает указатель? >> Да. Malloc - >> [студент] Я думаю, что таНос обозначает блок памяти, который можно использовать в качестве указателя. [Боуден] Я хочу, чтобы схема снова. >> [Студент] Таким образом, эта функция работает, правда? [Студент] Да, таНос обозначает блок памяти, который можно использовать, а затем возвращает адрес первого блока этой памяти. [Боуден] Да. Итак, когда вы таНос, вы захват некоторых блок памяти что в настоящее время в куче. Если куча слишком мало, то куча всего будет расти, и оно растет в этом направлении. Так скажем, куча слишком мала. Тогда речь идет о расти немного, и возвращает указатель на этот блок только росла. Когда Вы бесплатно вещи, вы делаете больше места в куче, так, то позже позвонить в таНос может использовать эту память, что ранее вы уже освобождены. Главное о таНос и бесплатно, что она дает вам полный контроль в течение срока службы этих блоков памяти. Глобальные переменные всегда жива. Локальные переменные живы в пределах своей компетенции. Как только вы идете мимо фигурной скобкой, локальные переменные мертвы. Malloced память жива, когда вы хотите, чтобы он жив , а затем высвобождается, когда вы сказать, что это должен быть освобожден. Те, на самом деле являются только 3 типов памяти, на самом деле. Там в автоматическое управление памятью, которая является стек. Все происходит автоматически. Когда вы говорите Int х, памяти выделяется для внутр х. При х выходит из области видимости, память будет утилизирован для х. Тогда есть динамическое управление памятью, что и таНос есть, который является, когда у вас есть контроль. Вы динамически решить, когда память должна и не должна быть выделена. А тут еще статические, который просто означает, что он живет вечно, что и глобальные переменные. Они просто всегда в памяти. Вопросы? [Студент] Можете ли вы определить блок только с помощью фигурных скобок но не того, чтобы иметь, если заявление или заявление во время или что-то в этом роде? Вы можете определить блок, как в функции, но это не имеет фигурные скобки тоже. [Студент] Таким образом, вы не можете просто как случайные пара фигурных скобок в коде , которые имеют локальные переменные? >> Да, можно. Внутри Int баре мы могли бы иметь {INT у = 3;}. Это должно быть здесь. Но это полностью определяет сферу Int у. После того, что второй фигурной скобкой, у не может быть использована больше. Вы почти никогда не делают этого, хотя. Возвращаясь к тому, что происходит, когда программа заканчивается, там вроде заблуждение / половина ложь, что мы даем для того, чтобы просто сделать вещи проще. Мы говорим вам, что, когда вы выделить память Вы выделении некоторых кусок оперативной памяти для этой переменной. Но вы действительно не касаясь непосредственно RAM все в ваших программах. Если вы думаете об этом, как я нарисовал - А на самом деле, если вы проходите в GDB вы увидите то же самое. Независимо от того, сколько раз вы запустите программу или какой программой вы работаете, Стек всегда собирается начать - Вы всегда увидите переменные вокруг адрес что-то oxbffff. Это, как правило, где-то в этом регионе. Но как 2 программы возможно иметь указатели на ту же память? [Студент] Там некоторые произвольные обозначения, где oxbfff должна быть на RAM которые действительно могут находиться в разных местах, в зависимости от того, когда функция была вызвана. Да. Этот термин является виртуальной памяти. Идея состоит в том, что каждый процесс, каждая программа, которая работает на вашем компьютере имеет свою собственную - предположим, 32 бит - полностью независимая адресного пространства. Это адресное пространство. Он имеет свой собственный полностью независимыми 4 гигабайта в использовании. Так что если вы запустите 2 программы одновременно, эта программа видит 4 гигабайта к себе, эта программа видит 4 гигабайта к себе, и невозможно для этой программы разыменовать указатель и в итоге памяти из этой программы. И то, что виртуальная память является отображением из адресного пространства процесса фактических вещей на память. Так что до вашей операционной системе знать, что, эй, когда этот указатель парень разыменовывает oxbfff, что на самом деле означает что он хочет байт RAM 1000, а если это oxbfff программы разыменовывает, что он действительно хочет байт RAM 10000. Они могут быть сколь угодно далеко друг от друга. Это верно даже вещи в одном адресном пространстве процесса. Так как он видит все 4 гигабайта к себе, но, скажем - [Студент] ли каждый процесс - Скажем, у вас есть компьютер с 4 гигабайтами оперативной памяти. Имеет ли каждый процесс увидеть целых 4 гигабайта? >> Да. Но 4 гигабайта он видит это ложь. Это просто он думает, что все это имеет памяти, потому что он не знает, и любой другой процесс существует. Он будет использовать только столько памяти, сколько на самом деле нужно. Операционная система не даст RAM в этот процесс если он не использует память во всей этой области. Это не собираюсь дать ему память для этого региона. Но идея в том, что - я пытаюсь думать - я не могу думать о аналогия. Аналогии трудно. Один из вопросов, виртуальной памяти, или одна из вещей, это решение является то, что процессы должны быть в полном неведении друг от друга. И таким образом, вы можете написать любую программу, которая просто разыменовывает любой указатель, хотел просто написать программу, которая говорит * (ox1234), и это разыменование адрес памяти 1234. Но это до операционной системы, чтобы затем перевести то, что 1234 средства. Так, если 1234 окажется действительный адрес памяти для этого процесса, как он в стек или что-то, то это будет возвращать значение данного адреса памяти Что касается процесса знает. Но если 1234 не является действительным адресом, как это происходит на землю В некоторых маленький кусочек памяти здесь, что выходит за пределы стека и кучи и вы действительно не использовали это, то что, когда вы получаете что-то вроде сегментации потому что ты прикасаешься памяти, которые вы не должны касаться. Это также верно - 32-битная система, 32 бит означает, что у вас есть 32 бита для определения адреса памяти. Вот почему указателей 8 байт, поскольку 32 бит 8 байт - или 4 байт. Указатели 4 байт. Поэтому, когда вы видите указатель, как oxbfffff, то есть - В любой данной программы вы можете просто построить любой произвольный указатель, в любом месте от Ох0 ОХ 8 f's - FFFFFFFF. [Студент] Разве вы не говорите, что они 4 байта? >> Да. [Студент] Тогда каждый байт будет - >> [Боуден] Шестнадцатеричные. Шестнадцатеричные - 5, 6, 7, 8. Так указателей вы будете всегда видеть в шестнадцатеричном виде. Это просто, как мы классифицируем указателей. Каждые 2 цифры шестнадцатеричной 1 байт. Так что это будет 8 шестнадцатеричных цифр на 4 байта. Таким образом, каждый указатель на 32-битной системе будет 4 байта, Это означает, что в вашем процессе можно построить любой произвольный 4 байта и сделать указатель из него, Это означает, что, насколько он знает, он может обратиться целая 2 до 32 байт памяти. Даже если это на самом деле не имеют доступа к этой, даже если ваш компьютер имеет только 512 мегабайт, он думает, что он имеет много памяти. И операционная система достаточно умна, что она будет только выделить то, что вам действительно нужно. Это не просто идти, ой, новый процесс: 4 концертов. Да. >> [Студент] Что бык значит? Почему вы пишете? Это просто символ шестнадцатеричной. Когда вы видите номер начинается с быка, последовательные вещи шестнадцатеричное. [Студент] Вы были объяснить, что происходит, когда программа заканчивается. >> Да. Что происходит, когда программа заканчивается представляет собой операционную систему просто стирает отображений, что она имеет для этих адресов, вот и все. В качестве операционной системы теперь можно просто дать, что память в другой программе использовать. [Студент] Хорошо. Итак, когда вы выделить что-то в куче или в стеке или глобальные переменные или что-нибудь, все они просто исчезают, как только программа заканчивается , поскольку операционная система теперь может дать, что память для любого другого процесса. [Студент] Даже если Есть, вероятно, еще значения написаны на? >> Да. Значения, вероятно, все еще там. Это просто, что это будет трудно получить на них. Это гораздо труднее получить на них, чем это, чтобы добраться до удаленных файлов потому что удаленный файл вида сидит там в течение долгого времени и жесткого диска намного больше. Таким образом, он собирается переписать разных частях памяти прежде чем это произойдет, чтобы заменить кусок памяти, что файл, используемый чтобы быть в. Но основной памяти, RAM, вы цикла через много быстрее, так что это будет очень быстро будут перезаписаны. Вопросы на эту или что-то еще? [Студент] У меня есть вопросы о другой теме. >> Хорошо. Кто-нибудь есть вопросы по этому поводу? Хорошо. Разные темы. >> [Студент] Хорошо. Я шел через некоторые практические тесты, и в одной из них он говорил о SizeOf и значение, которое она возвращает или различных типов переменных. >> Да. И он сказал, что оба Int и долго, как возвращение 4, так что они оба 4 байта. Есть ли разница между Int и долго, или это одно и то же? Да, есть разница. C стандарт - Я, вероятно, будет беспорядок. C стандарт просто нравится то, что C есть официальная документация C. Это то, что он говорит. Таким образом, C стандартная просто говорит, что символ будет вечно и всегда будет 1 байт. Все, после этого - короткий всегда просто определить как больше или равна символ. Это может быть строго больше, но не положительно. Int просто определяется как больше или равно короткий. И долго просто определяется как большее или равное Int. И долго долго, больше или равно долго. Так что единственное, C стандарт определяет относительный порядок во всем. Фактический объем памяти, что вещи занимают, как правило, до реализации, но он очень хорошо определена в этой точке. >> [Студент] Хорошо. Таким образом, шорты почти всегда будет 2 байта. Ints почти всегда будет 4 байт. Длинные длинные, почти всегда будет 8 байт. И мечтает, это зависит от того, используется ли 32-битные или 64-битные системы. Так долго будет соответствовать типу системы. Если вы используете 32-разрядную систему, как Appliance, это будет 4 байт. Если вы используете 64-разрядную, как много последних компьютерах, это будет 8 байт. Ints почти всегда 4 байта в этой точке. Длинные длинные, почти всегда 8 байт. В прошлом целые использованы только быть 2 байта. Но обратите внимание, что это полностью удовлетворяет все эти отношения больше и равна. До тех пор, прекрасно позволено быть такого же размера, как целое, и это также разрешено иметь тот же размер, как долго долго. И так уж случается, что в 99,999% систем, будет равна либо Int или длинный долго. Это зависит только от 32-битной или 64-битной. >> [Студент] Хорошо. В поплавки, каким десятичной точки, обозначенной в плане бит? Вроде как бинарный? >> Да. Вам не нужно знать, что для CS50. Вы даже не узнаете, что в 61. Вы не узнаете, что действительно в любой курс. Это просто представление. Я забыл точное наделы немного. Идея с плавающей точкой является то, что вы выделить определенное количество бит для представления - В принципе, все в научной нотации. Таким образом, вы выделить определенное количество бит для представления самого числа, как и 1.2345. Я никогда не могут представлять числа с более чем 5 цифр. После этого вы также выделить определенное количество битов, так что он стремится быть похожим на Вы можете идти только до определенного числа, как и самый большой показателя вы можете иметь, и вы можете идти только до определенного показателя, как это наименьший показатель вы можете иметь. Я не помню точно биты пути назначаются на все эти ценности, но определенное количество битов посвященный 1.2345, другой определенное количество битов предназначены для экспоненты, и это только можно представить показателем определенного размера. [Студент] и двойной? Разве что, как и удлиненные поплавок? >> Да. Это то же самое, как поплавок только теперь вы используете 8 байт вместо 4 байт. Теперь вы сможете использовать 9 цифр или 10 цифр, и это будет в состоянии пойти до 300 вместо 100. >> [Студент] Хорошо. И поплавки также 4 байта. >> Да. Ну, опять же, это, вероятно, зависит в целом на общую реализацию, но поплавки 4 байта, двухместные являются 8. Парный называются двойными, потому что они в два раза поплавков. [Студент] Хорошо. И есть двойное удваивает? >> Есть не так. Я думаю - >> [студент] Как долго тоскует? >> Да. Не думаю. Да. [Студент] На тесте в прошлом году там был вопрос об основной функции того, чтобы быть частью вашей программы. Ответ был, что она не должна быть частью вашей программы. В какой ситуации? Это то, что я видел. [Боуден] Кажется - >> [студент] Какая ситуация? Есть ли у вас проблемы? >> [Студент] Да, я могу определенно потяните его вверх. Это не должны быть технически, но в основном это будет. [Студент] Я видел одного на другой год. Это было похоже Верно или нет: действительно - >> О, с файлом.? . [Студент] Любое С файл должен иметь - [как говорит сразу - неразборчиво] Хорошо. Так вот отдельно. . C файл, просто должен содержать функций. Вы можете скомпилировать файл в машинный код, двоичный, что угодно, без его исполняемым еще нет. Действительный исполняемый файл должен иметь основную функцию. Вы можете написать 100 функций в 1 файл, но не основная , а затем скомпилировать, что вплоть до двоичный, Затем вы пишете другой файл, который имеет только главной, но она вызывает кучу этих функций В этот двоичный файл здесь. И поэтому, когда вы делаете исполняемый файл, вот что делает компоновщик оно сочетает в себе эти 2 двоичных файлов в исполняемый файл. Так. В файле не должно быть основной функцией на всех. И на больших базах кода вы увидите тысячи. Файлы с и 1 главный файл. Еще вопросы? [Студент] Существовал еще один вопрос. Он сказал, сделать это компилятор. Правда или Ложь? И ответ был ложным, и я понял, почему это не так, как Clang. Но то, что мы называем сделать, если это не так? Сделать это в основном просто - я вижу именно то, что он это называет. Но это только выполняет команды. Сделать. Я могу потянуть это. Да. О, да. Убедитесь также, что делает. Это говорит о цели марку утилита для автоматического определения какие части большой программы должны быть перекомпилированы и выдает команды для их перекомпиляции. Вы можете сделать файлы, которые являются абсолютно огромно. Сделать смотрит на штампы времени файлов и, как мы уже говорили, Вы можете собрать отдельные файлы вниз, и это не пока не дойдете до компоновщик что они собрали в исполняемый файл. Так что если у вас есть 10 различных файлов, и вы внести изменения в 1 из них, то, что делает собирается сделать, это просто перекомпиляция, что 1 файл , а затем повторно связать все вместе. Но гораздо тупее, чем это. Это до вас, чтобы полностью определить, что это то, что он должен делать. Это по умолчанию имеет способность распознавать этот материал штамп времени, но вы можете написать сделать файл ничего делать. Вы можете написать сделать файл, так что, когда вы вводите сделать это только компакт-диски в другой каталог. Я разочарованы, потому что я трека внутри все мои Appliance а потом просмотреть PDF с Mac. Так что я иду в Finder, и я могу действительно идете, подключиться к серверу, и сервер подключиться к мое Appliance, а затем я открываю PDF , который получает составленный LaTeX. Но меня постигло разочарование, потому что каждый раз, когда мне нужно, чтобы обновить PDF, Мне пришлось скопировать его в определенный каталог, что он может получить доступ к и это становилось раздражает. Так что вместо этого я написал сделать файл, который вы должны определить, как он делает вещи. Как вы делаете в это PDF LaTeX. Так же, как и любой другой файл марки - или я думаю, вы еще не видели марку файлов, но у нас есть в прибор файл глобальных марки, которые просто говорит: если вы компилируете файл C, используйте Clang. И вот здесь, в моей сделать файл, что я делаю я говорю, Этот файл вы собираетесь хотите собрать с PDF LaTeX. И таким образом, это PDF LaTeX, что делает компиляцию. Сделать это не компиляция. Это просто выполнения следующих команд в последовательности я указал. Таким образом, она работает PDF LaTeX, он копирует его в каталог, я хочу, чтобы быть скопирована, это компакт-дисков в каталоге и делает другие вещи, но все она делает, это признают при изменении файла, и если он меняется, то она будет работать командами, которые он должен выполнить При изменении файла. >> [Студент] Хорошо. Я не знаю, где глобальные файлы сделать для меня, чтобы проверить его. Другие вопросы? Все, начиная от прошлых тестов? Любой указатель вещи? Есть тонкие вещи с указателями, как - Я не собираюсь быть в состоянии найти вопрос викторины на нем - но, как и такого рода вещи. Убедитесь, что вы понимаете, что, когда я говорю Int * х * у - Это не совсем здесь ничего, я думаю. Но, как и * х * у, те 2 переменные, которые находятся на стеке. Когда я говорю, х = таНос (SizeOf (INT)), х-прежнему переменной в стек, таНос некоторый блок более в кучу, и мы имеющей точки х до кучи. Так что-то в стек указывает на кучу. Всякий раз, когда вы таНос что-нибудь, вы неизбежно хранить его внутри мыши. Так что указатель на стек, malloced блока в куче. Многие люди путают и говорят Int * х = таНос; х в кучу. Кол-х Что указывает на это в кучу. х сама находится в стеке, если по каким-либо причинам вы х глобальной переменной, В этом случае он оказывается в другой области памяти. Таким образом отслеживать эти коробки и стрелочные диаграммы являются довольно общими для викторины. Или, если это не тест на 0, это будет на тест 1. Вы должны знать все это, шаги в составлении так как вы должны были ответить на вопросы на них. Да. [Студент] Можем ли мы пойти на эти шаги - >> Конечно. Перед шагов и составление нас есть предварительная обработка, компиляции, сборки и компоновки. Предварительная обработка. Что же это сделать? Это самый простой шаг в - хорошо, не нравится - это не значит, должно быть очевидным, но это самый простой шаг. Вы, ребята могли реализовать себя. Да. [Студент] Возьмите то, что у вас есть в вашей включает в себя, как это и копирует, а затем и определяет. Он ищет вещи, как # # включают в себя и определить, и он просто копирует и вставляет то, что те на самом деле означает. Поэтому, когда вы говорите # включить cs50.h, препроцессор копирования и вставки cs50.h в этой линии. Когда вы говорите: # определить х равным 4, препроцессор проходит через всю программу и заменяет все экземпляры х с 4. Таким образом, препроцессор принимает правильный файл C и выдает правильный файл C , где вещи были скопированы. Так что теперь компиляции. Что же это сделать? [Студент] Это идет от C в двоичный формат. [Боуден] Это не пройти весь путь в двоичный формат. [Студент] в машинный код то? >> Это не машинный код. [Студент] Ассамблеи? >> Ассамблеи. Это идет в Ассамблее прежде чем он идет всю дорогу в код C, и большинство языков сделать что-то вроде этого. Выберите любой язык высокого уровня, и если вы собираетесь компилировать его, это, вероятно, собрать в шагах. Сначала он собирается составить Python в C, то это будет для компиляции C Ассамблеи, , а затем Ассамблея собирается получить перевод в двоичную. Таким образом, составление собирается вывести его из C Ассамблеи. Слово компиляции обычно означает приведение его от более высокого уровня в нижней язык программирования высокого уровня. Так что это только шаг в компиляции, где вы начинаете с языка высокого уровня и в конечном итоге в язык низкого уровня, и поэтому шаг называется компиляцией. [Студент] Во время компиляции, давайте скажем, что вы сделали # включить cs50.h. Будет ли перекомпилировать компилятор cs50.h, как и функции, которые там, , и перевести это в ассемблерный код, а также, или это скопировать и вставить то, что было предварительно собрание? cs50.h будет почти никогда не оказываются в Ассамблее. Вещи, как прототипы функций и вещей для вас быть осторожными. Это гарантирует, что компилятор может проверить такие вещи, как вы вызываете функции с правом типы возвращения и правильные аргументы и прочее. Так cs50.h будет предварительную обработку в файл, а затем, когда это компиляция это в основном выбрасываются после того, как убеждается, что все, что называют правильно. Но функции, определенные в CS50 библиотеки, которые являются отдельными от cs50.h, тех, кто не будет составлена ​​отдельно. Что будет на самом деле спуститься в стадии компоновки, поэтому мы вернемся к этому в секунду. Но, во-первых, то, что сборка? [Студент] ассамблеи в двоичную? >> Да. Сборка. Мы не называем его составления, поскольку Ассамблея является в значительной степени чистая перевода двоичного файла. Существует очень мало логики в переходе от Ассамблеи в двоичный формат. Это все равно, глядя в таблицу, ой, у нас есть эта инструкция; , что соответствует двоичным 01110. И поэтому файлы, которые сборки в целом выходы. О файлах. А. Вывода файлов, что мы говорили раньше, как файл не нужно иметь основную функцию. Любой файл может быть составлен до. Файл вывода тех пор, пока это правильный файл C. Он может быть составлен до. °. Теперь, связывая это то, что на самом деле приносит кучу. О файлах и приводит их к исполняемому файлу. И то, что компоновка делает, вы можете думать о CS50 библиотеку. Файл вывода. Это уже скомпилированных двоичных файлов. И так при компиляции файла, ваш hello.c, которая призывает GetString, hello.c компилируется до hello.o, hello.o в настоящее время в двоичном виде. Он использует GetString, поэтому она должна перейти к cs50.o, и компоновщик smooshes их вместе и копирует GetString в этот файл и выходит с исполняемого файла, который имеет все функции которых она нуждается. Так cs50.o на самом деле не о файле, но это достаточно близко, что нет никакой принципиальной разницы. Таким образом, связь только приносит кучу файлов вместе что отдельно содержат все функции мне нужно использовать и создает исполняемый файл, который будет реально работать. И таким образом, это также то, что мы говорили до где вы можете иметь 1000. с файлами, вы собрать их все. о файлах, который, вероятно, займет некоторое время, то вы измените 1. с файлом. Вам только нужно перекомпилировать, что 1. С файла, а затем перелинковки все остальное, связать все вместе. [Студент] Когда мы пишем связи lcs50? Да, так lcs50. Этот флаг сигналы в компоновщик, что вы должны связей в этой библиотеке. Вопросы? Разве мы перешли двоичной другие, чем 5 секунд в первой лекции? Не думаю. Вы должны знать все большую Os, что мы перешли, и вы должны быть в состоянии, если бы мы дали вам функции, Вы должны быть в состоянии сказать, что это большая O, грубо. Или же, Big O является приблизительным. Так что если вы видите, вложенные циклы циклы по сравнению с аналогичным количеством вещей, Int, как я, я <п; Int J, J <п - >> [студент] п квадрат. >> Он имеет тенденцию быть указан в квадрате. Если вы тройной вложенный, он, как правило, п кубе. Так что такого рода вещи вы должны быть в состоянии указать сразу. Вы должны знать, рода вставки и пузырьковой сортировки и сортировки слиянием, и все из них. Это легче понять, почему они являются п квадратов и п § п и все, что потому что я думаю, что была на тест один год, где мы в основном дал вам осуществление пузырьковой сортировки и сказал: "Что такое время работы этой функции?" Так что если вы признаете это, как пузырьковой сортировки, то вы можете сразу сказать, п ​​квадрат. Но если вы просто посмотрите на нее, вам даже не нужно осознать, что это пузырьковой сортировки; Вы можете просто сказать, что это делать это и это. Это п квадрат. [Студент] Существуют ли какие-либо жесткие примеры, которые вы можете придумать, как аналогичная идея выяснить? Я не думаю, что мы хотели бы дать Вам любые жесткие примеры. Дело в пузырьковой сортировки примерно так же жестко, как мы ходили, и то, как долго, как вы понимаете, что вы итерации по массиву Для каждого элемента массива, который будет что-то, что п в квадрате. Есть общие вопросы, например, прямо здесь, у нас - Oh. Буквально на днях, Дуг заявил: "Я изобрел алгоритм, который может сортировать массив "П чисел в O (журнал N) раз!" Итак, как мы знаем, что это невозможно? [Неразборчиво ответ студента] >> Да. По крайней мере, вы должны коснуться каждого элемента в массиве, так что это невозможно отсортировать массив - Если все в порядке несортированные, то вы будете касаться все, что в массиве, так что это невозможно сделать это менее чем за O н. [Студент] Вы показали нам, что пример в состоянии сделать это в O п если вы используете много памяти. >> Да. И that's - Я забыл, что that's - Разве подсчета рода? Хм. Это целое алгоритм сортировки. Я искал специальное название для этого, что я не мог вспомнить на прошлой неделе. Да. Эти типы видов, которые могут выполнить вещи в большом O н. Но есть ограничения, как вы можете использовать только целые числа до определенного числа. Плюс, если вы пытаетесь разобраться что-то that's - Если ваш массив 012, -12, 151, 4 млн. то, что один элемент будет полностью разрушит весь сортировки. Вопросы? [Студент] Если у вас есть рекурсивная функция, и он просто делает рекурсивные вызовы в возвращении заявления, что это хвост рекурсивной, и так бы это не использовать больше памяти во время выполнения или, по крайней мере, использовать сопоставимые памяти, как итерационные решения? [Боуден] Да. Это, вероятно, будет несколько медленнее, но не совсем. Хвост рекурсивных довольно хорошо. Глядя снова на кадры стека, скажем, у нас есть основной и у нас есть Int бар (INT х) или что-то еще. Это не идеальный рекурсивной функции, но возвращение бар (х - 1). Таким образом, очевидно, что это ошибочно. Вы должны базе случаи и прочее. Но идея здесь в том, что это хвост рекурсивной, что означает, когда главный бар звонки он собирается получить свой стек. В этом кадре стека там будет небольшой блок памяти , что соответствует ее аргумента х. И так скажем, основной, случается, называют Бар (100); Таким х собирается начать, как 100. Если компилятор признает, что это хвост рекурсивной функции, Затем, когда бара делает его рекурсивный вызов бар, вместо того, чтобы новый кадр стека, который является, где стек начинает расти в основном, в конечном итоге он будет работать в кучу и тогда вы получите ошибку сегментации потому что память начинает столкновения. Таким образом, вместо того, чтобы его собственный кадр стека, он может реализовать, Эй, я никогда не нужно возвращаться к этому кадру стека, так вместо этого я просто заменить этот аргумент с 99, а затем начать баре на всем протяжении. И тогда она будет делать это снова и она достигнет возвращения бар (х - 1), и вместо того, чтобы новый кадр стека, это будет просто заменить свой текущий аргумент с 98 , а затем перейти к самому началу бар. Эти операции, заменив, что 1 значение в стеке и прыгает обратно к началу, довольно эффективным. Так что не только эта же использование памяти как отдельная функция, которая итерационного потому что вы используете только 1 кадр стека, но вы не страдаете минусы того, чтобы вызывать функции. Вызов функции может быть несколько дороже, потому что он должен делать все это установка и демонтажа и все эти вещи. Так что этот хвостовой рекурсии хорошо. [Студент] Почему не создать новые шаги? Потому что он понимает, что это не нужно. Вызов бар только что вернулся рекурсивный вызов. Так что не нужно ничего делать с возвращаемым значением. Это просто будет немедленно вернуть его. Так что это просто собирается заменить свои аргументы и начать все сначала. А также, если вы не имеете хвост рекурсивной версии, , то вы получите все эти бары, где, когда этот бар возвращается он должен вернуть его значение в этом, то, что бар сразу же возвращается и возвращает его значение в этом, то он просто будет немедленно вернуться и вернуть его значение на этом. Таким образом, вы экономите этого появляются все эти вещи из стека С возвращаемого значения только собирается быть передан весь путь обратно в любом случае. Так почему бы не заменить наш спор с обновленным аргумент и начать все сначала? Если функция не является хвостовой рекурсией, если вы делаете что-то вроде - [Студент], если бар (х + 1). >> Да. Так что, если вы поместите его в состояние, то вы делаете что-то с возвращаемым значением. Или даже если вы просто возвращение 2 * бар (х - 1). Так что теперь бар (х - 1) необходимо вернуть для того, чтобы вычислить, что в 2 раза значения, так что теперь он действительно нуждается в своем собственном отдельном кадре стека, и теперь, как ни старайся, вы собираетесь нужно - Это не хвост рекурсивной. [Студент] Буду ли я пытаться довести рекурсии стремиться к хвостовой рекурсии - [Боуден] В идеальном мире, но в CS50 вам не придется. Для того чтобы получить хвостовой рекурсии, в общем, вы создали дополнительный аргумент где бар состоится Int х в у и у соответствует конечная вещь, которую вы хотите вернуть. Так вот это вы будете возвращаться бар (х - 1), 2 * у. Так что это только на высоком уровне, как вы преобразования вещей, чтобы быть хвостом рекурсивные. Но дополнительный аргумент - А потом, в конце концов, когда вы достигнете своей базы случае, вы просто вернуть у потому что у вас накапливается все время возвращается значение, что вы хотите. Вы вроде делали это многократно, но с использованием рекурсивных вызовов. Вопросы? [Студент] Может быть, о арифметику указателей, например, при использовании строк. >> Конечно. Указатель арифметика. При использовании строк, что это легко, потому что строки символов звезды, символы вечны и всегда один байт, и так арифметики указателей эквивалентно регулярные арифметических когда вы имеете дело со строками. Давайте просто скажем, символ * S = "привет". Итак, мы имеем блок в памяти. Она нуждается в 6 байт, потому что вы всегда должны нулем. И символ * S будет указывать на начало этого массива. Таким образом, с точек. Теперь, это в основном, как любой массив работает, независимо от того, было ли это возвращение таНос или это в стеке. Любой массив в основном указатель на начало массива, и тогда любой массив операции, любые индексации, только собирается в этот массив определенного смещения. Поэтому, когда я говорю что-то вроде с [3], это будет ей и подсчет 3 символа дюйма Таким образом, с [3], мы имеем 0, 1, 2, 3, таким образом, с [3] будет ссылаться на эту л. [Студент] И мы могли бы достичь такого же значения, делая с + 3, а затем скобки звезды? Да. Это эквивалентно * (S + 3); и это навсегда и всегда эквивалентны независимо от того, что вы делаете. Вы никогда не должны использовать кронштейн синтаксиса. Вы всегда можете использовать * (S + 3) синтаксис. Люди, как правило, нравятся кронштейн синтаксиса, однако. [Студент] Таким образом, все массивы в действительности являются просто указателями. Существует небольшое различие, когда я говорю Int х [4] >> [студент] Значит ли это, создайте памяти? [Боуден], что собирается создать 4 целых чисел в стеке, поэтому 16 байт в целом. Он собирается создать 16 байт в стеке. х нигде не сохраняется. Это просто символ со ссылкой на старте вещь. Потому что вы объявили массив внутри этой функции, что компилятор будет сделать, это просто заменить все вхождения переменной х с, где это произошло выбрать, чтобы положить эти 16 байт. Он не может сделать это с помощью символов * потому, что ей это фактически указатель. Это бесплатно, чтобы потом указать на другие вещи. х является постоянным. Вы не можете иметь его точки к другой массив. >> [Студент] Хорошо. Но эта идея, эта индексация, такое же, независимо от того, является ли это традиционным массивом или, если это указатель на что-то или, если это указатель на malloced массива. И в самом деле, это так эквивалентной, что это также одно и то же. Это на самом деле просто означает, что внутри скобок и то, что осталось за скобки, складывает их, и разыменовывает. Так что это только же силу, как * (S + 3) или с [3]. [Студент] Может у вас есть указатели, указывающие на 2-мерных массивов? Это труднее. Традиционно, нет. 2-мерный массив находится всего в 1-мерный массив с некоторым удобный синтаксис потому что, когда я говорю Int х [3] [3], это действительно только 1 массив с 9 значений. И поэтому, когда я индексом, компилятор знает, что я имею в виду. Если я скажу, х [1] [2], он знает, я хочу пойти на второй строке, так что он собирается пропустить первые 3, , а затем она хочет Второе в том, что так оно собирается получить это. Но это еще только одномерный массив. И поэтому, если я хотел присвоить указатель на этот массив, Я бы сказал Int * р = х; Тип х просто - Это грубо говоря типа х, так как это всего лишь символ, и это не фактической переменной, Но это всего лишь Int *. х это просто указатель на начало этого. >> [Студент] Хорошо. И поэтому я не буду иметь возможность доступа [1] [2]. Я думаю, что есть специальный синтаксис для объявления указателя, что-то смешное, как Int (* р [-. что-то абсолютно смешно, я даже не знаю. Но есть синтаксис для объявления указателей, как со скобками и вещи. Он не может даже позволить вам сделать это. Я могу оглянуться на то, что бы сказать мне правду. Я буду искать его позже, если есть синтаксис точки. Но вы никогда не увидите. И даже синтаксис очень архаичная, что если вы используете его, люди будут сбиты с толку. Многомерные массивы являются довольно редкими, как это. Вы в значительной степени - Ну, а если вы делаете матрицу вещей он не собирается быть редкими, но в C вы редко будете использовать многомерные массивы. Да. >> [Студент] Скажем, у вас есть очень длинный массив. Таким образом, в виртуальной памяти, она, казалось бы, все подряд, как элементы рядом друг с другом, но и в физической памяти, это было бы возможно, что быть разделены? >> Да. Как виртуальная память работает это только отделяет - Блок распределения представляет собой страницу, которая имеет тенденцию быть 4 килобайта, и поэтому, когда процесс говорит, эй, я хочу использовать эту память, Операционная система собирается выделить ее 4 килобайта, что мало блок памяти. Даже если вы используете только один маленький байт в целый блок памяти, Операционная система собираюсь дать ему полный 4 килобайта. Так что это означает, я мог бы - скажем, это мой стек. Этот стек могут быть разделены. Мой стек может быть мегабайты и мегабайты. Мой стек может быть огромным. Но сам стек должен быть разбит на отдельные страницы, , который, если мы посмотрим на здесь скажем, это наша память, если у меня есть 2 гигабайта оперативной памяти, это действительно адресу 0 как нулевой байт моей памяти, и это составляет 2 гигабайта на всем пути сюда. Так этой странице может соответствовать этому блоку здесь. Эта страница может соответствовать этому блоку здесь. Это одна может соответствовать этим сюда. Таким образом, операционная система свободна назначить физической памяти в отдельных страниц произвольно. А это значит, что если это произойдет, граница оседлать массива, Массив случается, оставил это и право этот порядок страниц, Затем этот массив будет разделен в физической памяти. А потом, когда вы выходите из программы, когда процесс закончится, эти отображения получить стерты, а затем она свободно использовать эти маленькие блоки для других вещей. Еще вопросы? [Студент] арифметики указателей. >> Ах да. Струны были легче, но, глядя на то, как целыми, Итак, вернемся к Int х [4]; Является ли это массив или это указатель на malloced массив из 4 чисел, это будет рассматриваться таким же образом. [Студент] Так массивов в куче? [Боуден] Массивы не в куче. >> [Студент] Ох. [Боуден] Этот тип массива, как правило, в стеке если Вы заявил на - игнорирование глобальных переменных. Не используйте глобальные переменные. Внутри функции Я говорю Int х [4]; Он собирается создать 4-целое число блоков в стеке для этого массива. Но это таНос (4 * SizeOf (INT)); будет идти в кучу. Но после этого момента я могу использовать х и р в значительной степени теми же способами, кроме исключений, я уже говорил о вас можно переназначить р. Технически, их размеры несколько отличаются, но это совершенно не имеет значения. Вы никогда не использовать их размеров. Р я могу сказать, р [3] = 2, или х [3] = 2; Вы можете использовать их точно так же способами. Так что арифметика указателей теперь - да. [Студент] Вы не должны делать р * если у вас есть скобки? Скобках неявных ссылок. >> Хорошо. На самом деле, и то, что вы говорите с вы можете получить многомерные массивы с указателями, что вы можете сделать что-то вроде, скажем, Int ** рр = таНос (SizeOf (INT *) * 5); Я просто написать все это в первую очередь. Я не хотел этого. Хорошо. Что я сделал здесь - Это должно быть рр [I]. Так п.п. это указатель на указатель. Вы mallocing п.п. указывает на массив из 5 звезд Int. Таким образом, в памяти у вас в стеке С. Это будет указывать на массив из 5 блоков, которые все сами указатели. А потом, когда я таНос сюда, я таНос, что каждый из этих отдельных указателей должен указывать на отдельный блок из 4 байт в куче. Таким образом, это указывает на 4 байта. А это указывает на другую 4 байт. И все они указывают на своих 4 байт. Это дает мне способ сделать многомерным вещи. Я мог бы сказать п.п. [3] [4], но теперь это не то же самое, многомерные массивы потому что многомерные массивы в ее переводе [3] [4] в одну смещение в массиве х. Это разыменовывает р, доступ к третьему индекса, то, что разыменовывает и доступы - 4 будут считаться недействительными - второй индекс. В то время, когда мы были Int х [3] [4] до как многомерный массив и при двойном кронштейне это действительно только один разыменования, Вы после одного указателя, а затем смещение, это действительно 2D ссылки. Вы следуете 2 отдельные указатели. Таким образом, это также технически позволяет иметь многомерные массивы где каждый массива различных размеров. Поэтому я думаю, зубчатые многомерных массивов является то, что она называется так как на самом деле первое, что может указывать на то, что имеет 10 элементов, Второе, что может указывать на то, что имеет 100 элементов. [Студент] Есть ли ограничение на количество указателей вы можете иметь указывающих на другие указатели? >> Нет. Вы можете иметь Int ***** р. Вернуться к арифметике с указателями - >> [студент] Ох. >> Да. [Студент] Если у меня есть Int *** р а затем я разыменование, и я говорю р * равна этому значению, это только собирается сделать 1 уровень разыменования? >> Да. Так что, если я хочу получить доступ то, что последний указатель направлен на - Тогда вы *** р. >> Хорошо. Так что это р указывает на 1 блок, указывающий на другой блок, указывающий на другой блок. Тогда, если вы делаете * р = что-то другое, то вы меняете эту Теперь, чтобы указать на другой блок. >> Хорошо. [Боуден] И если они были malloced, то вы теперь утечка памяти если вам посчастливилось иметь различные ссылки из этих Поскольку вы не можете вернуться в те, что вы просто выбросили. Указатель арифметика. Int х [4]; собирается выделить массив из 4 чисел где х будет указывать на начало массива. Поэтому, когда я говорю что-то вроде X [1], я хочу, чтобы это означало идти на второй целое число в массиве, , который был бы этому. Но на самом деле, это 4 байта в массиве, так как это целое число занимает 4 байта. Таким образом, смещение 1 на самом деле означает смещение 1 раз размер независимо от типа массива. Это массив целых чисел, поэтому он знает, что нужно делать 1 раз размер Int, когда он хочет, чтобы компенсировать. Другой синтаксис. Помните, что это эквивалентно * (х + 1); Когда я говорю указатель + 1, то, что возвращает это адрес, что указатель хранения плюс 1 раз размер тип указателя. Таким образом, если х = ox100, то х + 1 = ox104. И вы можете злоупотреблять этим и сказать что-то вроде символ * C = (символ *) х; и теперь с будет тот же адрес, х. С будет равна ox100, но с + 1 будет равна ox101 С арифметикой указателя зависит от типа указатель, который вы добавляете в. Таким образом, с + 1, он смотрит на C, это символьный указатель, так что он собирается добавить 1 раза размер символов, который всегда будет на 1, так что вы получите 101, а если я сделаю х, которая также еще 100, х + 1 будет 104. [Студент] Можно ли использовать C + +, в целях продвижения указателя на 1? Да, можно. Вы не можете сделать этого, потому что с х х это просто символ, это постоянная, вы не можете изменить х. Но с происходит, чтобы быть просто указатель, так что C + + является вполне допустимым, и она будет увеличиваться на 1. Если с просто Int *, то C + + будет 104. + + Делает арифметику указателей так же, как с + 1 сделал бы арифметики указателей. На самом деле, как много таких вещей, как сортировки слиянием - Вместо того чтобы создавать копии вещей, вы можете вместо этого пройти - Как если бы я хотел передать эту половину массива - давайте стереть часть этого. Скажем, я хотел бы передать эту сторону массива в функцию. Что бы я передать эту функцию? Если я прохожу х, я передаю этот адрес. Но я хочу, чтобы пройти этот конкретный адрес. Так что я должен пройти? [Студент] указатель + 2? [Боуден] Таким образом, х + 2. Да. Это будет этот адрес. Вы также очень часто вижу это как х [2], а затем адрес этого. Таким образом, вы должны взять на адрес, потому что кронштейн неявных ссылок. х [2] ссылается на значение, которое находится в этом поле, а затем вы хотите адрес этого окна, так что вы говорите и х [2]. Так вот, как что-то сортировки слиянием, где вы хотите передать половину списка, чтобы что-то Вы действительно просто передать и х [2], и в настоящее время, насколько рекурсивный вызов, то, мой новый массив начинается там. Последние вопросы минуту. [Студент] Если мы не будем ставить амперсанд или - что, что называется? >> Star? [Студент] Star. >> Технически, оператор разыменования, но - >> [студент] Dereference. Если мы не ставим звезды или амперсанд, что произойдет, если я просто скажу, у = х и х является указателем? Какой тип у? >> [Студент] Я просто говорю, что это указатель 2. Так что если вы только что сказали у = х, теперь х и у указывают на одно и то же. >> [Студент] указывают на то же самое. И если х Int указателя? >> Было бы жаловаться, потому что вы не можете назначить указателей. [Студент] Хорошо. Помните, что указатели, хотя мы и привлечь их, как стрелы, на самом деле все, что они магазина - Int * х - действительно все х хранения что-то вроде ox100, которые мы, случается, представляющих как указание на блоке хранится 100. Поэтому когда я говорю Int * у = х, я просто копирование ox100 в у, которые мы только собираемся представить как у, также указывая на ox100. И если я говорю Int я = (INT) х, тогда я намерен хранить любые значения ox100 является внутри него, но теперь это будет интерпретироваться как целое, а не указатель. Но для этого нужно литых или же он будет жаловаться. [Студент] Таким образом, вы имеете в виду, чтобы бросить - Это собирается быть литья Int х или литье Int у? [Боуден] Что? [Студент] Хорошо. После этих скобках там будет х или ау там? [Боуден] Либо. х и у являются эквивалентными. >> [Студент] Хорошо. Потому что они оба указателя. >> Да. [Студент] Поэтому было бы хранить шестнадцатеричное целое число 100 в форме? >> [Боуден] Да. Но не значение того, что это указывает. [Боуден] Да. >> [Студент] Таким образом, только адрес в целочисленном виде. Хорошо. [Боуден] Если вы хотели бы по некоторой странной причине, Вы могли бы иметь дело исключительно с указателями и никогда не иметь дело с целыми числами и просто быть как Int * х = 0. Тогда вы собираетесь получить действительно путают раз арифметики указателей начинает происходить. Так что цифры, которые они хранят не имеют смысла. Это просто, как вы в конечном итоге их интерпретации. Так что я свободно копировать ox100 от Int * в целое число, и я свободно назначать - ты, вероятно, собираюсь кричать на что не литье - Я свободен назначить что-то вроде (Int *) ox1234 в этой произвольной * Int. Так ox123 так же верен адрес памяти, как это и у. И у случается, вернуть то, что является в значительной степени ox123. [Студент] Это было бы действительно здорово путь от шестнадцатеричной в десятичную форму, нравится, если у вас есть указатель, и вы бросили его в виде целого числа? [Боуден] Вы действительно можете просто печатать, используя как Printf. Скажем, у меня есть Int у = 100. Таким образом, Е (% г \ п - как вы уже знаете - печать, что как целое, х%. Мы просто распечатать его как шестнадцатеричное. Таким образом, указатель не хранится в шестнадцатеричном, и целое не хранится в виде десятичной. Все хранится в двоичном виде. Это только, что мы, как правило, чтобы показать, указатели, как шестнадцатеричное потому что мы думаем о вещах, в этих 4-байтовых блоков, и адреса памяти, как правило, знакомы. Мы как, если он начинается с BF, то оно произойдет, будет в стеке. Так что это просто наша интерпретация указатели, как шестнадцатеричное. Хорошо. Любой последних вопросов? Я буду здесь немного после, если у вас есть что-то еще. И это конец. [Студент] Ура! [Аплодисменты] [CS50.TV]