Сколько байтов занимает следующая строка в памяти компьютера, я стану лучшим программистом в мире

Обновлено: 01.07.2024

Несмотря на распространенность языков высокого уровня, язык программирования C продолжает расширять возможности мира. Есть много причин полагать, что программирование на C будет оставаться актуальным еще долгое время. Вот несколько причин, по которым C непревзойден и почти обязателен для некоторых приложений.

Дэниел создал высокопроизводительные приложения на C++ для крупных компаний, таких как Dreamworks. Он также преуспевает в C и ASM (x86).

Многие из существующих сегодня проектов C были начаты несколько десятилетий назад.

Разработка операционной системы UNIX началась в 1969 году, а ее код был переписан на C в 1972 году. Фактически язык C был создан для переноса кода ядра UNIX с ассемблера на язык более высокого уровня, который выполнял бы те же задачи с меньшими затратами. строки кода.

Разработка базы данных Oracle началась в 1977 году, а ее код был переписан с ассемблера на C в 1983 году. Она стала одной из самых популярных баз данных в мире.

В 1985 году была выпущена Windows 1.0. Хотя исходный код Windows не является общедоступным, было заявлено, что его ядро ​​​​в основном написано на C, а некоторые части находятся на ассемблере. Разработка ядра Linux началась в 1991 году, и оно также написано на C. В следующем году оно было выпущено под лицензией GNU и использовалось как часть операционной системы GNU. Сама операционная система GNU была запущена с использованием языков программирования C и Lisp, поэтому многие ее компоненты написаны на C.

Но программирование на C не ограничивается проектами, начатыми несколько десятилетий назад, когда языков программирования не было так много, как сегодня. Многие проекты на C все еще начаты сегодня; для этого есть несколько веских причин.

Как мир работает на C?

Несмотря на распространенность языков высокого уровня, C продолжает расширять возможности мира. Ниже перечислены некоторые из систем, которые используются миллионами и запрограммированы на языке C.

Майкрософт Windows

Ядро Microsoft Windows разработано в основном на языке C, а некоторые части — на ассемблере. На протяжении десятилетий самая используемая операционная система в мире, на долю которой приходится около 90 % рынка, работает на ядре, написанном на C.

Линукс

Linux также написан в основном на C с некоторыми частями на ассемблере. Около 97 процентов из 500 самых мощных суперкомпьютеров мира работают под управлением ядра Linux. Он также используется во многих персональных компьютерах.

Компьютеры Mac также работают на C, поскольку ядро ​​OS X написано в основном на C. Каждая программа и драйвер на Mac, как и на компьютерах с Windows и Linux, работают на ядре C.

Мобильный

Ядра iOS, Android и Windows Phone также написаны на C. Они представляют собой просто мобильные адаптации существующих ядер Mac OS, Linux и Windows. Итак, смартфоны, которыми вы пользуетесь каждый день, работают на ядре C.

Базы данных

Самые популярные в мире базы данных, в том числе Oracle Database, MySQL, MS SQL Server и PostgreSQL, написаны на C (первые три из них на самом деле и на C, и на C++).

Базы данных используются во всех типах систем: финансовых, правительственных, медиа, развлекательных, телекоммуникационных, медицинских, образовательных, розничных, социальных, веб- и т. д.

3D-фильмы

3D-фильмы создаются с помощью приложений, которые обычно написаны на C и C++. Эти приложения должны быть очень эффективными и быстрыми, поскольку они обрабатывают огромные объемы данных и выполняют множество вычислений в секунду. Чем эффективнее они работают, тем меньше времени требуется художникам и аниматорам для создания кадров фильма, и тем больше денег экономит компания.

Встроенные системы

Представьте, что однажды вы просыпаетесь и идете за покупками. Будильник, который будит вас, вероятно, запрограммирован на C. Затем вы используете микроволновую печь или кофеварку, чтобы приготовить себе завтрак. Они также являются встроенными системами и поэтому, вероятно, запрограммированы на C. Вы включаете телевизор или радио во время завтрака. Это также встроенные системы, работающие на C. Когда вы открываете дверь гаража с помощью пульта дистанционного управления, вы также используете встроенную систему, которая, скорее всего, запрограммирована на C.

Затем вы садитесь в машину. Если он имеет следующие функции, также запрограммированные на C:

  • автоматическая коробка передач
  • системы контроля давления в шинах
  • датчики (кислорода, температуры, уровня масла и т. д.)
  • память настроек сидений и зеркал.
  • панель управления
  • антиблокировочная система тормозов
  • автоматический контроль устойчивости
  • круиз-контроль
  • климат-контроль
  • замки с защитой от детей
  • вход без ключа
  • подогрев сидений
  • управление подушкой безопасности

Вы добираетесь до магазина, паркуете машину и идете к автомату за газировкой. Какой язык они использовали для программирования этого торгового автомата? Вероятно, С. Тогда вы покупаете что-то в магазине.Кассовый аппарат тоже запрограммирован на C. А когда вы платите кредитной картой? Как вы уже догадались: устройство чтения кредитных карт опять же, скорее всего, запрограммировано на C.

Все эти устройства являются встроенными системами. Они похожи на небольшие компьютеры, внутри которых есть микроконтроллер/микропроцессор, который запускает программу, также называемую прошивкой, на встроенных устройствах. Эта программа должна обнаруживать нажатия клавиш и действовать соответствующим образом, а также отображать информацию для пользователя. Например, будильник должен взаимодействовать с пользователем, определяя, какую кнопку нажимает пользователь, а иногда и как долго она нажата, и соответствующим образом программировать устройство, одновременно отображая пользователю соответствующую информацию. Антиблокировочная тормозная система автомобиля, например, должна обнаруживать внезапную блокировку шин и на короткое время сбрасывать давление на тормоза, разблокируя их и тем самым предотвращая неконтролируемое занос. Все эти расчеты выполняются запрограммированной встроенной системой.

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

Почему до сих пор используется язык программирования C?

Сегодня существует множество языков программирования, которые позволяют разработчикам работать более продуктивно, чем C, для различных типов проектов. Существуют языки более высокого уровня, которые предоставляют гораздо большие встроенные библиотеки, которые упрощают работу с JSON, XML, пользовательским интерфейсом, веб-страницами, клиентскими запросами, подключениями к базе данных, манипулированием мультимедиа и т. д.

Но, несмотря на это, есть много причин полагать, что программирование на C будет оставаться актуальным еще долгое время.

В языках программирования один размер не подходит всем. Вот несколько причин, по которым C непревзойден и почти обязателен для некоторых приложений.

Портативность и эффективность

C — это почти переносимый язык ассемблера. Он максимально приближен к машине и почти повсеместно доступен для существующих процессорных архитектур. Почти для каждой существующей архитектуры существует по крайней мере один компилятор C. И в настоящее время из-за высокооптимизированных двоичных файлов, генерируемых современными компиляторами, не так просто улучшить их вывод с помощью написанного вручную ассемблера.

Его переносимость и эффективность настолько высоки, что «компиляторы, библиотеки и интерпретаторы других языков программирования часто реализуются на C». Интерпретируемые языки, такие как Python, Ruby и PHP, имеют свои основные реализации, написанные на C. Он даже используется компиляторами других языков для связи с машиной. Например, C является промежуточным языком, лежащим в основе Eiffel и Forth. Это означает, что вместо того, чтобы генерировать машинный код для каждой поддерживаемой архитектуры, компиляторы для этих языков просто генерируют промежуточный код C, а компилятор C занимается генерацией машинного кода.

C – отличный язык для выражения общих идей программирования удобным для большинства людей способом. Более того, многие принципы, используемые в C, например, argc и argv для параметров командной строки, а также конструкции циклов и типы переменных, появятся во многих других языках, которые вы изучаете, так что вы сможете говорить людям, даже если они не знают C так, как это свойственно вам обоим.

Манипулирование памятью

Доступ к произвольным адресам памяти и арифметические операции с указателями — важная функция, благодаря которой C идеально подходит для системного программирования (операционные системы и встроенные системы).

На границе аппаратного и программного обеспечения компьютерные системы и микроконтроллеры сопоставляют свои периферийные устройства и контакты ввода-вывода с адресами памяти. Системные приложения должны читать и записывать в эти пользовательские ячейки памяти для связи с миром. Таким образом, способность C манипулировать произвольными адресами памяти необходима для системного программирования.

Микроконтроллер можно спроектировать, например, так, чтобы байт в памяти с адресом 0x40008000 был отправлен универсальным асинхронным приемником/передатчиком (или UART, общим аппаратным компонентом для связи с периферийными устройствами). каждый раз, когда бит номер 4 адреса 0x40008001 устанавливается в 1, и что после того, как вы установите этот бит, он будет автоматически сбрасываться периферийным устройством.

Это будет код для функции C, которая отправляет байт через этот UART:

Первая строка функции будет расширена до:

Эта строка указывает компилятору интерпретировать значение 0x40008000 как указатель на char , затем разыменовать (дать значение, на которое указывает) этот указатель (с крайним левым оператором *) и, наконец, присвоить байтовое значение этому разыменованному указателю. . Другими словами: запишите значение переменной byte по адресу памяти 0x40008000 .

Следующая строка будет расширена до:

В этой строке мы выполняем побитовую операцию ИЛИ над значением по адресу 0x40008001 и значением 0x08 (00001000 в двоичном формате, т. е. 1 в бите номер 4) и сохраняем результат обратно по адресу 0x40008001. Другими словами: мы устанавливаем бит 4 байта, который находится по адресу 0x40008001. Мы также объявляем, что значение по адресу 0x40008001 является изменчивым. Это сообщает компилятору, что это значение может быть изменено процессами, внешними по отношению к нашему коду, поэтому компилятор не будет делать никаких предположений о значении в этом адресе после записи в него. (В данном случае этот бит сбрасывается аппаратно UART сразу после того, как мы устанавливаем его программно.) Эта информация важна для оптимизатора компилятора. Если бы мы сделали это внутри цикла for, например, не указав, что значение является изменчивым, компилятор мог бы предположить, что это значение никогда не изменяется после установки, и пропустить выполнение команды после первого цикла.

Детерминированное использование ресурсов

Общая языковая функция, на которую системное программирование не может полагаться, — это сборка мусора или даже просто динамическое выделение для некоторых встроенных систем. Встроенные приложения очень ограничены по времени и ресурсам памяти. Они часто используются для систем реального времени, где недетерминированный вызов сборщика мусора невозможен. И если динамическое выделение нельзя использовать из-за нехватки памяти, очень важно иметь другие механизмы управления памятью, такие как размещение данных по настраиваемым адресам, как это позволяют указатели C. Языки, сильно зависящие от динамического выделения памяти и сборки мусора, не подходят для систем с ограниченными ресурсами.

Размер кода

C имеет очень маленькое время выполнения. И объем памяти для его кода меньше, чем для большинства других языков.

Например, по сравнению с C++ двоичный файл, сгенерированный на C, который отправляется на встроенное устройство, примерно вдвое меньше двоичного файла, сгенерированного аналогичным кодом на C++. Одной из основных причин этого является поддержка исключений.

Исключения — это отличный инструмент, добавленный C++ поверх C, и, если их не запускать и правильно реализовывать, они практически не требуют дополнительных затрат времени на выполнение (но за счет увеличения размера кода).

Давайте рассмотрим пример на C++:

Методы классов A , B и C определены где-то еще (например, в других файлах). Поэтому компилятор не может их анализировать и не может знать, вызовут ли они исключения. Поэтому он должен быть готов к обработке исключений, вызванных любым из их конструкторов, деструкторов или вызовов других методов. Деструкторы не должны генерировать исключение (очень плохая практика), но пользователь все равно может генерировать исключение, или они могут вызывать генерацию косвенно, вызывая какую-либо функцию или метод (явно или неявно), которые генерируют исключение.

Если какой-либо из вызовов в myFunction вызывает исключение, механизм раскрутки стека должен иметь возможность вызывать все деструкторы для уже созданных объектов. Одна реализация механизма раскручивания стека будет использовать адрес возврата последнего вызова этой функции для проверки «номера контрольной точки» вызова, вызвавшего исключение (это простое объяснение). Он делает это, используя вспомогательную автоматически сгенерированную функцию (своего рода справочную таблицу), которая будет использоваться для раскручивания стека в случае возникновения исключения из тела этой функции, которое будет похоже на это:

Если исключение выдается из контрольных точек 1 и 9, уничтожение объектов не требуется. Для контрольной точки 3 b и a должны быть уничтожены. Для контрольной точки 6, c и a должны быть уничтожены. Во всех случаях порядок уничтожения должен соблюдаться. Для контрольных точек 2, 4, 5, 7 и 8 необходимо уничтожить только объект a.

Эта вспомогательная функция увеличивает размер кода. Это часть служебного пространства, которое C++ добавляет к C. Многие встраиваемые приложения не могут позволить себе такое дополнительное пространство. Поэтому компиляторы C++ для встраиваемых систем часто имеют флаг для отключения исключений. Отключение исключений в C++ не является бесплатным, поскольку стандартная библиотека шаблонов в значительной степени зависит от исключений для информирования об ошибках. Использование этой модифицированной схемы без исключений требует дополнительного обучения разработчиков C++ для выявления возможных проблем или поиска ошибок.

И мы говорим о C++, языке, принцип которого гласит: «Вы не платите за то, чем не пользуетесь». Это увеличение размера двоичного файла усугубляется для других языков, которые добавляют дополнительные накладные расходы с другими функциями, которые очень полезны, но не могут быть предоставлены встроенными системами. Хотя C не дает вам возможности использовать эти дополнительные функции, он обеспечивает гораздо более компактный размер кода, чем другие языки.

Причины изучения C

C — несложный язык для изучения, поэтому все преимущества его изучения обойдутся довольно дешево. Давайте рассмотрим некоторые из этих преимуществ.

Лингва франка

Как уже упоминалось, C — это язык межнационального общения для разработчиков. Многие реализации новых алгоритмов в книгах или в Интернете впервые (или только) доступны на языке C их авторами.Это дает максимально возможную переносимость реализации. Я видел, как программисты пытались в Интернете переписать алгоритм C на другие языки программирования, потому что они не знали самых основных концепций C.

Имейте в виду, что C — это старый и широко распространенный язык, поэтому в Интернете можно найти всевозможные алгоритмы, написанные на C. Поэтому вам, скорее всего, будет полезно знать этот язык.

Понимание машины (думай на C)

Когда мы обсуждаем поведение определенных частей кода или определенных функций других языков с коллегами, мы заканчиваем тем, что «говорим на C»: эта часть передает «указатель» на объект или копирует весь объект? Мог ли здесь происходить какой-то «каст»? И так далее.

Мы редко обсуждаем (или думаем) об инструкциях ассемблера, которые выполняет часть кода, анализируя поведение части кода языка высокого уровня. Вместо этого, обсуждая, что делает машина, мы довольно ясно говорим (или думаем) на C.

Более того, если вы не можете остановиться и подумать таким образом о том, что вы делаете, вы можете закончить тем, что программируете с каким-то суеверием относительно того, как (волшебным образом) что-то делается.

Работа над многими интересными проектами на C

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

Заключение

Похоже, у языка программирования C нет срока годности. Его близость к оборудованию, отличная переносимость и детерминированное использование ресурсов делают его идеальным для низкоуровневой разработки таких вещей, как ядра операционных систем и встроенное программное обеспечение. Его универсальность, эффективность и хорошая производительность делают его отличным выбором для программ обработки данных высокой сложности, таких как базы данных или 3D-анимация. Тот факт, что сегодня многие языки программирования лучше, чем C, для предполагаемого использования, не означает, что они превосходят C во всех областях. C по-прежнему непревзойден, когда производительность является приоритетом.

Мир работает на устройствах с процессором C. Мы используем эти устройства каждый день, осознаем мы это или нет. C — это прошлое, настоящее и, насколько мы можем судить, будущее для многих областей программного обеспечения.

Получите полный доступ к Practical C Programming, 3rd Edition и более чем 60 000 другим играм с бесплатной 10-дневной пробной версией O'Reilly.

Есть также прямые онлайн-мероприятия, интерактивный контент, материалы для подготовки к сертификации и многое другое.

Глава 4. Основные объявления и выражения

Путешествие в тысячу миль должно начинаться с одного шага.

Если бы плотники строили здания так же, как программисты создают программы, первый дятел, который появится, уничтожит всю цивилизацию.

Элементы программы

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

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

В строительстве, прежде чем мы сможем начать, мы должны заказать наши материалы: «Нам нужно 500 больших кирпичей, 80 половинных кирпичей и 4 плиты». Точно так же в C мы должны объявить наши переменные, прежде чем сможем их использовать. Мы должны назвать каждый из наших «кирпичей» и указать C, какой тип кирпичей использовать.

После того, как наши переменные определены, мы можем начать их использовать. В строительстве основной структурой является помещение. Объединив множество комнат, мы образуем здание. В C базовой структурой является функция. Функции могут быть объединены в программу.

Начинающий строитель не начинает строить Эмпайр Стейт Билдинг, а начинает с однокомнатного дома. В этой главе мы сосредоточимся на создании простых однофункциональных программ.

Базовая структура программы

Основными элементами программы являются объявления данных, функции и комментарии. Давайте посмотрим, как их можно организовать в простую программу на C.

Основная структура однофункциональной программы:

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

Наша единственная функция называется main . Имя main особенное, потому что это первая вызываемая функция. Другие функции вызываются прямо или косвенно из main . Функция main начинается с:

Строка return(0); используется, чтобы сообщить операционной системе (UNIX или MS-DOS/Windows), что программа завершилась нормально (Status=0). Ненулевой статус указывает на ошибку — чем больше возвращаемое значение, тем серьезнее ошибка. Как правило, статус 1 используется для самых простых ошибок, таких как отсутствующий файл или неверный синтаксис командной строки.

Теперь давайте взглянем на нашу программу Hello World (пример 3-1).

В начале программы есть поле комментария, заключенное в /* и */. За этим полем следует строка:

Это утверждение сигнализирует C, что мы собираемся использовать стандартный пакет ввода-вывода. Оператор является типом объявления данных. [5] Позже мы воспользуемся функцией printf из этого пакета.

Наша основная процедура содержит инструкцию:

Эта строка представляет собой исполняемый оператор, предписывающий C вывести на экран сообщение «Hello World». C использует точку с запятой ( ; ) для завершения оператора почти так же, как мы используем точку для завершения предложения. В отличие от языков, ориентированных на строки, таких как BASIC, конец строки не завершает оператор. Предложения в этой книге могут занимать несколько строк — конец строки рассматривается как пробел между словами. C работает так же. Один оператор может занимать несколько строк. Точно так же вы можете поместить несколько предложений в одну строку, так же как вы можете поместить несколько операторов C в одну строку. Однако в большинстве случаев ваша программа будет более читабельной, если каждый оператор будет начинаться с отдельной строки.

Для вывода нашего сообщения используется стандартная функция printf. Библиотечная подпрограмма — это процедура или функция на языке C, написанная и помещенная в библиотеку или набор полезных функций. Такие подпрограммы выполняют сортировку, ввод, вывод, математические функции и работу с файлами. Полный список библиотечных функций см. в справочном руководстве по языку C.

Hello World — одна из самых простых программ на C. Он не содержит вычислений; он просто отправляет одно сообщение на экран. Это отправная точка. Освоив эту простую программу, вы сделали ряд вещей правильно.

Простые выражения

Компьютеры могут не только печатать строки, но и выполнять вычисления. Выражения используются для указания простых вычислений. Пять простых операторов C перечислены в таблице 4-1.

Переменная f занимает четыре байта оперативной памяти. У этого местоположения есть определенный адрес, в данном случае 248 440.

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

Все компьютеры имеют память, также известную как ОЗУ (оперативная память). Например, прямо сейчас на вашем компьютере может быть установлено 16, 32 или 64 мегабайта оперативной памяти. Оперативная память содержит программы, которые в данный момент выполняются на вашем компьютере, а также данные, с которыми они в данный момент манипулируют (их переменные и структуры данных). Память можно рассматривать просто как массив байтов. В этом массиве каждая ячейка памяти имеет свой собственный адрес — адрес первого байта равен 0, за ним следуют 1, 2, 3 и так далее. Адреса памяти действуют так же, как индексы обычного массива. Компьютер может получить доступ к любому адресу в памяти в любое время (отсюда и название «оперативная память»). Он также может группировать байты вместе, если это необходимо для формирования больших переменных, массивов и структур. Например, переменная с плавающей запятой занимает в памяти 4 последовательных байта. Вы можете сделать следующее глобальное объявление в программе:

В этом утверждении говорится: "Объявите местоположение с именем f, которое может содержать одно значение с плавающей запятой". Когда программа запускается, компьютер резервирует место для переменной f где-то в памяти. Это место имеет фиксированный адрес в пространстве памяти, например:

Пока вы думаете о переменной f, компьютер думает об определенном адресе в памяти (например, 248 440). Поэтому, когда вы создаете подобное заявление:

Компилятор может перевести это как "Загрузить значение 3,14 в ячейку памяти 248 440". Компьютер всегда думает о памяти с точки зрения адресов и значений по этим адресам.

Кстати, у того, как ваш компьютер обрабатывает память, есть несколько интересных побочных эффектов. Например, предположим, что вы включили в одну из своих программ следующий код:

Вывод, который вы видите из программы, вероятно, будет выглядеть следующим образом:

Поэтому, когда вы пытаетесь записать в несуществующий s[4], вместо этого система записывает в t[0], потому что t[0] находится там, где должен быть s[4]. Когда вы пишете в t[4], вы на самом деле пишете в u. Что касается компьютера, то s[4] — это просто адрес, и он может писать в него. Однако, как вы можете видеть, даже если компьютер выполняет программу, она неверна или недействительна. Программа портит массив t в процессе работы. Если вы выполните следующий оператор, это приведет к более серьезным последствиям:

Местоположение s[1000000], скорее всего, находится за пределами памяти вашей программы. Другими словами, вы записываете в память, которой не владеет ваша программа. В системе с защищенными пространствами памяти (UNIX, Windows 98/NT) оператор такого рода заставит систему прекратить выполнение программы. Однако в других системах (Windows 3.1, Mac) система не знает, что вы делаете. Вы в конечном итоге повреждаете код или переменные в другом приложении. Последствия нарушения могут варьироваться от полного отсутствия до полного сбоя системы. В памяти i, s, t и u располагаются рядом друг с другом по определенным адресам. Поэтому, если вы запишете за пределы переменной, компьютер сделает то, что вы скажете, но в конечном итоге это приведет к повреждению другой области памяти.

Поскольку C и C++ не выполняют какой-либо проверки диапазона при доступе к элементу массива, важно, чтобы вы, как программист, сами уделяли пристальное внимание диапазонам массива и не выходили за соответствующие границы массива. Непреднамеренное чтение или запись за пределами массива всегда приводит к неправильному поведению программы.

В качестве другого примера попробуйте следующее:

Этот код говорит компилятору распечатать адрес, содержащийся вp, вместе с адресом ofi. Переменная p начинается с какого-то сумасшедшего значения или с 0. Адрес i обычно имеет большое значение. Например, когда я запустил этот код, я получил следующий результат:

что означает, что адрес i равен 2147478276. Как только выражение p = &i; был выполнен, p содержит адрес i. Попробуйте и это:

Этот код указывает компилятору напечатать значение, на которое указывает p. Однако p еще не инициализирован; он содержит адрес 0 или какой-то случайный адрес. В большинстве случаев возникает ошибка сегментации (или какая-либо другая ошибка времени выполнения), что означает, что вы использовали указатель, указывающий на недопустимую область памяти. Почти всегда неинициализированный указатель или неверный адрес указателя являются причиной ошибок сегментации.

Сказав все это, теперь мы можем взглянуть на указатели в совершенно новом свете. Возьмем, к примеру, эту программу:

Вот что происходит:

Переменная i занимает 4 байта памяти. Указатель p также занимает 4 байта (на большинстве машин, используемых сегодня, указатель занимает 4 байта памяти. Сегодня на большинстве ЦП адреса памяти имеют длину 32 бита, хотя наблюдается растущая тенденция к 64-битной адресации). Местоположение i имеет определенный адрес, в данном случае 248 440. Указатель p содержит этот адрес, когда вы говорите p = &i;. Таким образом, переменные *p и i эквивалентны.

Указатель p буквально содержит адрес i. Когда вы говорите что-то подобное в программе:

Получите полный доступ к Practical C Programming, 3rd Edition и более чем 60 000 другим играм с бесплатной 10-дневной пробной версией O'Reilly.

Есть также прямые онлайн-мероприятия, интерактивный контент, материалы для подготовки к сертификации и многое другое.

Глава 4. Основные объявления и выражения

Путешествие в тысячу миль должно начинаться с одного шага.

Если бы плотники строили здания так же, как программисты создают программы, первый дятел, который появится, уничтожит всю цивилизацию.

Элементы программы

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

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

В строительстве, прежде чем мы сможем начать, мы должны заказать наши материалы: «Нам нужно 500 больших кирпичей, 80 половинных кирпичей и 4 плиты». Точно так же в C мы должны объявить наши переменные, прежде чем сможем их использовать. Мы должны назвать каждый из наших «кирпичей» и указать C, какой тип кирпичей использовать.

После того, как наши переменные определены, мы можем начать их использовать. В строительстве основной структурой является помещение. Объединив множество комнат, мы образуем здание. В C базовой структурой является функция. Функции могут быть объединены в программу.

Начинающий строитель не начинает строить Эмпайр Стейт Билдинг, а начинает с однокомнатного дома. В этой главе мы сосредоточимся на создании простых однофункциональных программ.

Базовая структура программы

Основными элементами программы являются объявления данных, функции и комментарии. Давайте посмотрим, как их можно организовать в простую программу на C.

Основная структура однофункциональной программы:

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

Наша единственная функция называется main . Имя main особенное, потому что это первая вызываемая функция. Другие функции вызываются прямо или косвенно из main . Функция main начинается с:

Строка return(0); используется, чтобы сообщить операционной системе (UNIX или MS-DOS/Windows), что программа завершилась нормально (Status=0). Ненулевой статус указывает на ошибку — чем больше возвращаемое значение, тем серьезнее ошибка. Как правило, статус 1 используется для самых простых ошибок, таких как отсутствующий файл или неверный синтаксис командной строки.

Теперь давайте взглянем на нашу программу Hello World (пример 3-1).

В начале программы есть поле комментария, заключенное в /* и */. За этим полем следует строка:

Это утверждение сигнализирует C, что мы собираемся использовать стандартный пакет ввода-вывода. Оператор является типом объявления данных. [5] Позже мы воспользуемся функцией printf из этого пакета.

Наша основная процедура содержит инструкцию:

Эта строка представляет собой исполняемый оператор, предписывающий C вывести на экран сообщение «Hello World». C использует точку с запятой ( ; ) для завершения оператора почти так же, как мы используем точку для завершения предложения. В отличие от языков, ориентированных на строки, таких как BASIC, конец строки не завершает оператор. Предложения в этой книге могут занимать несколько строк — конец строки рассматривается как пробел между словами. C работает так же. Один оператор может занимать несколько строк. Точно так же вы можете поместить несколько предложений в одну строку, так же как вы можете поместить несколько операторов C в одну строку. Однако в большинстве случаев ваша программа будет более читабельной, если каждый оператор будет начинаться с отдельной строки.

Для вывода нашего сообщения используется стандартная функция printf. Библиотечная подпрограмма — это процедура или функция на языке C, написанная и помещенная в библиотеку или набор полезных функций. Такие подпрограммы выполняют сортировку, ввод, вывод, математические функции и работу с файлами. Полный список библиотечных функций см. в справочном руководстве по языку C.

Hello World — одна из самых простых программ на C. Он не содержит вычислений; он просто отправляет одно сообщение на экран. Это отправная точка. Освоив эту простую программу, вы сделали ряд вещей правильно.

Простые выражения

Компьютеры могут не только печатать строки, но и выполнять вычисления. Выражения используются для указания простых вычислений. Пять простых операторов C перечислены в таблице 4-1.

Читайте также: