1 (20.04.2011 10:21:00 отредактировано drBatty)

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


Керниган, Ричи. Язык С.


Итак. Нам потребуется текстовый редактор(vim), компилятор(gcc), и make. Ещё потребуется линковщик (ld).
Как это найти - зависит от дистрибутива, в Slackware это добро лежит в d/

1) создаём каталог для нашего проекта:

 Консоль:
doc@bx:~$ mkdir -pv projects/first_program
mkdir: создан каталог `projects/first_program'
doc@bx:~$ cd !$
cd projects/first_program
doc@bx:~/projects/first_program$

2) запускаем vim, и пишем
http://s009.radikal.ru/i309/1011/69/e45ff6980554.png

#include <stdio.h> /*это заголовочный файл. */
/* Там лежат объявления функций. Нам понадобится printf */
/* про эту функцию можно почитать в man'е. */
/* Беда в том, что в bash тоже есть такая функция */
/* потому набирайте man 3 printf */

int main(void) /* наша функция. она не имеет параметров,*/
/*но возвращает значение */
{
    printf("Привет Мир!\n"); /* вывод сообщения */
    return 0; /* выход. 0 - успешное завершение */
}

3) теперь собираем:

 Консоль:
doc@bx:~/projects/first_program$ gcc -Wall -O3 -o hello main.c

объяснения ключей:
-Wall - все ошибки выводятся.
-O3 самая сильная оптимизация
-o hello имя нашей программы
main.c созданный нами файл

*примечание: можно собирать открыв ещё одну консоль. А в виме можно перейти в командный режим и набрать команду vim'а !, и сразу после неё команду shella

 Консоль:
:!gcc -Wall -O3 -o hello main.c

конечно это работает в любом хорошем редакторе.

4) Запускаем нашу программу:

 Консоль:
doc@bx:~/projects/first_program$ ./hello
Привет Мир!

а про make я вам завтра расскажу. Если это кому-то интересно...

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

2

Как использовать vim?

Вход в режим редактирования осуществляется кнопкой i.
Выход - кнопкой ESC
в нормальном режиме можно всё сохранить командой :w
выход из нормального режима :q

Полезно:
Копировать строку yy
поиск и замена :%s/маша/таня/gci
Здесь: % значит - по всему тексту
s - команда замены
маша - что ищем
таня - на что меняем
g значит "все вхождения в строке"
c с вопросами
i регистро НеЗаВиСиМо

для кодеров очень полезно выделение блока (CTRL+V) и ещё вставка (I) перед блоком.
команда :set number (используйте автодополнение!) включает номера строк
gv включает прошлый блок

Автодополнение: обычно я использую CTRL+N, но есть и CTRL+X+...

вкладки: zo открыть, zc закрыть и т.д. Незаменимая фича для кодера.

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

3

Окна в vim'е

Угу. консольная прога поддерживает окошки.

можно открыть второй файл командой :split файл это разбиение по вертикали. По горизонтали :vsplit
переключатся можно используя CTRL+W+W (есть и ещё 100500 команд)

А ещё есть вкладки, aka табы. Для их открытия наберите :tabnew файл
Лично я юзаю и то и другое.

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

4

Подсветка синтакса.

Это великая вещь. Без неё никуда. Включается командой :syntax on. в vim работает поддержка ВСЕХ языков программирования, в т.ч. даже такой экзотики как sed. Впрочем, мы про C, а он конечно тоже подсвечивается. Как и C++.

Ну и автоотступы - Хорошая Мысль. Оно тоже работает.

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

5

К вышеперечисленным опциям gcc стоит добавить
-std=c89 - достаточно для K&R
-std=c99 - для ANSI/ISO C 99.

Чтобы не набирать каждый раз всю эту красоту для вызова gcc,
можно, например, добавить в .bashrc, который лежит в вашем домашнем каталоге,
такую строчку:
alias c99='gcc -std=c99 -Wall -O3'

потом сделать
~ $ source .bashrc

и "девушка созрела":
теперь можно осуществлять компиляцию командой
~ $ c99 -o <e_name> <s_name.c>

Для учебных целей представляется уместным выделить под ваши программы отдельный каталог:
~ $ mkdir <c_progs>

Если нет необходимости хранить скомпилированными все ваши учебные программы,
можно ещё упростить себе жизнь:

в тот же .bashrc добавить строчку
alias run='./a.out'

перед началом деятельности уходить в связанный с ней каталог:
~ $ cd <c_progs>

запускать компиляцию командой
~ $ c99 <s_name.c>
получая на выходе каждый раз новый a.out в вашем каталоге <c_progs>,
и запускать его на выполнение командой
~ $ run

На вашем терминале приглашение ОСи может выглядеть несколько отличным от ~ $.

Угловые скобки в названиях файлов и каталогов - не используем.

Кстати, о терминалах smile

Если всё получилось с компиляцией первых программ на С,
и вам захотелось выжать из вашей командной строки всё, что она может
(а может она совсем не мало),

возможно, стоит обратиться к nCurses.

Для gcc нет conio.h, и не будет,
потому что для полного управления терминалом в *nix'ах используется библиотека nCurses.

Но поговорим об этом чуть позже, одолев основы С.

Доктор, алаверды smile

Давно уже не забавно наблюдать торжество отрицательного отбора.

6

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

MX 23.6 Libretto x86_64
Чем больше я работаю админом, тем больше понимаю, насколько волшебна фраза - "Нет технической возможности!"

7

Chars67, Спасибо! Плюсик поставил.

xlin пишет:

Мужики, продолжайте... пожалуйста. Мне это очень интересно...

мне тоже. в планах
make & mercurial

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

8

Чтобы не отставать в разговоре про первую программу,

в число опций gcc добавим -lncurses и скомпилируем такой код:

#include <ncurses.h>

int main(void)
{
  initscr();

  addstr("Hello, C with nCurses world!!!\n") // вызов addstr можно заменить на printw
  refresh();

  getch();  // вовсе не обязательный вызов, но об этом - позже
  endwin();
  return 0;
}

Вызовы initscr(), refresh() и endwin() обязательны для адекватной работы любой программы,

обращающейся к библиотеке nCurses.

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

Если говорить более конструктивно, то попробуйте убрать getch(),
и сравните результаты работы программы в "окне терминала" под Иксами,
и в виртуальной консоли (которая Alt-F1..Alt-F6).

Собственно, дальше можно обратиться к
Dan Gookin
"Programmer's Guide to nCurses"
2007
,
к man'ам и faq'ам по данной библиотеке.

Или здесь найдём о чём потолковать, разбираясь с ней дальше.

smile Просто это будет уже не первая программа

Давно уже не забавно наблюдать торжество отрицательного отбора.

9

alias'ы конечно хорошо, но я использую make. Что это такое, и зачем оно надо? эта утилитка собирает проект из исходных файлов. я добавил в свой простой проект ещё один файл, с одной функцией. Точнее 2 файла:

#include <stdio.h>

#include "other.h"

int my_printf(char *s)
{
    int return_code;
    return_code = printf("%s\n", s);
    return return_code;
}

это файл other.c

а вот второй (other.h):

#ifndef OTHER_H
#define OTHER_H


int my_printf(char *s);

#endif /* OTHER_H */

файл main.c теперь принял такой вид:

#include "other.h"

int main(void)
{
    my_printf("Привет, мир!");
    return 0;
}

теперь у меня сначала собираются 2 модуля, а потом они уже линкуются (по-русски "связываются") в законченную программу. Ну а что-бы это всё собирать, используется утилита make, и Makefile к ней:

CC = gcc
CFLAGS = -Wall -g
# CFLAGS = -Wall -O2
LDFLAGS =

OBJECTS = main.o other.o
TARGET = helloworld

RM = rm -f
INSTALL = /usr/bin/install -c

BINDIR = /usr/local/bin

$(TARGET): $(OBJECTS)
    $(CC) $(LDFLAGS) -o $@ $(OBJECTS)

%.o: %.c
    $(CC) $(CFLAGS) -c $<

main.o: main.c other.h
other.o: other.c other.h


clean:
    $(RM) $(OBJECTS) $(TARGET)

install: $(TARGET)
    $(INSTALL) $(TARGET) $(BINDIR)

вот теперь всё по взрослому.

В переменной $(OBJECTS) прописаны все 2 моих объектных файла, а в строчках

main.o: main.c other.h
other.o: other.c other.h

прописано, от чего они зависят. собирается это всё командой

 Консоль:
make

без всяких параметров. тут дана отладочная версия, но вы можете прописать и другие ключики в $(FLAGS)
я советовал -O3, но с этим ключём некоторые программы могут и не заработать (слишком сильная оптимизация. Хотя у меня работает).
выглядит это так
 Консоль:
doc@bx:~/docs/projects/HelloWorld$ make
gcc -Wall -g   -c -o main.o main.c
gcc -Wall -g   -c -o other.o other.c
gcc  -o helloworld main.o other.o
doc@bx:~/docs/projects/HelloWorld$ ./helloworld
Привет, мир!

если изменить other.c
то пересоберётся лишь модуль other.o
 Консоль:
doc@bx:~/docs/projects/HelloWorld$ make
gcc -Wall -g   -c -o other.o other.c
gcc  -o helloworld main.o other.o

а второй модуль не будет пересобираться (main.o), это здорово ускоряет сборку (что важно, ибо с первого раза лично у меня ничего не работает)

конечно для первой программы это и не нужно, но вам, уважаемые читатели, наверное не такой примитив придётся делать в реальной жизни?

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

10

забыл сказать - в Makefile в строчках

$(TARGET): $(OBJECTS)
    $(CC) $(LDFLAGS) -o $@ $(OBJECTS)

%.o: %.cpp
    $(CC) $(CFLAGS) -c $<

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

Вообще говоря, make собирает цели. цель по умолчанию у меня helloworld, но есть ещё make clean, для того, что-бы удалить все результаты работы make

doc@bx:~/docs/projects/HelloWorld$ make clean
rm -f main.o other.o helloworld

теперь make будет пересобирать всё с нуля.

Есть ещё и цель install, для установки нашего приложения в систему (что НЕ рекомендуется, а рекомендуется собрать пакет. Это уже дистроспецифично).

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

11

Если кто-то захочет посмотреть примеры решения простых задач на Си, то пожалуйста:
http://cirishen.blogspot.com/
Чем богаты. :-)

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

12 (22.01.2011 07:51:49 отредактировано Fat-Zer)

drBatty, а СMake'а в планах нет?
[added]
Эх... не посмотрел на дату старта топика...=\

95% процентов проблем находятся между клавиатурой и стулом.

13

Fat-Zer пишет:

а СMake'а в планах нет?

будет... потом.

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

14

если будут продолжения то эт здорово.

Верить нельзя никому...

15

про cmake писать сложно... это ОЧЕНЬ далеко от темы (первая программа). нужно отдельную тему заводить, а может и отдельный раздел (ИМХО я не вижу особых преимуществ у CMake, кроме кроссплатформенности).

Вот неплохой мануал на эту тему: http://symmetrica.net/cmake/CMake-1.htm

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

16 (23.01.2011 11:00:31 отредактировано Fat-Zer)

drBatty пишет:

про cmake писать сложно... это ОЧЕНЬ далеко от темы (первая программа). нужно отдельную тему заводить, а может и отдельный раздел (ИМХО я не вижу особых преимуществ у CMake, кроме кроссплатформенности).

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

ЗЫ: ещё было бы интересно почитать про valgrid, automake/autoconf. Но всё это когда время будет...

95% процентов проблем находятся между клавиатурой и стулом.

17

а не проще написать
cout<<"hello, world";

18

kosmo26 пишет:

а не проще написать
cout<<"hello, world";

Это уже не С, это С++

19

kosmo26 пишет:

а не проще написать
cout<<"hello, world";

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

durc пишет:

Это уже не С, это С++

это ещё и ООП - вместо функционального программирования используется объектно ориентированное.

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

20

А вот в самом начале во втором пункте надо было написать этот код в Vim я написал чего с ним дальше то делать ? почему сразу идет переход к 3 пункту!?
Простите новичка!!!

21

Шок пишет:

А вот в самом начале во втором пункте надо было написать этот код в Vim я написал чего с ним дальше то делать ? почему сразу идет переход к 3 пункту!?
Простите новичка!!!

ИМХО очевидные действия:
сохраняем(<ESC><ESC>:w main.c), выходим в консоль (<ESC><ESC>:q) и выполняем команду из п.3.

95% процентов проблем находятся между клавиатурой и стулом.

22

При написании Makefile неплохо сразу не забывать про DESTDIR...

23

Шок пишет:

А вот в самом начале во втором пункте надо было написать этот код в Vim я написал чего с ним дальше то делать ? почему сразу идет переход к 3 пункту!?

можно не выходя из VIM'а написать

 Консоль:
:!gcc -Wall -O3 -o hello main.c

конечно, другие кодерские редакторы тоже так умеют. Потому и сразу к п3. Я не выхожу из редактора.

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

24

bormant пишет:

При написании Makefile неплохо сразу не забывать про DESTDIR...

при написании первого?.. я как-бы самые базовые понятия дал, для чего вообще эта make нужна...

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

25

Может не в тему, но всё же. Как можно зделат добавление   элемента в массив?

Пока начинающий линуксоид :)

26

gnomsi, как-то совсем не в тему.
По сути никак - если его размер задан заранее, то есть ограничен. Если нужно увеличить размер - придётся выделять память для него в другом месте. а старую потом не забыть удалить. Например, так:

// первый массив
int *a = malloc(sizeof(int)*10);
// какие-то операции... пусть a будет, например, заполнен числами от 0 до 9 в цикле, например
// ...
// второй массив
int *b = malloc(sizeof(int)*11);
// сначала копируем старый массив в новый
for (int i=0; i!=10; i++) {
b[i]=a[i];
}
// затем добавляем уже новый элемент
int new=123;
b[11]=new;
// ну и подчищаем за собой
free(a);
// можно переприсвоить обратно, если хочется
a=b;

Принцип примерно такой...

27

gnomsi, в C? да никак.  ac
размер массива === константное целое число, заданное на этапе компиляции, и жёстко вшитое в код.

Можно делать динамические массивы:

int *a;

a = malloc(10*sizeof(int));
if(!a) exit(70)
// работаем с массивом a[10]

// увеличиваем на 1 число эл-тов
int *t = malloc(11*sizeof(int));
if(!t) exit(70);
memcpy(t, a, 10*sizeof(int));
free(a);
a = t;

// работаем с массивом a[11]
Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

28

Battle Coder, хы... даже числа одинаковые  ag

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)

29

Да... только memcpy и правда будет работать побыстрее, чем цикл for - недодумал =) впрочем, новичку может первый вариант проще окажется для понимания.

30

Battle Coder пишет:

только memcpy и правда будет работать побыстрее, чем цикл for

кстати, не факт. Особенно с такими малыми числами. for компилятор может свернуть и распараллелить, а вот с memcpy ничего не поделать - она не оптимизирована на 40 байт...

Battle Coder пишет:

впрочем, новичку может первый вариант проще окажется для понимания.

ну не знаю bx

Карусель разнесло по цепочке за час
Всех известий — конец
Да, весна началась!
(всё к лицу подлецу, как родному отцу, не рассказывай, батя, и так всё пройдёт)