Все записи автора KaDeaT

Без рубрики

Программирование для начинающих. Запуск проекта!

Добрый день, уважаемый читатель!

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

Перед новичком в программировании встает сразу куча вопросов:
  • Как стать программистом?Как научиться программированию? 
  • С какого языка начать обучение программированию
  • По какому учебнику/книге учиться?Какие книги нужны? 
  • Что нужно чтобы начать обучение программированию? 

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

И так начнем по порядку!

1) Как стать программистом? Как научиться программированию? С чего начать?

Чтобы стать программистом и научиться программировать надо... учиться! Учиться программировать! И естественно программировать, практиковаться. Программирование - очень интересное и увлекательное занятие, главное уловить его дух. Посмотрите следующее видео.


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

2)С какого языка начать обучение программированию?

Если вы уже искали по этому вопросу информацию в поисковиках, то наверно видели, что выбор идет между двумя языками C (Си) и Pascal(Паскаль). Между приверженцами этих двух языковых направлений постоянно возникают споры, называемые в интернете "холиварами". Я предлагаю вам онлайн-курс программирования на языке C(Си). На данном этапе обучения, нам в принципе не важно с какого языка начать. Это мое личное мнение основанное на том, что язык это всего лишь инструмент для описания алгоритма. Я считаю что главное в программировании, это научиться строить алгоритмы решения задачи, а языки это дело наживное!Так что переходим к следующему вопросу!

3)По какому учебнику/книге заниматься?

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

4) Что нужно что бы начать обучение программированию?

Итак, чтобы заниматься программированием по моему курсу, ну и вообще учиться программированию, нам понадобится:
  • Учебник по конкретному языку программирования.(в данном случае это мой блог) 
  • Справочник по данному языку программирования. 
  • Среда программирования (о выборе среды программирования). 
  • Ну и конечно же, огонек в глазах и стимул. 
Перед началом обучения ознакомьтесь с программой онлайн-курса обучения программированию на языке Си.К каждому занятию есть небольшое практическое задание. За время работы  блога, был собран архив образцовых решений.

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

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

Всем спасибо, до встречи на страницах блога! =)))

Перейти к первому уроку.

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

Программирование для начинающих. Запуск проекта!

Добрый день, уважаемый читатель!

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

Перед новичком в программировании встает сразу куча вопросов:
  • Как стать программистом?Как научиться программированию? 
  • С какого языка начать обучение программированию
  • По какому учебнику/книге учиться?Какие книги нужны? 
  • Что нужно чтобы начать обучение программированию? 

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

И так начнем по порядку!

1) Как стать программистом? Как научиться программированию? С чего начать?

Чтобы стать программистом и научиться программировать надо... учиться! Учиться программировать! И естественно программировать, практиковаться. Программирование - очень интересное и увлекательное занятие, главное уловить его дух. Посмотрите следующее видео.


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

2)С какого языка начать обучение программированию?

Если вы уже искали по этому вопросу информацию в поисковиках, то наверно видели, что выбор идет между двумя языками C (Си) и Pascal(Паскаль). Между приверженцами этих двух языковых направлений постоянно возникают споры, называемые в интернете "холиварами". Я предлагаю вам онлайн-курс программирования на языке C(Си). На данном этапе обучения, нам в принципе не важно с какого языка начать. Это мое личное мнение основанное на том, что язык это всего лишь инструмент для описания алгоритма. Я считаю что главное в программировании, это научиться строить алгоритмы решения задачи, а языки это дело наживное!Так что переходим к следующему вопросу!

3)По какому учебнику/книге заниматься?

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

4) Что нужно что бы начать обучение программированию?

Итак, чтобы заниматься программированием по моему курсу, ну и вообще учиться программированию, нам понадобится:
  • Учебник по конкретному языку программирования.(в данном случае это мой блог) 
  • Справочник по данному языку программирования. 
  • Среда программирования (о выборе среды программирования). 
  • Ну и конечно же, огонек в глазах и стимул. 
Перед началом обучения ознакомьтесь с программой онлайн-курса обучения программированию на языке Си.К каждому занятию есть небольшое практическое задание. За время работы  блога, был собран архив образцовых решений.

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

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

Всем спасибо, до встречи на страницах блога! =)))

Перейти к первому уроку.

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

Структуры в языке Си.

Видео урок.

Прежде чем говорить о структурах, вспомним массивы. Как вы, наверное, помните, массивы предназначены для хранения однотипных данных. Другими словами каждый элемент массива представляет собой значение определенного типа: целое число, символ, строка. Но зачастую, в программах, требуется хранить в одном месте данные разных типов. В качестве примера, в этом уроке будем рассматривать программу каталог книг. Про каждую книгу нам известно: название, автор, год издания, количество страниц, стоимость.
Типы переменных, используемые для хранения подобных данных очевидны:
char[] – автор, название.
int – год издания, количество страниц.
float – стоимость.

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

int book_date[100];        // дата издания
int book_pages[100];       // количество страниц
char book_author[100][50]; // автор
char book_title[100][100]; // название книги
float book_price[100];     //стоимость

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

printf("%s-%s %d page", book_author[3], book_title[3], book_pages[3]);

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

Что такое структура.

Задумаемся, что такое структура в обычном понимании этого слова. Структура – это строение или внутренне устройство какого-либо объекта.
Структура в языке Си – это тип данных, создаваемый программистом, предназначенный для объединения данных различных типов в единое целое.
Прежде чем использовать в своей программе структуру, необходимо её описать, т.е. описать её внутреннее устройство. Иногда это называю шаблоном структуры. Шаблон структуры описывается следующим образом.
На картинке слева, мы описали шаблон структуры с именем point. В любом шаблоне структуры можно выделить две основных части: заголовок (ключевое слово struct и имя структуры) и тело (поля структуры, записанные внутри составного оператора).
Точка с запятой в конце обязательна, не забывайте про неё.

Возвращаясь к нашему примеру, опишем структуру book с полями date, pages, author, title, price соответствующих типов.

struct book {
    int date;        // дата издания
    int pages;       // количество страниц
    char author[50]; // автор
    char title[100]; // название книги
    float price;     // стоимость
};

Попутно отметим, что в качестве полей структуры могут выступать любые встроенные типы данных и даже другие структуры. Подробнее об этом я расскажу в другом уроке. На имена полей накладываются те же ограничения, что и на обычные переменные. Внутри одной структуры не должно быть полей с одинаковыми именами. Имя поля не должно начинаться с цифры. Регистр учитывается.
После того, как мы описали внутреннее устройство структуры, можно считать, что мы создали новый тип данных, который устроен таким вот образом. Теперь этот тип данных можно использовать в нашей программе.
ПРИМЕЧАНИЕ:  Обычно структуры описываются сразу после подключения заголовочных файлов. Иногда, для удобства, описание структур выносят в отдельный заголовочный файл.

Как объявить структурную переменную (структуру).

Объявление структурной переменной происходит по обычным правилам.
 struct book kniga1;

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


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


Если кто-то имел дело с реляционными базами данных (MySQL, Oracle), то вам эта такая интерпретация будет очень знакома.

Как инициализировать структуру.

Хорошо, переменную мы объявили. Самое время научиться сохранять в неё данные, иначе, зачем она нам вообще нужна. Мы можем присвоить значения сразу всем полям структуры при объявлении. Это очень похоже на то, как мы присваивали значения массиву при его объявлении.

struct book kniga1 = {1998, 230, "D. Ritchi","The C programming language.", 540.2};


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

struct book kniga1 = {1998, 230, "D. Ritchi"};

Как обращаться к полям структуры.

Для обращения к отдельным полям структуры используется оператор доступа ".". Да-да, обычная точка.
Примеры:

kniga1.pages = 250; // записываем в поле pages переменной kniga1
                    // значение 250.
printf("%s-%s %d page", kniga1.author, kniga1.title, kniga1.pages);

Задание: Проверить, что хранится в полях структуры до того, как им присвоено значение.
Сейчас, в одной переменной типа book храниться вся информация об одной книге. Но так как в каталоге вряд ли будет всего одна книга, нам потребуется много переменных одного и того же типа book. А значит что? Правильно, нужно создать массив таких переменных, то есть массив структур. Делается это аналогично, как если бы мы создавали массив переменных любого стандартного типа.

struct book kniga[100];

Каждый элемент этого массива это переменная типа book. Т.е. у каждого элемента есть свои поля date, pages, author, title, price.  Тут-то и удобно вспомнить о второй интерпретации структуры. В ней массив структур будет выглядеть как таблица.


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

printf("%s-%s %d page", kniga[3].author, kniga[3].title, kniga[3].pages);

Обращаясь к kniga[3].author мы обращаемся к четвертой строке нашей таблицы и столбику с именем author. Удобная интерпретация, не правда ли?
На данном этапе мы научились основам работы со структурами. Точнее мы переписали с использованием структур тот же код, который использовал несколько массивов. Кажется, что особой разницы нет.  Да, на первый взгляд это действительно так. Но дьявол, как обычно, кроется в мелочах.
Например,  очевидно, что в нашей программе нам часто придется выводить данные о книге на экран. Разумным решением будет написать для этого отдельную функцию.
Если бы мы пользуемся несколькими массивами, то  эта функция выглядела бы примерно так:

void print_book ( int date, int pages, char *author, 
                  char *title, float price){
      printf("%s-%s %d page.\nDate: %d \nPRICE: %f rub.\n",
             author, title, pages,date, price);
}

А её вызов выглядел как-то вот так:

print_book (book_date[3], book_pages[3], book_author[3],
            book_title[3], book_price[3]);

Не очень-то и компактно получилось, как вы можете заметить. Легче  было бы писать каждый раз отдельный printf();.
Совсем другое дело, если мы используем структуры. Так как структура представляет собой один целый объект (большую коробку с отсеками), то и передавать в функцию нужно только его. И тогда нашу функцию можно было бы записать следующим образом:

void sprint_book (book temp){
      printf("%s-%s %d page.\nDate: %d \nPRICE: %f rub.",
             temp.author,temp.title, temp.pages, 
             temp.date, temp.price);
}

И вызов, выглядел бы приятнее:

sprint_book (kniga[3]);

Вот это я понимаю, быстро и удобно, и не нужно  каждый раз писать пять параметров. А представьте теперь, что полей у структуры  бы их было не 5, а допустим 10? Вот-вот, и я о том же.
Стоит отметить, что передача структурных переменных в функцию, как и в случае обычных переменных осуществляется по значению. Т.е. внутри функции мы работаем не с самой структурной переменной, а с её копией. Чтобы этого избежать, как и в случае переменных стандартных типов используют указатель на структуру. Там есть небольшая особенность, но об этом я расскажу в другой раз.
Кроме того, мы можем присваивать  структурные переменные, если они относятся к одному и тому же шаблону. Зачастую это очень упрощает программирование.
Например, вполне реальная задача для каталога книг, упорядочить книги по количеству страниц.
Если бы мы использовали отдельные массивы, то сортировка выглядела бы примерно так.

for (int i = 99; i > 0; i--)
    for (int j = 0; j < i; j++)
       if (book_pages[j] > book_page[j+1]){
            //меняем местами значения во всех массивах
            int temp_date;
            int temp_pages;
            char temp_author[50];
            char temp_title[100];
            float temp_price;
  
            temp_date = book_date[i];
            book_date[i] = book_date[j];
            book_date[j] = temp_date;

            temp_pages = book_pages[i];
            book_pages[i] = book_pages[j];
            book_pages[j] = temp_pages;

            //и так далее для остальных трех массивов
       }

Совсем другой дело, если мы используем структуры.

for (int i = 99; i > 0; i--)
   for (int j = 0; j < i; j++)
      if (knigi[j].pages > knigi[j+1].pages){
          struct book temp;
          temp = knigi[j];        //присваивание структур
          knigi[j] = knigi[j+1];
          knigi[j+1] = temp;
      }

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

Практическое задание:

1. Добавить в структуру поле количество прочитанных страниц.
2. Напишите несколько дополнительных функций для описанной программы.
  • Чтение данных  в структуру из файла. В файле запись о каждой книге хранится в следующем формате:
Автор||Название||Год издания||Прочитано||Количество страниц||Стоимость

Примеры:

Khnut||Art of programming. T.1||1972||129||764||234.2
Ritchie||The C Programming Language. 2 ed.||1986||80||512||140.5
Cormen||Kniga pro algoritmy||1996||273||346||239

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

Версия урока для просмотра  offline
Исходные коды программ  

    Структуры в языке Си.

    Видео урок.

    Прежде чем говорить о структурах, вспомним массивы. Как вы, наверное, помните, массивы предназначены для хранения однотипных данных. Другими словами каждый элемент массива представляет собой значение определенного типа: целое число, символ, строка. Но зачастую, в программах, требуется хранить в одном месте данные разных типов. В качестве примера, в этом уроке будем рассматривать программу каталог книг. Про каждую книгу нам известно: название, автор, год издания, количество страниц, стоимость.
    Типы переменных, используемые для хранения подобных данных очевидны:
    char[] – автор, название.
    int – год издания, количество страниц.
    float – стоимость.

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

    int book_date[100];        // дата издания
    int book_pages[100];       // количество страниц
    char book_author[100][50]; // автор
    char book_title[100][100]; // название книги
    float book_price[100];     //стоимость

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

    printf("%s-%s %d page", book_author[3], book_title[3], book_pages[3]);

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

    Что такое структура.

    Задумаемся, что такое структура в обычном понимании этого слова. Структура – это строение или внутренне устройство какого-либо объекта.
    Структура в языке Си – это тип данных, создаваемый программистом, предназначенный для объединения данных различных типов в единое целое.
    Прежде чем использовать в своей программе структуру, необходимо её описать, т.е. описать её внутреннее устройство. Иногда это называю шаблоном структуры. Шаблон структуры описывается следующим образом.
    На картинке слева, мы описали шаблон структуры с именем point. В любом шаблоне структуры можно выделить две основных части: заголовок (ключевое слово struct и имя структуры) и тело (поля структуры, записанные внутри составного оператора).
    Точка с запятой в конце обязательна, не забывайте про неё.

    Возвращаясь к нашему примеру, опишем структуру book с полями date, pages, author, title, price соответствующих типов.

    struct book {
        int date;        // дата издания
        int pages;       // количество страниц
        char author[50]; // автор
        char title[100]; // название книги
        float price;     // стоимость
    };

    Попутно отметим, что в качестве полей структуры могут выступать любые встроенные типы данных и даже другие структуры. Подробнее об этом я расскажу в другом уроке. На имена полей накладываются те же ограничения, что и на обычные переменные. Внутри одной структуры не должно быть полей с одинаковыми именами. Имя поля не должно начинаться с цифры. Регистр учитывается.
    После того, как мы описали внутреннее устройство структуры, можно считать, что мы создали новый тип данных, который устроен таким вот образом. Теперь этот тип данных можно использовать в нашей программе.
    ПРИМЕЧАНИЕ:  Обычно структуры описываются сразу после подключения заголовочных файлов. Иногда, для удобства, описание структур выносят в отдельный заголовочный файл.

    Как объявить структурную переменную (структуру).

    Объявление структурной переменной происходит по обычным правилам.
     struct book kniga1;

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


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


    Если кто-то имел дело с реляционными базами данных (MySQL, Oracle), то вам эта такая интерпретация будет очень знакома.

    Как инициализировать структуру.

    Хорошо, переменную мы объявили. Самое время научиться сохранять в неё данные, иначе, зачем она нам вообще нужна. Мы можем присвоить значения сразу всем полям структуры при объявлении. Это очень похоже на то, как мы присваивали значения массиву при его объявлении.

    struct book kniga1 = {1998, 230, "D. Ritchi","The C programming language.", 540.2};


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

    struct book kniga1 = {1998, 230, "D. Ritchi"};

    Как обращаться к полям структуры.

    Для обращения к отдельным полям структуры используется оператор доступа ".". Да-да, обычная точка.
    Примеры:

    kniga1.pages = 250; // записываем в поле pages переменной kniga1
                        // значение 250.
    printf("%s-%s %d page", kniga1.author, kniga1.title, kniga1.pages);

    Задание: Проверить, что хранится в полях структуры до того, как им присвоено значение.
    Сейчас, в одной переменной типа book храниться вся информация об одной книге. Но так как в каталоге вряд ли будет всего одна книга, нам потребуется много переменных одного и того же типа book. А значит что? Правильно, нужно создать массив таких переменных, то есть массив структур. Делается это аналогично, как если бы мы создавали массив переменных любого стандартного типа.

    struct book kniga[100];

    Каждый элемент этого массива это переменная типа book. Т.е. у каждого элемента есть свои поля date, pages, author, title, price.  Тут-то и удобно вспомнить о второй интерпретации структуры. В ней массив структур будет выглядеть как таблица.


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

    printf("%s-%s %d page", kniga[3].author, kniga[3].title, kniga[3].pages);

    Обращаясь к kniga[3].author мы обращаемся к четвертой строке нашей таблицы и столбику с именем author. Удобная интерпретация, не правда ли?
    На данном этапе мы научились основам работы со структурами. Точнее мы переписали с использованием структур тот же код, который использовал несколько массивов. Кажется, что особой разницы нет.  Да, на первый взгляд это действительно так. Но дьявол, как обычно, кроется в мелочах.
    Например,  очевидно, что в нашей программе нам часто придется выводить данные о книге на экран. Разумным решением будет написать для этого отдельную функцию.
    Если бы мы пользуемся несколькими массивами, то  эта функция выглядела бы примерно так:

    void print_book ( int date, int pages, char *author, 
                      char *title, float price){
          printf("%s-%s %d page.\nDate: %d \nPRICE: %f rub.\n",
                 author, title, pages,date, price);
    }

    А её вызов выглядел как-то вот так:

    print_book (book_date[3], book_pages[3], book_author[3],
                book_title[3], book_price[3]);

    Не очень-то и компактно получилось, как вы можете заметить. Легче  было бы писать каждый раз отдельный printf();.
    Совсем другое дело, если мы используем структуры. Так как структура представляет собой один целый объект (большую коробку с отсеками), то и передавать в функцию нужно только его. И тогда нашу функцию можно было бы записать следующим образом:

    void sprint_book (book temp){
          printf("%s-%s %d page.\nDate: %d \nPRICE: %f rub.",
                 temp.author,temp.title, temp.pages, 
                 temp.date, temp.price);
    }

    И вызов, выглядел бы приятнее:

    sprint_book (kniga[3]);

    Вот это я понимаю, быстро и удобно, и не нужно  каждый раз писать пять параметров. А представьте теперь, что полей у структуры  бы их было не 5, а допустим 10? Вот-вот, и я о том же.
    Стоит отметить, что передача структурных переменных в функцию, как и в случае обычных переменных осуществляется по значению. Т.е. внутри функции мы работаем не с самой структурной переменной, а с её копией. Чтобы этого избежать, как и в случае переменных стандартных типов используют указатель на структуру. Там есть небольшая особенность, но об этом я расскажу в другой раз.
    Кроме того, мы можем присваивать  структурные переменные, если они относятся к одному и тому же шаблону. Зачастую это очень упрощает программирование.
    Например, вполне реальная задача для каталога книг, упорядочить книги по количеству страниц.
    Если бы мы использовали отдельные массивы, то сортировка выглядела бы примерно так.

    for (int i = 99; i > 0; i--)
        for (int j = 0; j < i; j++)
           if (book_pages[j] > book_page[j+1]){
                //меняем местами значения во всех массивах
                int temp_date;
                int temp_pages;
                char temp_author[50];
                char temp_title[100];
                float temp_price;
      
                temp_date = book_date[i];
                book_date[i] = book_date[j];
                book_date[j] = temp_date;

                temp_pages = book_pages[i];
                book_pages[i] = book_pages[j];
                book_pages[j] = temp_pages;

                //и так далее для остальных трех массивов
           }

    Совсем другой дело, если мы используем структуры.

    for (int i = 99; i > 0; i--)
       for (int j = 0; j < i; j++)
          if (knigi[j].pages > knigi[j+1].pages){
              struct book temp;
              temp = knigi[j];        //присваивание структур
              knigi[j] = knigi[j+1];
              knigi[j+1] = temp;
          }

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

    Практическое задание:

    1. Добавить в структуру поле количество прочитанных страниц.
    2. Напишите несколько дополнительных функций для описанной программы.
    • Чтение данных  в структуру из файла. В файле запись о каждой книге хранится в следующем формате:
    Автор||Название||Год издания||Прочитано||Количество страниц||Стоимость

    Примеры:

    Khnut||Art of programming. T.1||1972||129||764||234.2
    Ritchie||The C Programming Language. 2 ed.||1986||80||512||140.5
    Cormen||Kniga pro algoritmy||1996||273||346||239

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

    Версия урока для просмотра  offline
    Исходные коды программ  

      2014 год. Цифры и факты.

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

      За 2014 год на блог зашло 67.5 тысяч уникальных пользователей. Из них, около 8.3%, то есть приблизительно 5600 пользователей, успели разочароваться в блоге за первые 15 секунд знакомства с ним и сразу же закрыли его. Но есть и другие, которые не разочаровались и совершили в общей сложности 266 788 просмотров. Причем, учитывая что в общей сложности к блогу обращались 145 тысяч раз, получается, что каждый посетитель заходил на сайт в среднем 2 раза. Хотя, понимаю, что здесь среднее не очень уместно.

      Максимальное число посетителей за сутки - 432 человека. Такое случалось дважды: 20 октября и 22 апреля. Минимальное количество посетителей за сутки – 150 человек. Данная цифра зафиксирована 5 января, то есть в новогодние праздники. Если отбросить новогодние праздники и летние каникулы, то минимальная посещаемость 227 человек.

      Средняя посещаемость 294 человек в сутки.

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

      В среднем пользователи проводят на сайте чуть более четырех минут. Максимальное среднее время за сутки составляет 15 минут. Как это ни странно, а случилось это 28 июня. Пользователей было мало, но занимались, по-видимому, они серьезно.

      Средняя глубина просмотра сайта 1.8 страниц.

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

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

      На паблик в vk подписано 2360 человек.

      Кроме того, при последнем обновлении ТИЦ Яндексом, сайту присвоен ТИЦ 10.
      На этом по цифрам и фактам 2014 года всё.

      Посмотрим, что год грядущий нам готовит.

      2014 год. Цифры и факты.

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

      За 2014 год на блог зашло 67.5 тысяч уникальных пользователей. Из них, около 8.3%, то есть приблизительно 5600 пользователей, успели разочароваться в блоге за первые 15 секунд знакомства с ним и сразу же закрыли его. Но есть и другие, которые не разочаровались и совершили в общей сложности 266 788 просмотров. Причем, учитывая что в общей сложности к блогу обращались 145 тысяч раз, получается, что каждый посетитель заходил на сайт в среднем 2 раза. Хотя, понимаю, что здесь среднее не очень уместно.

      Максимальное число посетителей за сутки - 432 человека. Такое случалось дважды: 20 октября и 22 апреля. Минимальное количество посетителей за сутки – 150 человек. Данная цифра зафиксирована 5 января, то есть в новогодние праздники. Если отбросить новогодние праздники и летние каникулы, то минимальная посещаемость 227 человек.

      Средняя посещаемость 294 человек в сутки.

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

      В среднем пользователи проводят на сайте чуть более четырех минут. Максимальное среднее время за сутки составляет 15 минут. Как это ни странно, а случилось это 28 июня. Пользователей было мало, но занимались, по-видимому, они серьезно.

      Средняя глубина просмотра сайта 1.8 страниц.

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

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

      На паблик в vk подписано 2360 человек.

      Кроме того, при последнем обновлении ТИЦ Яндексом, сайту присвоен ТИЦ 10.
      На этом по цифрам и фактам 2014 года всё.

      Посмотрим, что год грядущий нам готовит.

      Препроцессор языка Си. Директивы препроцессора.

      Еще в самом первом уроке, я говорил вам, что когда компилятор встречает команду #include <stdio.h> он подставляет в это место содержимое файла stdio.h. На самом деле все немножко не так. Настал час, когда вас можно посвятить в эти тонкости, раньше они были излишними.
      На самом деле, компилятор никакой строчки #include <stdio.h> никогда не встретит. Я уже упоминал, что процесс преобразования кода программы в исполняемый файл не так прост. Прежде чем передать код попадет к компилятору, его обрабатывает другая программа – препроцессор.
      Препроцессор - это специальная программа, которая обрабатывает исходный код, прежде чем передать его компилятору.

       Чем занимается препроцессор?

      • удаляет комментарии из кода   
      • обрабатывает директивы препроцессора
      Директивы препроцессора - это все те команды, которые начинаются с символа «#».
      На данный момент вы знаете как минимум две такие команды #include и #define, хотя есть и другие.
      Данный список неполный. Есть и другие действия, которые выполняет препроцессор, но я о них пока рассказывать не буду.
       

      Как работает препроцессор?

      В работе препроцессора важно понимать две вещи:
      • Препроцессор работает строго до компилятора
      • Препроцессор просто заменяет один текст – другим
      Ему вообще наплевать на синтаксис и всякие условности. Он просматривает текст, и заменяет одни его кусочки другими.
      Что и на что заменяется, вы уже должны знать, но я на всякий случай напомню.
      В случае директивы #include <stdio.h> сама эта строка будет заменена препроцессором на содержимое файла stdio.h.
      В случае директивы #define FJ 11 все вхождения FJ заменяются на 11. Кстати, это тоже не единственный вариант использования директивы #define. Но мы пока что коснемся только этого варианта.
      Стоит отметить, что если FJ встретиться внутри имени какой-нибудь переменной или в названии оператора, то она естественно ни на что не заменится. Например, если есть переменная с именем kFJ, то она так и останется kFJ а не станет после обработки препроцессором k11.
      Теперь разберем пример, который был в тесте в нашей группе во Вконтакте.


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


      #include <stdio.h>
      #define G s89
      int main (){
              char G =10;
              s89=12;
              // комментарий
              printf("%d  %d\n", s89, G);
              return 0;
      }

      Препроцессор начинает  обрабатывать этот код и буквально сразу же встречает директиву #include <stdio.h>. Для него, как мы уже знаем, это команда на то, чтобы вставить вместо этой строчки содержимое файла stdio.h. Вставляем.  Получившийся код я сюда выписывать не буду, иначе это займет очень много места.
      Препроцессор продолжает обработку файла и встречает команду #define G s89. Это как мы знаем, команда на то, чтобы заменить G на s89
      После замены получим следующий код. (ниже приведен код только для функции main)

      int main (){
              char s89 =10;
              s89=12;
             
              printf("%d  %d\n", s89, s89);
              return 0;
      }

      Ну и походу дела, препроцессор удалит комментарий из программы, а точнее заменит его пустой строчкой.
      Вот, в принципе, мы и ответили на вопрос: «Почему программа компилируется?»
      Хоть многих и смутило, что в ней отсутствует переменная s89, разобравшись обстоятельно, видим, что она-то как раз есть, а вот переменной G нет. Именно такой код поступит на компиляцию. Нетрудно видеть, что он корректный.

      Как посмотреть код программы, после обработки препроцессором.

      Дальше материал для тех, кому хотелось бы посмотреть полный код после обработки препроцессором Си. Такая возможность предусмотрена средой Visual Studio. Для этого нужно немножко поковыряться в свойствах проекта.
      Ниже пошаговая инструкция:
      1 шаг.
      Открываем свойства проекта. Либо используем меню «Проект -> Свойства», либо горячие клавиши «Alt+F7».



      2 шаг.
      Слева, в появившемся окне выбираем «Свойства конфигурации -> С/С++ -> Препроцессор». 


      Затем в правой части окна, в поле «Создавать файл препроцессора»  выбираем «Без номеров строк». Нажимаем «Ок».
      Теперь, после нажатия «F7» в папке с проектом появится файл с расширением *.i открыв его в любом текстовом редакторе, вы и увидите файл после обработки препроцессором.
      Стоит отметить, что при этом код не компилируется, и если вы попытаетесь запустить программу «Alt+F5» среда разработки предложит вам заново построить решение и только после этого запустит программу.
       

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



      Скачать текстовую версию урока. [pdf]

      Препроцессор языка Си. Директивы препроцессора.

      Еще в самом первом уроке, я говорил вам, что когда компилятор встречает команду #include <stdio.h> он подставляет в это место содержимое файла stdio.h. На самом деле все немножко не так. Настал час, когда вас можно посвятить в эти тонкости, раньше они были излишними.
      На самом деле, компилятор никакой строчки #include <stdio.h> никогда не встретит. Я уже упоминал, что процесс преобразования кода программы в исполняемый файл не так прост. Прежде чем передать код попадет к компилятору, его обрабатывает другая программа – препроцессор.
      Препроцессор - это специальная программа, которая обрабатывает исходный код, прежде чем передать его компилятору.

       Чем занимается препроцессор?

      • удаляет комментарии из кода   
      • обрабатывает директивы препроцессора
      Директивы препроцессора - это все те команды, которые начинаются с символа «#».
      На данный момент вы знаете как минимум две такие команды #include и #define, хотя есть и другие.
      Данный список неполный. Есть и другие действия, которые выполняет препроцессор, но я о них пока рассказывать не буду.
       

      Как работает препроцессор?

      В работе препроцессора важно понимать две вещи:
      • Препроцессор работает строго до компилятора
      • Препроцессор просто заменяет один текст – другим
      Ему вообще наплевать на синтаксис и всякие условности. Он просматривает текст, и заменяет одни его кусочки другими.
      Что и на что заменяется, вы уже должны знать, но я на всякий случай напомню.
      В случае директивы #include <stdio.h> сама эта строка будет заменена препроцессором на содержимое файла stdio.h.
      В случае директивы #define FJ 11 все вхождения FJ заменяются на 11. Кстати, это тоже не единственный вариант использования директивы #define. Но мы пока что коснемся только этого варианта.
      Стоит отметить, что если FJ встретиться внутри имени какой-нибудь переменной или в названии оператора, то она естественно ни на что не заменится. Например, если есть переменная с именем kFJ, то она так и останется kFJ а не станет после обработки препроцессором k11.
      Теперь разберем пример, который был в тесте в нашей группе во Вконтакте.


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


      #include <stdio.h>
      #define G s89
      int main (){
              char G =10;
              s89=12;
              // комментарий
              printf("%d  %dn", s89, G);
              return 0;
      }

      Препроцессор начинает  обрабатывать этот код и буквально сразу же встречает директиву #include <stdio.h>. Для него, как мы уже знаем, это команда на то, чтобы вставить вместо этой строчки содержимое файла stdio.h. Вставляем.  Получившийся код я сюда выписывать не буду, иначе это займет очень много места.
      Препроцессор продолжает обработку файла и встречает команду #define G s89. Это как мы знаем, команда на то, чтобы заменить G на s89
      После замены получим следующий код. (ниже приведен код только для функции main)

      int main (){
              char s89 =10;
              s89=12;
             
              printf("%d  %dn", s89, s89);
              return 0;
      }

      Ну и походу дела, препроцессор удалит комментарий из программы, а точнее заменит его пустой строчкой.
      Вот, в принципе, мы и ответили на вопрос: «Почему программа компилируется?»
      Хоть многих и смутило, что в ней отсутствует переменная s89, разобравшись обстоятельно, видим, что она-то как раз есть, а вот переменной G нет. Именно такой код поступит на компиляцию. Нетрудно видеть, что он корректный.

      Как посмотреть код программы, после обработки препроцессором.

      Дальше материал для тех, кому хотелось бы посмотреть полный код после обработки препроцессором Си. Такая возможность предусмотрена средой Visual Studio. Для этого нужно немножко поковыряться в свойствах проекта.
      Ниже пошаговая инструкция:
      1 шаг.
      Открываем свойства проекта. Либо используем меню «Проект -> Свойства», либо горячие клавиши «Alt+F7».



      2 шаг.
      Слева, в появившемся окне выбираем «Свойства конфигурации -> С/С++ -> Препроцессор». 


      Затем в правой части окна, в поле «Создавать файл препроцессора»  выбираем «Без номеров строк». Нажимаем «Ок».
      Теперь, после нажатия «F7» в папке с проектом появится файл с расширением *.i открыв его в любом текстовом редакторе, вы и увидите файл после обработки препроцессором.
      Стоит отметить, что при этом код не компилируется, и если вы попытаетесь запустить программу «Alt+F5» среда разработки предложит вам заново построить решение и только после этого запустит программу.
       

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



      Скачать текстовую версию урока. [pdf]

      Зачем нужны указатели в языке Си?

      Зачем нужны указатели в языке Си?

       В блоге уже есть урок, рассказывающий об указателях. В том уроке я попытался подробно объяснить, что такое указатель и как с ним можно работать. Но забыл самое главное, то с чего стоило бы начать. И вдумчивые читатели быстро заметили этот мой недочет, и стали  задавать  логичные вопросы:«А зачем это всё? Зачем нужны указатели? Почему нам не работается с переменными? Нормально же всё было, ну чего ты начал-то? А?»
      И правда, чего я начал-то?  Пора расставить точки над i. Итак, ниже несколько вариантов ответа на вопрос: «Зачем в Си нужны указатели?»

      Ответ номер один.

      Правила языка Си таковы, что без использования указателей некоторые вещи невозможно реализовать.
      Умные слова хорошо, а наглядный пример еще лучше.
      Напоминаю, что в языке Си переменные в функцию передаются «по значению».  Это обозначает, что когда мы вызываем функцию с какими-то параметрами, то в памяти создаются копии этих переменных и уже с ними работает функция. Когда функция заканчивает свою работу, эти копии уничтожаются.
      И чем это нам мешает?
      Ну, в принципе, тем, что мы не можем написать функцию, которая меняет значения двух переменных местами.  В принципе, я уже говорил об этой проблеме и даже приводил её решение, но как-то не акцентировал внимания на том, что без указателей написать такую функцию невозможно. Но чтобы всё было в одном месте, кратко повторюсь.
      На первый взгляд кажется, что всё в порядке, но запустив следующую программу, легко убедиться, что написанная нами функция работает не так, как мы ожидаем.
      #include <stdio.h>
      void swap(int a, int b) {
      int temp = a;
      a = b;
      b = temp;
      }

      int main(){
      int x = 3,y = 5;
              printf("x=%d t y=%d n",x,y);
              swap(x,y);
              printf("x=%d t y=%d n",x,y);
              return (0);
      }


      А ниже результат её работы.

      Решение простое, использовать указатели. Т.е. передавать в функцию не копию переменной, а её адрес в памяти и работать уже непосредственно с этим адресом. Такой способ передачи аргументов в функцию, называется передача аргументов «по ссылке».
      #include <stdio.h>
      void swap (int *pi_a, int *pi_b){
      //принимаем указатели на переменные типа int
            int temp = *pi_a;
            *pi_a = *pi_b;
            *pi_b = temp;
      }
      int main (){
            int x=3,y=5;
            printf("x=%d t y=%d n",x,y);
            // ВНИМАНИЕ!передаем адреса,
            //так как функция swap принимает указатели
            swap(&x,&y);
            printf("x=%d t y=%d n",x,y);
            return(0);
      }

      Результат работы программы с использование указателей:

      Как видите, теперь функция работает так, как он неё требуется.

      Ответ номер два.

      Указатели позволяет эффективно использовать возможности и ресурсы компьютера.
      Хотя ответ и другой, а причина всё та же. Передача аргументов в функцию. Я уже говорил выше, в функцию передаются копии переменных. Это правило не касается массивов. Массивы всегда передаются «по ссылке». Именно это и позволяет эффективно использовать ресурсы и возможности компьютера.
      Представьте, что вы бы передавали массив из 10000 значений типа double по значению. То есть, при вызове функции программе нужно было бы найти достаточно места, чтобы сохранить такой объем данных. Причем места непрерывного, так как массивы, как вы должны помнить, располагаются в памяти последовательно. И, кроме того, необходимо было бы скопировать все элементы из одного массива в другой.
      Такой подход занимал бы уйму времени и памяти, да и вообще, был бы невозможен при больших массивах. А так, мы передали указатель на первый элемент и радуемся. И не нужно много памяти искать, и копировать ничего не приходится.

      Третий ответ.

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

      Четвертый ответ.

      Это ответ скорее относится к вопросу: «Зачем вам нужно знать указатели?», а не к изначальному вопросу: «Зачем указатели нужны в Си, в принципе?».
      Ответ банальный и очевидный.
      Язык Си устроен таким образом, что, не зная принципов работы с указателями, вы просто не сумеете использовать огромное количество его возможностей. 
      Пример привести очень легко. Откройте справочник по функциям работы со строками в Си и внимательно посмотрите, что возвращают эти функции. Огромное их число возвращают в качестве результат своей работы указатели. А если вы о них ничего не знаете, как вы сможете их использовать? Да никак. 

      Вот и всё на сегодня.

       Скачать текстовую версию урока.[pdf]

      Зачем нужны указатели в языке Си?

      Зачем нужны указатели в языке Си?

       В блоге уже есть урок, рассказывающий об указателях. В том уроке я попытался подробно объяснить, что такое указатель и как с ним можно работать. Но забыл самое главное, то с чего стоило бы начать. И вдумчивые читатели быстро заметили этот мой недочет, и стали  задавать  логичные вопросы:«А зачем это всё? Зачем нужны указатели? Почему нам не работается с переменными? Нормально же всё было, ну чего ты начал-то? А?»
      И правда, чего я начал-то?  Пора расставить точки над i. Итак, ниже несколько вариантов ответа на вопрос: «Зачем в Си нужны указатели?»

      Ответ номер один.

      Правила языка Си таковы, что без использования указателей некоторые вещи невозможно реализовать.
      Умные слова хорошо, а наглядный пример еще лучше.
      Напоминаю, что в языке Си переменные в функцию передаются «по значению».  Это обозначает, что когда мы вызываем функцию с какими-то параметрами, то в памяти создаются копии этих переменных и уже с ними работает функция. Когда функция заканчивает свою работу, эти копии уничтожаются.
      И чем это нам мешает?
      Ну, в принципе, тем, что мы не можем написать функцию, которая меняет значения двух переменных местами.  В принципе, я уже говорил об этой проблеме и даже приводил её решение, но как-то не акцентировал внимания на том, что без указателей написать такую функцию невозможно. Но чтобы всё было в одном месте, кратко повторюсь.
      На первый взгляд кажется, что всё в порядке, но запустив следующую программу, легко убедиться, что написанная нами функция работает не так, как мы ожидаем.
      #include <stdio.h>
      void swap(int a, int b) {
      int temp = a;
      a = b;
      b = temp;
      }

      int main(){
      int x = 3,y = 5;
              printf("x=%d \t y=%d \n",x,y);
              swap(x,y);
              printf("x=%d \t y=%d \n",x,y);
              return (0);
      }


      А ниже результат её работы.

      Решение простое, использовать указатели. Т.е. передавать в функцию не копию переменной, а её адрес в памяти и работать уже непосредственно с этим адресом. Такой способ передачи аргументов в функцию, называется передача аргументов «по ссылке».
      #include <stdio.h>
      void swap (int *pi_a, int *pi_b){
      //принимаем указатели на переменные типа int
            int temp = *pi_a;
            *pi_a = *pi_b;
            *pi_b = temp;
      }
      int main (){
            int x=3,y=5;
            printf("x=%d \t y=%d \n",x,y);
            // ВНИМАНИЕ!передаем адреса,
            //так как функция swap принимает указатели
            swap(&x,&y);
            printf("x=%d \t y=%d \n",x,y);
            return(0);
      }

      Результат работы программы с использование указателей:

      Как видите, теперь функция работает так, как он неё требуется.

      Ответ номер два.

      Указатели позволяет эффективно использовать возможности и ресурсы компьютера.
      Хотя ответ и другой, а причина всё та же. Передача аргументов в функцию. Я уже говорил выше, в функцию передаются копии переменных. Это правило не касается массивов. Массивы всегда передаются «по ссылке». Именно это и позволяет эффективно использовать ресурсы и возможности компьютера.
      Представьте, что вы бы передавали массив из 10000 значений типа double по значению. То есть, при вызове функции программе нужно было бы найти достаточно места, чтобы сохранить такой объем данных. Причем места непрерывного, так как массивы, как вы должны помнить, располагаются в памяти последовательно. И, кроме того, необходимо было бы скопировать все элементы из одного массива в другой.
      Такой подход занимал бы уйму времени и памяти, да и вообще, был бы невозможен при больших массивах. А так, мы передали указатель на первый элемент и радуемся. И не нужно много памяти искать, и копировать ничего не приходится.

      Третий ответ.

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

      Четвертый ответ.

      Это ответ скорее относится к вопросу: «Зачем вам нужно знать указатели?», а не к изначальному вопросу: «Зачем указатели нужны в Си, в принципе?».
      Ответ банальный и очевидный.
      Язык Си устроен таким образом, что, не зная принципов работы с указателями, вы просто не сумеете использовать огромное количество его возможностей. 
      Пример привести очень легко. Откройте справочник по функциям работы со строками в Си и внимательно посмотрите, что возвращают эти функции. Огромное их число возвращают в качестве результат своей работы указатели. А если вы о них ничего не знаете, как вы сможете их использовать? Да никак. 

      Вот и всё на сегодня.

       Скачать текстовую версию урока.[pdf]