Как сделать структуру программы

Обновлено: 07.07.2024

  • объявление пространства имен (своего рода контейнера);
  • объявление класса (основная сущность программы);
  • методы класса (подпрограммы), как минимум метод Main;
  • операторы и выражения;
  • комментарии.

Пример простейшей программы

Первая строка данной программы, это комментарий. Комментарии никак не влияют на работу программы, они нужны для человека, который будет сопровождать код программы (дорабатывать её, исправлять ошибки и т.п.).

В строке 11 как раз и объявляется метод Main. Этот метод является главным в нашей программе, так называемая точка входа в программу. Это означает, что при запуске программы, первым будет выполняться именно метод Main. Каждый метод тоже имеет границы, которые так же обозначаются фигурными скобками (строки 12 и 17).

А теперь попробуйте собрать и запустить это программу в Visual Studio. Для этого нужно:

  • запустить Visual Studio;
  • создать новый проект консольного приложения;
  • скопировать строки 13-16 из приведенного выше примера;
  • вставить эти строки в метод Main созданного в Visual Studio проекта;
  • нажать клавишу F5.

О том как создавать проект консольного приложения в Visual Studion я подробно рассказывал в этом уроке, советую прочитать его.

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

Этапы разработки программы

Зачем нужно проектировать программу и соблюдать этапы разработки?

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

В зависимости от размера программных проектов этапы разработки могут отличаться, в некоторых случаях это будут очень детализированные и бюрократичные этапы, а в некоторых — просто сформулированные в любом удобном для разработчиков виде.

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

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

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

Чем раньше будут обнаружены ошибки или выявлен неправильных подход в реализации того или иного действия, тем цена этих ошибок будет меньше. Иными словами, в зависимости от этапа обнаружения ошибки ее цена может меняться от 10 до 100 раз. Например, если на самом начальном этапе цена исправления ошибки будет равняться 100 рублей, то на этапе тестирования она может вылиться в 10000. Поэтому этапы разработки ПО очень важны, и разработчик должен их соблюдать и попытаться донести это видение до менеджеров, которым всегда нужен только результат. Так как они или отводят на это слишком мало времени или и вовсе не считают это необходимым, например, зачем при программировании вырабатывать какие-то требования или что-то там проектировать.

Основные этапы разработки ПО

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

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

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

Этап 1 – Определение проблемы

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

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

Определение проблемы – это фундамент всего процесса программирования!

Этап 2 – Выработка требований

Что такое требования и зачем их нужно выработать?

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

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

Этап 3 – Создание плана разработки

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

Этап 4 – Разработка архитектуры системы или высокоуровневое проектирование

Архитектура системы – это каркас программы, это высокоуровневое проектирование программы.

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

Архитектура системы обычно включает:

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

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

Этап 5 – Детальное проектирование

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

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

Но при реализации крупных проектов данному процессу отводится отдельный этап и проектирование в этом случае проводится с очень высокой степенью детальности.

Этап 6 – Кодирование и отладка

Это как раз тот этап, который все знают и, наверное, думают, что это единственный этап в процессе разработке программного обеспечения – это непосредственное написание кода и его отладка. Но, как видите, это далеко не первый и не единственный этап разработки ПО.

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

После того как код написан, программисту необходимо отладить этот код, чтобы в нем не было никаких ошибок.

Этап 7 – Тестирование компонентов

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

Этап 8 – Интеграция компонентов

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

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

Этап 9 – Тестирование всей системы

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

Этап 10 – Сопровождение, внесение изменений, оптимизация

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

В этой главе мы сначала рассмотрим ряд тем, которые важны для каждой программы на C++. Поскольку тем, которые нужно охватить, довольно много, мы рассмотрим большую часть на довольно поверхностном (достаточном для понимания) уровне. Цель этой главы – помочь вам понять, как строятся простейшие программы на C++. К концу главы вы сможете писать свои собственные простые программы.

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

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

Инструкции

Компьютерная программа – это последовательность инструкций, которые говорят компьютеру, что делать. Инструкция (оператор, statement) заставляет программу выполнять какое-либо действие.

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

Большинство (но не все) инструкций в C++ заканчиваются точкой с запятой. Если вы видите строку, оканчивающуюся точкой с запятой, вероятно, это инструкция.

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

Для продвинутых читателей

В C++ есть много разных типов инструкций:

  1. инструкции объявления;
  2. инструкции переходов;
  3. инструкции выражений;
  4. составные инструкции;
  5. инструкции выбора (условия);
  6. инструкции итерации (циклы);
  7. блоки попыток (try).

К тому времени, когда вы прочтете эту серию статей, вы поймете, что всё это такое!

Функции и функция main

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

Правило

Каждая программа на C++ должна иметь специальную функцию с именем main (все буквы в нижнем регистре). Когда программа запускается, операторы внутри main выполняются в последовательном порядке.

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

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

Примечание автора

Препарирование программы HelloWorld!

Строка 1 – это особый тип строки, называемый директивой препроцессора. Эта директива препроцессора указывает, что мы хотели бы использовать содержимое библиотеки iostream , которая является частью стандартной библиотеки C++, которая позволяет нам читать и записывать текст из и в консоль. Эта строка нужна нам для использования std::cout в строке 5. Удаление этой строки привело бы к ошибке компиляции в строке 5, поскольку иначе компилятор не узнал бы, что такое std::cout .

Строка 3 сообщает компилятору, что мы собираемся написать (определить) функцию с именем main . Как вы узнали ранее, каждая программа на C++ должна иметь функцию main , иначе она не сможет компилироваться.

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

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

Примечание автора

Если часть (или всё из) приведенного выше объяснения сбивает вас с толку, то этого можно было ожидать на данном этапе. Это было просто для краткого обзора. В последующих уроках будут подробно рассмотрены все вышеперечисленные темы с большим количеством дополнительных объяснений и примеров.

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

Синтаксис и синтаксические ошибки

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

В C++ тоже есть синтаксис: правила о том, как ваши программы должны быть построены, чтобы считаться корректными. Когда вы компилируете свою программу, компилятор отвечает за то, чтобы ваша программа следовала базовому синтаксису языка C++. Если вы нарушите это правило, компилятор пожалуется, когда вы попытаетесь скомпилировать свою программу, и выдаст вам синтаксическую ошибку.

Не стесняйтесь компилировать самостоятельно эту плохо сформированную программу.

Это означает, что у вас есть синтаксическая ошибка в строке 6: компилятор ожидал точку с запятой перед оператором return , но не нашел ее. Хотя компилятор сообщит вам, какую строку кода он компилировал, когда обнаружил синтаксическую ошибку, на самом деле пропуск может быть в предыдущей строке. В этом случае ошибка фактически находится в конце строки 5 (компилятор не обнаружил проблему до строки 6).

Время для теста

Следующий тест призван укрепить ваше понимание представленного выше материала.

Вопрос 1

Что такое инструкция (statement)?

Инструкция в компьютерной программе – это аналог предложения в естественном языке. Она сообщает компьютеру выполнить какое-либо действие.

Вопрос 2

Что такое функция?

Функция – это набор инструкций, которые выполняются последовательно.

Вопрос 3

Как называется функция, которая должна быть во всех программах?

Вопрос 4

Где начинается выполнение, когда запускается программа?

Выполнение начинается с первой инструкции внутри функции main .

Вопрос 5

Каким символом часто заканчиваются инструкции в C++?

Точка с запятой ( ; ).

Вопрос 6

Что такое синтаксическая ошибка?

Синтаксическая ошибка – это ошибка, выдаваемая компилятором во время компиляции, когда ваша программа нарушает грамматические правила языка C++.

Вопрос 7

Что такое стандартная библиотека C++?

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


  • Выберите в списке Templates (Шаблоны) пункт C++ File (Файл C++). Укажите Ishodnik в качестве названия файла. Введите в окно исходника файла (Ishodnik.cpp) код примера:
  • Скомпилируйте и запустите проект: Выберите пункт меню Build => Build (Создать => Создать).

Тест пройден успешно! Используйте этот проект для запуска программ, исходные тексты которых приводятся ниже. Изменяйте только текст программы в исходном файле проекта, компилируйте его и осуществляйте запуск.

Исходная программа на Си – это совокупность следующих элементов: директив препроцессора, объявлений (деклараций), определений.

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

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

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

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

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

Функция main служит точкой старта при выполнении программы.

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

В языке C\C++ предусмотрен форматный и бесформатный ввод данных

Бесформатный ввод (вывод) данных реализуется для любых типов данных и обеспечивается так называемыми операциями ввода (вывода) в поток. Например:

Операции бесформатного ввод/вывода данных относятся к языку С++

Строка программы cout > i; через поток cin переправляет данное с клавиатуры в переменную.

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

Ниже приводится пример, в котором исходный код, написанный на языке Pascal, при препроцессорной обработке заменяется на Си-исходник:


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

Переменные одного типа могут быть явно преобразованы к другому типу посредством операции приведения типов. Пример:


В этом примере величины i,l,d будут явно преобразовываться к указанным в круглых скобках типам.

Ниже приводится пример программы из 2-х функций.

Точка входа в программу – функция main. Из нее вызывается функция power. Функция определена с 2-я входными параметрами t и n. При определении функции эти параметры называются формальными. При вызове функции она получает фактические параметры a и n. Значение, вычисляемое функцией power, передается в main с помощью оператора return(p).

Функция power должна быть определена или объявлена до ее вызова в main. Что такое объявление функции? До сих пор мы сталкивались только с объявлением переменных. Объявление функции имеет вид:

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

Контрольные задания. Прочитайте программу. Запустите программу из проекта консольного приложения. Поменяйте местами определения функций power и main и выполните все необходимое для запуска программы.

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

Почему неверное решение? Вызванная функция копирует значения фактических параметров в локальные переменные, но обратно обновленные значения не возвращает.

Контрольное задание. Запустите программу. Прочитайте программный код. Модифицируйте программу, чтобы значение переменной a менялось на значение переменной b при вызове функции change(a, b).

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


В соответствии со стандартом ANSI С ключевое слово void применяется для явного указания на отсутствие аргументов функции. Указывать слово void не обязательно, хотя это широко используется.

Ниже рассмотрены специфические операции языка Си.

сокращенная форма оператора if — then — else, переменной max присваивается максимальное значение переменных d и b.

Присваивание x*=y+1 фактически означает x=x*(y+1), а не x=x*y+1.

Если считать, что значение n равно 5, то переменная m в выражении m=++n, будет иметь значение 6, а в выражение m=n++ переменная m равна 5, в том и этом случае переменная n будет равняться 6. Первый пример в точности соответствует следующей последовательности операторов n=n+1; m=n; а второй последовательности m=n; n=n+1. В первом примере на результате сказывается приоритетность операций, операция = приоритетнее операции ++.

& — поразрядное И
>> — сдвиг вправо
| — поразрядное ИЛИ
10 ), восьмеричное ( 012 ) или шестнадцатеричное число ( 0Xa или 0xA ). Константа без суффикса u или U считается знаковой.

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

Операция – (минус) более приоритетная операции & (побитовое И).
операции & (побитовое И) или может это операция адресации? (по контексту)
Если считать, что значение n равно 5, то переменная m в выражении m=++n будет иметь значение 6, а в выражение m=n++ переменная m равна 5

Массив – это совокупность данных одного типа. В случае многомерных массивов показывают столько пар скобок, какова размерность массива, например int a[2][5];

Обращение к некоторому элементу массива a[1][3], a[0][k+2]. Индексы массива в Си всегда начинаются с 0, а не с 1,

Двумерный массив можно инициировать так: int a [2][5] = ,>;

В языке Си отсутствует возможность динамически выделять память под массивы традиционным способом, однако для массива типа char делается исключение:

Контрольное задание. Запустите программу. Прочитайте программный код.

До сих пор все было относительно просто. Сложности понимания программ на языке C обычно начинаются с указателей. Рассмотрим специфику указателей на простейших примерах.


Указатель – это переменная, значением которой является адрес другой переменной.

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

Обратите внимание. Звездочка (*) около указателя есть в двух случаях — при декларации и раскрытии значения по указателю. Если указателю присваивается адрес, она отсутствует

Контрольный вопрос. Какое значение переменной y после выполнения кода?

При объявлении указателя операционная система выделяет память (4-е байта для 32 разрядной системы) только лишь для хранения самого указателя, а не под то, на что он будет указывать. Тогда зачем в декларации указателя описывать тип объекта?

Ответ. При объявлении типа указателя с ним можно выполнять операции сложения и вычитания, поскольку тип указателя определяет количество байт, на которое изменяется значение указателя. Например, при выполнении операции ++ (инкремент) значение указателя изменяется не на 1 (единицу), а на количество байт, отводимых под переменную указанного типа:

Контрольное задание. Создайте программу, которая обеспечивает форматный вывод адресов указателей до операции ++ и после нее.

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

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

Однако, если в качестве параметра передать указатель на некоторую переменную, то можно изменить значение этой переменной. Ранее мы могли возвращать результат работы функции только через return.

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


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

Контрольное задание. Создайте программу на основе аналогичного примера, чтобы значение переменных a и b обменивались при вызове функции change (&a,&b).

В C/C++ можно создавать указатели на другие указатели, которые, в свою очередь, содержат адреса реальных переменных

Между указателями и массивами существует тесная связь. Например, когда объявляется массив в виде int array[25], то этим определяется не только выделение памяти для двадцати пяти элементов массива, но и значение адреса первого по счету (нулевого) элемента массива, которое хранится в переменной с именем array.

Последний рядок можно записать в эквивалентной форме ptr = &array[0]. Получается, что определяя массив, мы автоматически получаем указатель. Это не совсем так, поскольку значение имени массива array нельзя изменить (имя массива-указателя это константа), а значения указателя ptr (это переменная) можно:

Объявление двумерного массива arr[4][3] порождает в программе три разных объекта: указатель с идентификатором arr, безымянный массив из четырех указателей и безымянный массив из двенадцати чисел типа.

Здесь уточним. Массив и четырех указателей есть виртуальным. Реальный только массив из 12 чисел, которые последовательно расположены в памяти — в ряду слева направо, по рядам сверху вниз. Виртуальный массив служит лишь для описания последовательности доступа к реальным элементам массива – от указателей на ряды к элементам ряда.

Для доступа к элементам массива может быть использовано индексное выражение в форме arr[1][2] или эквивалентные ей адресные выражения (*(arr+1))[2] и *(*(arr+1)+2).

Контрольное задание. Прочитайте код *(*(arr+1)+2), докажите, что он эквивалентный arr[1][2].

Рассмотрим теперь указатели на функции. Синтаксически имя функции является адресом начала тела функции. Точно, как и имя массива есть адресом первого элемента массива. Это значит, что функция может быть вызвана и через указатель на функцию. Пример:

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

Объявляется указатель fun1 на функцию, которая содержит 2 параметра типа int и возвращает значение типа double

Вызов функции происходит через знак раскрытия значения по указателю (*) .

Указатель на функцию может быть передан в качестве параметра функции. Ниже приведен пример, в котором один из параметров функции proiz есть указатель на функцию.

Функция proiz вычисляет производную от функции cos(x) опосредовано через функцию fun.

Для вычисления производной от какой-либо другой функции можно изменить тело функции fun или использовать при вызове функции proiz имя другой функции. В частности, для вычисления производной от функции cos(x) можно вызвать функцию proiz в форме

Контрольное задания. Прочитайте программный код. Запустите программу для вычисления производной от функции sin(x) в форме z=proiz(x,dx,sin); .

В языке Си отсутствует возможность динамически управлять памятью под массивы через индексное выражение в форме arr[] []. Такая возможность реализуется через указатели, функции malloc, calloc и free.

Пример программы 1:

Пример программы 2:


Функции malloc и calloc возвращают указатель на динамически запрашиваемую ими область памяти. Функция free (p) освобождает область памяти, на которую ссылается указатель. Указатель, возвращаемый функциями malloc и calloc, имеет тип void. К нему должна быть применена операция явного приведения к соответствующему типу.

Контрольное задание. Прочитайте программный код. Запустите программу 2.

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

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

Объявление:

В первом примере объявляется функция, поименованная add, которая требует два аргумента типа int и возвращает величину типа int.

Во втором примере объявляется функция, поименованная calc, которая возвращает величину типа double. Список типов аргументов не задан.

В третьем примере объявляется функция, поименованная strfind, которая возвращает указатель на величину типа char. Функция требует, по крайней мере, один аргумент указатель на величину типа char. Список типов аргументов заканчивается запятой с многоточием, обозначающим, что функция может потребовать большее число аргументов.

В четвертом примере объявляется функция с типом возврата void (нет возвращаемой величины). Список типов аргументов также void, означающий отсутствие аргументов для этой функции.

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

  • long *var(long,long); – функция, возвращающая указатель на величину типа long. В этом примере модификатор функции имеет более высокий приоритет, чем модификатор указателя, так что переменная var объявляется функцией, возвращающей указатель на величину типа long. Функция объявлена с двумя аргументами типа long.
  • long (*var) (long,long); – указатель на функцию, возвращающую величину типа long. Этот пример похож на второй. Скобки задают более высокий приоритет модификатору указателя, и поэтому переменная var объявляется как указатель на функцию с двумя аргументами типа long и возвращающую величину типа long.

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