Форум программистов, компьютерный форум, киберфорум
Наши страницы
CoderHuligan
Войти
Регистрация
Восстановить пароль
Рейтинг: 2.80. Голосов: 5.

Уроки программинга. Урок 4. Hello World! А как же без него родного!

Запись от CoderHuligan размещена 28.05.2019 в 19:46
Обновил(-а) CoderHuligan 28.05.2019 в 19:56

К настоящему времени достаточно хорошо оформились некоторые традиции, в частности при изучении языков программирования. Одним из таких традиционных средств считается первая простая программка, которая выводит строку "Hello World!", что в переводе на русский будет - "Привет мир!". Не будем нарушать этой традиции и напишем этот первый пример, который позволит нам познакомиться с некоторыми основополагающими концепциями языка Си.

C
1
2
3
4
5
6
7
#include <stdio.h>
 
int main(void)
{
    printf("Hello World\n");
    return (0);
}
Программы на Си состоят из функций, переменных и операций над ними. Переменная это именованная ячейка или группа ячеек памяти, которая хранит в себе некое значение определённого типа. Доступ к содержимому конкретной ячейки осуществляется в языке Си посредством имени этой переменной (или указателя). Если значение переменной невозможно изменить по ходу выполнения программы, то такая переменная называется константой. Об областях их определения позже.
Функция это некоторый блок кода, на который можно переходить, затем выполнять данный блок кода, а затем возвращаться в ту точку откуда произошёл переход (вызов) на эту функцию (блок кода), после чего выполнение программы продолжится далее. Причем делать это можно многократно. Однако здесь есть определённые ограничения. Если из данной конкретной функции вызывается эта же самая функция(а такое вполне возможно, и называется подобное рекурсией), то количество вызовов данной функции ограничено глубиной системного стека. Вот почему с рекурсивными алгоритмами надо всегда быть начеку и учитывать глубину стека, ведь если произойдёт исчерпание стека, тогда и ваша программа вылетит с ошибкой.
В функции можно передавать так называемые параметры. Параметров может быть неограниченное количество (правда чисто технически их число всё же ограничено глубиной стека). Функции могут иметь и переменное количество параметров (неизвестное их количество на момент вызова), о чём позже. Фактические параметры, которые известны на момент вызова функции называются аргументами.
Функция может возвратить только одно значение (технически оставить его на стеке или в регистре процессора, что зависит от реализации, но обычно на стеке). Однако при помощи передаваемых в функцию адресов внешних переменных, можно изменять внутри функции их значения. Однако чисто семантически у функции всего один выход. Изменять внешние переменные всегда опасно, так как функция становится несамостоятельной сущностью (не вещью "в себе"), что затрудняет сопровождение программ.
Подробно тему о функциях мы рассмотрим в другом уроке.
Операции это встроенные в ядро языка элементарные действия-команды над переменными. Например: + это операция сложения двух операндов(переменных) и т.д.
Программа на Си всегда имеет одну единственную точку входа - функцию main, что мы и наблюдаем в первом примере. Компилятор должен быть осведомлён с чего начинается ваша программа (с какой точки начать её трансляцию). Согласились, что она будет начинаться с определённой начальной функции. Преимущество этого в том, что в данную начальную функцию можно передавать параметры из-вне вашей программы, возможно даже из совсем другой программы. К тому же, данная функция может возвратить какое-то значение во "внешнее пространство", как результат работы программы. Это пошло от ОС Юникс, в которой были (и есть) так называемые "пайпы" - каналы связи одной программы с другой.

Давайте подробнее рассмотрим нашу первую программу. Первая строчка:

C
1
#include <stdio.h>
это директива (приказ) препроцессору языка Си. Препроцессор это часть компилятора, - особая программа, которая позволяет изменить режим компиляции путём особых директив (приказов), которые начинаются с символа # (шарп, или решетка), за которым идёт имя директивы. Препроцессинг осуществляется до самой компиляции программы. Имя директивы и этот знак могут отделятся друг от друга любым количеством пробелов и табуляций, но не знаком перевода строки. Принято печатать их слитно. Include в переводе "включить". В данном случае директива предписывает препроцессору заменить (включить) данную директиву на текст того файла имя которого указано в угловых скобках. Угловые скобки означают, что препроцессор будет искать файлы в системных директориях компилятора. Если имя файла указано в двойных кавычках, то препроцессор сначала будет искать в текущем каталоге пользователя, а затем, если не найдёт его здесь, уже в системных каталогах. То есть происходит просто замена данной строки директивы на текст из включаемого файла и всё, всё просто. Файл с расширением .h, является заголовочным файлом, в котором описаны объявления функций, переменных и т. д. Другая часть компилятора, которая называется компоновщиком, читает эти объявления функций и включает их тела в тело основной программы, но только те функции, которые встречаются в вашем коде. Иначе бы исполняемые файлы разбухли бы донельзя. Конкретные описания функций лежат обычно в файлах с расширением .c. Их можно тоже точно также подключать. Но всё же правильней принято подключать только их объявления (хэдер-файлы). В принципе так можно подключить файлы с любым расширением, только надо помнить о том, что компилятор может их не понять..
С другими директивами препроцессора будем знакомиться по ходу изучения примеров. Препроцессор Си это очень мощная штука, как бы язык в языке. Он позволяет вести раздельную компиляцию, например для разных процессоров, операционных систем и пр.
После того, как препроцессор отработал (не нашёл более ни одной директивы), то вступает в действие транслятор.

Далее идёт главная функция main, в которой происходит вызов функции из библиотеки стандартных функций, объявления которых мы и подключили препроцессорной директивой в начале программы. Если бы мы не сделали этого, то компилятор бы крепко выругался на вас: "я встретил функцию printf(), но мне она не знакома!))". Так что если вам нужно использовать стандартные библиотечные функции (как в данном случае мы подключили библиотеку ввода-вывода), то всегда подключайте их в самом начале вашего файла с кодом. Подключать их где-либо ещё сильно не рекомендуется (вспомним о том, что исходный текст заголовочных файлов включается непосредственно в то место, где была директива), из-за возможных ошибок дальнейшей обработки данного файла.
Параметром функции main() идёт void, что говорит компилятору об отсутствии параметров. Сейчас рекомендуется явно указывать это слово. Раньше если в функции не было параметров, можно было писать main();, сейчас это считается устаревшим и так делать не рекомендуется.
Функция printf() это стандартная функция вывода, но не просто вывода(просто выводом занимается функция puts()), а выводом форматированным (о чём говорит буква f в конце её имени). Данная функция может принимать произвольное количество параметров. Первым параметром идёт всегда строка форматирования, в которой есть особые обозначения, которые начинаются со знака процента, например "%d" означает, что %d надо заменить на значение целочисленной переменной, которая должна быть вторым параметром функции printf(). В данном случае никаких подстановок не производится, поэтому параметр может быть всего один.
Здесь функция printf принимает один параметр - строку "Hello World!\n" и выводит её в консольное окно вашей операционной системы. Управляющая последовательность \n (они всегда начинаются с обратной косой черты) это перевод строки (следующая строка начнётся с новой строки). Есть и другие последовательности:
'\t' - знак горизонтальной табуляции;
'\r' - возврат курсора к началу строки;
'\\' - обратная косая черта;
'\'' - одинарная кавычка;
'"' - двойная кавычка;
'\0' - нулевой символ (не путать с цифрой 0!);
'\a' - звуковой сигнал;
'\b' - возврат на один символ;
'\f' - переход на другую страницу;
'\v' - вертикальный табулятор;
'\?' - знак вопроса;
Восьмеричные числа обозначаются через '\ddd' вместо d должна быть одна из цифр от 0 до 9 восьмеричного числа. Шестнадцатеричные символы так: '\xdd', вместо d идут цифры, которых может быть больше или меньше чем две. Все эти управляющие последовательности в коде должны заключаться в одинарные кавычки - '.
Насчёт комментариев в исходном коде. Есть две разновидности. Одна начинается с двух обратных слешей: \\. В этом случае компилятор пропустит (не примет во внимание) всё, что начинается с этих символов и до конца строки. При втором способе всё, что заключено между символами \* и *\ будет проигнорировано компилятором. Вложенные комментарии такого вида не допускаются, однако внутри них могут находиться комментарии первого вида.
В конце функции main() мы видим:
C
1
return 0;
это значит, что программа завершилась без ошибок (возвратит ноль). В принципе возвратить можно любое нужное вам значение.
Знак точки с запятой завершает операцию. Он позволяет отделить одну операцию от другой и избежать путаницы.
Размещено в Без категории
Просмотров 261 Комментарии 15
Всего комментариев 15
Комментарии
  1. Старый комментарий
    Аватар для Croessmah
    Цитата:
    Если значение переменной невозможно изменить по ходу выполнения программы, то такая переменная называется константой.
    Где Вы видели такие переменные?
    Константой в C называется "непосредственное значение" или значение enum'а.
    12 - целочисленная константа
    'a' - символьная константа
    и т.д.
    C
    1
    
    const int x = 10;//x - НЕ константа
    Цитата:
    Раньше если в функции не было параметров, можно было писать main();, сейчас это считается устаревшим и так делать не рекомендуется.
    Откуда это? Стандарт C ясно говорит, что main должна быть либо
    int main(void) { /* ... */ }, либо
    int main(int argc, char *argv[]) { /* ... */ }.
    Все остальные варианты являются зависимыми от реализации, т.е. непереносимыми.
    По поводу void'а в параметрах читать здесь: http://www.cyberforum.ru/c-beginners/thread2317239.html
    Цитата:
    Файл с расширением .h, является заголовочным файлом, в котором описаны объявления функций, переменных и т. д. Другая часть компилятора, которая называется компоновщиком, читает эти объявления функций и включает их тела в тело основной программы, но только те функции, которые встречаются в вашем коде.
    Компоновщику не нужны эти .h файлы и объявления.
    Заголовочные файлы (точнее объявления в них), нужны лишь компилятору,
    чтобы он не спотыкался во время компиляции о неизвестные символы.
    К слову, раньше в C разрешалось использовать функции без их объявления,
    т.е. можно было написать
    C
    1
    2
    3
    4
    5
    
    int main(void) 
    {
        printf("Hi\n");//Раньше было можно использовать без объявления
        return 0;
    }
    а затем слинковать с библиотекой в которой есть функция printf.
    Цитата:
    "%d" означает, что %d надо заменить на значение целочисленной переменной
    Не просто целочисленной, а переменной именно типа int.
    Запись от Croessmah размещена 28.05.2019 в 20:23 Croessmah на форуме
    Обновил(-а) Croessmah 28.05.2019 в 20:26
  2. Старый комментарий
    Аватар для liv
    Как все запущено... Какая каша в голове... Можно только догадываться, что нас ждет впереди...
    Запись от liv размещена 29.05.2019 в 10:30 liv вне форума
  3. Старый комментарий
    Аватар для CoderHuligan
    Цитата:
    Сообщение от Croessmah Просмотреть комментарий
    Где Вы видели такие переменные?
    Например определенные через define.

    Цитата:
    Сообщение от Croessmah Просмотреть комментарий
    Откуда это?
    Из книги КР. Там используется устаревшая нотация.

    Цитата:
    Сообщение от Croessmah Просмотреть комментарий
    Компоновщику не нужны эти .h файлы и объявления.
    А где я писал что нужны?

    Цитата:
    Сообщение от Croessmah Просмотреть комментарий
    Заголовочные файлы (точнее объявления в них), нужны лишь компилятору,
    чтобы он не спотыкался во время компиляции о неизвестные символы.
    Конечно. Он использует обьектный файл. Но ему же всё равно придётся искать эти библиотеки. Я лишь слишком схематически описал происходящее. До обьектных файлов ещё дойдём.

    Цитата:
    Сообщение от Croessmah Просмотреть комментарий
    Не просто целочисленной, а переменной именно типа int.
    А как же char, который является неполным целочисленным типом?
    Запись от CoderHuligan размещена 29.05.2019 в 14:24 CoderHuligan на форуме
  4. Старый комментарий
    Аватар для CoderHuligan
    Цитата:
    Сообщение от liv Просмотреть комментарий
    Как все запущено... Какая каша в голове... Можно только догадываться, что нас ждет впереди...
    А по конкретнее? Давайте не будем тупо троллить тему. Откровенный троллизм буду удалять, такая возможность у меня есть. Где, что я такого написал неверного?
    Запись от CoderHuligan размещена 29.05.2019 в 14:25 CoderHuligan на форуме
  5. Старый комментарий
    Аватар для Croessmah
    Цитата:
    Например определенные через define.
    Это вообще макросы.
    Цитата:
    А как же char, который является неполным целочисленным типом?
    Что такое неполный целочисленный тип?
    Как определяется полнота целочисленного типа?

    При передаче в функцию с эллипсисом char и short
    будут продвинуты в int, так что работа будет именно с int.
    float, например, будет продвинут в double.
    Запись от Croessmah размещена 29.05.2019 в 14:29 Croessmah на форуме
  6. Старый комментарий
    Аватар для liv
    Цитата:
    А где я писал что нужны?
    Цитата:
    Файл с расширением .h, является заголовочным файлом, в котором описаны объявления функций, переменных и т. д. Другая часть компилятора, которая называется компоновщиком, читает эти объявления функций и включает их тела в тело основной программы
    Цитата:
    Например определенные через define.
    define служит для определения констант и для определения макросов.
    В любом случае - это директива для препроцессора и чаще всего используется для замены одного текста на другой, а не для задания переменных. К моменту компиляции никаких define нет и в помине...
    Цитата:
    А как же char, который является неполным целочисленным типом?
    И что с того? Требуется именно int, поэтому, если возможно, расширяется до int и передается int. А как насчет _int64? Это ведь тоже целое...
    Да и с int main(void) Вы попали пальцем в небо... В каком году Вы живете? Наверное, когда язык Си только писался...
    Запись от liv размещена 29.05.2019 в 14:51 liv вне форума
  7. Старый комментарий
    Аватар для bedvit
    Цитата:
    Сообщение от Croessmah Просмотреть комментарий
    Что такое неполный целочисленный тип?
    Как определяется полнота целочисленного типа?
    Возможно уважаемый CoderHuligan имел ввиду размер машинного слова.

    Цитата:
    Сообщение от Croessmah Просмотреть комментарий
    При передаче в функцию с эллипсисом char и short
    будут продвинуты в int, так что работа будет именно с int.
    float, например, будет продвинут в double.
    Уважаемый Croessmah, поясните почему именно int, а не int64_t (long long)?
    На х64 системах, размер машинного слова ведь 8 байт. А int это 4 байта (2 байта на 16- и 8-битных платформах).
    Запись от bedvit размещена 29.05.2019 в 15:17 bedvit на форуме
  8. Старый комментарий
    Аватар для _lunar_
    почему все забывают в Hello World, да вообще в любой консольной программе, о такой штуке как ожидание действий пользователя?

    где getchar() после printf() ?
    Запись от _lunar_ размещена 29.05.2019 в 17:06 _lunar_ вне форума
  9. Старый комментарий
    Аватар для Curry
    Цитата:
    В принципе возвратить можно любое нужное вам значение.
    Не любое, а типа int. Хотя С съест любую ерунду типа return "qwery";. Писать на С, это всё равно что ходить возле ременной передачи не закрытой кожухом с длинными волосами и с развевающимися полами одежды. И говорить при этом "у нас всё под контролем. Мы ошибок не допускаем, нам техника безопасности ни к чему."
    Запись от Curry размещена 29.05.2019 в 17:29 Curry на форуме
  10. Старый комментарий
    Операции это встроенные в ядро языка элементарные действия-команды над переменными. Например: + это операция сложения двух операндов (переменных) и т.д.
    .........
    Это не совсем верно.
    Знаком + обозначается также УНАРНАЯ операция над одним операндом. Например x = +7
    Хотя особого значения эта операция не имеет в отличие от УНАРНОГО МИНУСА
    Операция "-" есть также унарный минус, предназначена для изменения знака числа (переменной)
    Унарный минус имеет высокий приоритет. Выше, чем приоритет умножения и деления
    пример x = -5 * -7
    Запись от нтч размещена 29.05.2019 в 18:12 нтч вне форума
  11. Старый комментарий
    Аватар для CoderHuligan
    Цитата:
    Сообщение от Croessmah Просмотреть комментарий
    Это вообще макросы.
    Макросы это непосредственно дефайны, результат их подстановки есть чистые именованные константы, о чём писано в КР.
    Цитата:
    Сообщение от Croessmah Просмотреть комментарий
    Что такое неполный целочисленный тип?
    "By definition, chars are just small integers, so char variables and constants are identical to ints in arithmetic expressions." - из КР.
    Запись от CoderHuligan размещена 29.05.2019 в 18:39 CoderHuligan на форуме
  12. Старый комментарий
    Аватар для CoderHuligan
    Цитата:
    Сообщение от _lunar_ Просмотреть комментарий
    где getchar() после printf() ?
    У меня в Pelles C он не нужен, так как консоль не закрывается автоматически. А в других средах это действительно необходимо. Но это чистый пример, а не конкретно под какую-то среду разработки.
    Запись от CoderHuligan размещена 29.05.2019 в 18:42 CoderHuligan на форуме
  13. Старый комментарий
    Аватар для Avazart
    Цитата:
    Давайте не будем тупо троллить тему. Откровенный троллизм буду удалять, такая возможность у меня есть. Где, что я такого написал неверного?
    Так сама тема троляцка.
    Запись от Avazart размещена 29.05.2019 в 21:19 Avazart на форуме
  14. Старый комментарий
    Аватар для Avazart
    Цитата:
    почему все забывают в Hello World, да вообще в любой консольной программе, о такой штуке как ожидание действий пользователя?

    где getchar() после printf() ?
    По тому что это глупость. Нормальные должны завершаться, а не висеть в процессах.
    getchar() и прочие нужны для отладки и то зависит от среды разработки.
    Запись от Avazart размещена 29.05.2019 в 21:23 Avazart на форуме
  15. Старый комментарий
    Аватар для Croessmah
    Цитата:
    Сообщение от CoderHuligan Просмотреть комментарий
    Макросы это непосредственно дефайны, результат их подстановки есть чистые именованные константы, о чём писано в КР.
    А кроме этого ты что-нибудь читал?
    Цитата:
    результат их подстановки есть чистые именованные константы
    Ты же написал, что это переменные, а теперь пишешь, что это константы.
    Если уж на то пошло, то идентификатор после #define - это просто macro name, которые даже в единицу трансляции не попадают.
    Хоть имя макроса и является идентификатором, оно не является ordinary и вообще не рассматриваются в большей части стандарта языка, и по-сути, с языком мало связаны, т.к. удаляются до семантической части трансляции.
    Цитата:
    Сообщение от bedvit Просмотреть комментарий
    Уважаемый Croessmah, поясните почему именно int, а не int64_t (long long)?
    Таковы требования спецификации языка.
    Цитата:
    If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.
    А тип int представляет естественный размер в целевой архитектуре
    Цитата:
    A ‘‘plain’’ int object has the natural size suggested by the architecture of the execution environment
    Запись от Croessmah размещена 29.05.2019 в 22:00 Croessmah на форуме
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru