язык C в Linux: вопросы начального уровня

Вопросы написания собственного программного кода (на любых языках)

Модератор: Olej

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 09 окт 2013, 21:33

Мне выпала необходимость выполнить небольшой учебный курс для пары-тройки учеников, по использованию C в Linux... детали не важны ;-) .
И по ходу я придумываю не совсем тривиальные примеры, заставляющие детальнее подумать над синтаксическими правилами C ... хотя, казалось бы, чего там думать?
Но примеры получаются временами ... смешные. И я решил показывать их здесь. В расчёте на то, что кто-то, у кого есть любопытные примерчики, тоже покажет их здесь... ;-)

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

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 09 окт 2013, 21:37

Olej писал(а): Но примеры получаются временами ... смешные.
Типы данных (файл 1.c):

Код: Выделить всё

#include <stdio.h>

// скалярные типы данных:
int main () {
   int i = 123;
   short is = 12;
   char ic1 = 3, ic2 = '2';
   long il = 12345;
   long long ill = 123456;

   printf( " %d \n %d \n %d \n %d \n %lx \n %llx \n",
              i,    is,   ic1,  ic2,  il,    ill );
   printf( "%c => %i\n", ic2, ic2 );

   double rd = 3.14159265358979323846264338327950288419716939937510;
   float rf = rd;
#define FMT "%30.27f"
   printf( FMT" - "FMT" = "FMT"\n", rd, rf, rd - rf );

   return 0;
}
Выполнение:

Код: Выделить всё

bash-4.2$ ./exe1
 123 
 12 
 3 
 50 
 3039 
 1e240 
2 => 50
 3.141592653589793115997963469 -  3.141592741012573242187500000 = -0.000000087422780126189536531
Последний результат хорош:
A = A;
A - A ... - это вовсе не равно 0 ;-)

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 09 окт 2013, 21:41

Olej писал(а): Но примеры получаются временами ... смешные.
Следующая группа операций: агрегирование данных из простых скалярных (файл 2.c):

Код: Выделить всё

bash-4.2$ cat 2.c
#include <stdio.h>
#include <string.h>
#include <wchar.h>

// агрегаты данных:
int main () {

   int ai[] = { 1, 2, 3, 4, 5 }, ni, j;
   printf( "%d => ", ni = sizeof( ai ) / sizeof( ai[ 0 ] ) );
   for( j = 0; j < ni; j++ ) printf( "%d, ", ai[ j ] );
   printf( "\n" );

   // разница в представлении
   char ac[] = { '1', '2', '3', '4', '5', 0, '6', '\0' };
   printf( "%d (строка %d) => ", ni = sizeof( ac ) / sizeof( ac[ 0 ] ), strlen( ac ) );
   for( j = 0; j < ni; j++ ) printf( "%d, ", ac[ j ] );
   printf( "\n" );

   // присвоение структурных данных
   struct ss {
      int a1, a2, a3;
   } vss1 = { 1, 2, 3 }, vss2 = { 3, 2, 1 };
   vss1 = vss2;
   printf( " %d %d %d \n", vss1.a1, vss1.a2, vss1.a3 );

   // наложение разнородныз данных
   struct su {
      union {
         char c[ 12 ];     
         short s[ 6 ];
         float f[ 3 ];
      };
   } su1 = {{{ '1', '2', '3', '4', '5', '6', 0, 0, 0, 0, 0, 0 }}};
   printf( "размер структуры %d байт\n", sizeof( su1 ) );
   for( j = 0; j < sizeof( su1.c ) / sizeof( su1.c[ 0 ] ); j++ )
      printf( "%d, ", su1.c[ j ] );
   printf( "\n" );
   for( j = 0; j < sizeof( su1.s ) / sizeof( su1.s[ 0 ] ); j++ )
      printf( "%d, ", su1.s[ j ] );
   printf( "\n" );
   for( j = 0; j < sizeof( su1.f ) / sizeof( su1.f[ 0 ] ); j++ )
      printf( "%f, ", su1.f[ j ] );
   printf( "\n" );
   char *p = (char*)&su1;
   printf( "адрес=%p : %s, длина %d символов\n", p, p, strlen( p ) );
   
   // разница длины UTF-8 строки (русскоязычной) в байтах и символах
   const char buf[] = "русскоязычная строка";
   printf( "строка: '%s', длина %d ,байт\n", buf, strlen( buf ) );

   return 0;
}
Результатом это имеет:

Код: Выделить всё

bash-4.2$ ./exe2
5 => 1, 2, 3, 4, 5, 
8 (строка 5) => 49, 50, 51, 52, 53, 0, 54, 0, 
 3 2 1 
размер структуры 12 байт
49, 50, 51, 52, 53, 54, 0, 0, 0, 0, 0, 0, 
12849, 13363, 13877, 0, 0, 0, 
0.000000, 0.000000, 0.000000, 
адрес=0xbf8c7e34 : 123456, длина 6 символов
строка: 'русскоязычная строка', длина 39 ,байт
Любопытный последний результат: глаза явно видят 20 букв, а программа говорит 39 байт ;-)

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 09 окт 2013, 21:44

Структуры управления (файл 3.c):

Код: Выделить всё

bash-4.2$ cat 3.c 
#include <stdio.h>

// структуры управления:
int main () {
   short s1[] = { 1, 2, 3, 4, 5, 6 },
         ns = sizeof( s1 ) / sizeof( s1[ 0 ] ),
         i;
   for( i = 0; i < ns; i++ ) 
      printf( "%d, ", s1[ i ] );
   printf( "\n" );

   i = -1;
   while( ++i < ns ) {
      printf( "%d, ", s1[ i ] );
   }
   printf( "\n" );

   i = 0;
   do {
      printf( "%d, ", s1[ i ] );
   } while( i++ < ns - 1 );      // !!!
   printf( "\n" );

   for( i = 0; i < ns; i++ ) {
      printf( "%d : ", s1[ i ] );
      switch( s1[ i ] ) {
         case 1:
         case 2: 
            printf( "%s ", "мало" );
            break;
         case 3:
            printf( "%s ", "нормально" );
            break;
         case 4:
            printf( "%s ", "много" );
            break;
         default:
            printf( "%s ", "чрезмерно" );
         case 5:
            printf( "%s", "много " );
      }
      printf( "\n" );
    
   }

   return 0;
}
Здесь меньше веселья ... но всё же:

Код: Выделить всё

bash-4.2$ ./exe3
1, 2, 3, 4, 5, 6, 
1, 2, 3, 4, 5, 6, 
1, 2, 3, 4, 5, 6, 
1 : мало 
2 : мало 
3 : нормально 
4 : много 
5 : много 
6 : чрезмерно много 

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 09 окт 2013, 21:46

Последняя на сегодня группа развлечений ;-) - вызовы функций:

Код: Выделить всё

bash-4.2$ cat 4.c 
#include <stdio.h>

typedef int (*summ_t) ( int );
int summ2( int x ) { return x + 2; }
int summ3( int x ) { return x + 3; }
int summ4( int x ) { return x + 4; }

summ_t funcs[] = { summ2, summ3, summ4 };

int call( summ_t func, void *data ) {
   return func( *(int*)data );
}

void set1( int x ) { x++; }
void set2( int* x ) { (*x)++; }

//------------------------------------------

#define N 10
typedef struct {
   int x[ N ];
} astruct_t;

astruct_t revers( astruct_t s ) {
   int n, i, j;
   n = sizeof( s ) / sizeof( int );
   for( i = 0, j = n - 1; i < j; i++, j-- ) {
      int var = s.x[ i ];
      s.x[ i ] = s.x[ j ];
      s.x[ j ] = var;
   } 
   return s;
}

void show_ba( astruct_t* b, astruct_t* a ) {
   int i;
   printf( "before: " );
   for( i = 0; i < N; i++ ) 
      printf( "%d%s", b->x[ i ], i != N - 1 ? ", " : ""  );
   printf( " | after: " );
   for( i = 0; i < N; i++ ) 
      printf( "%d%s", a->x[ i ], i != N - 1 ? ", " : ""  );
   printf( "\n" );
}

//------------------------------------------

void mod( astruct_t* s ) {
   int n = sizeof( *s ) / sizeof( int );
   void pow2( void ) {
      int i;
      for( i = 0; i < n; i++ ) 
         s->x[ i ] *= s->x[ i ];
   } 
   pow2();
   return;
}

//------------------------------------------


// функции и вызовы:
int main () {
   int i;
//------------------------------------------
   for( i = 0; i < sizeof( funcs ) / sizeof( funcs[ 0 ] ); i++ )
      printf( "%d ", funcs[ i ]( i ) );
   printf( "\n" );
//------------------------------------------
   summ_t summ2_2 = summ2;
   printf( "%d ", summ2_2( 7 ) );
   for( i = 0; i < sizeof( funcs ) / sizeof( funcs[ 0 ] ); i++ ) {
      summ2_2 = funcs[ i ];
      printf( "%d ", summ2_2( 7 ) );
   }
   printf( "\n" );
//------------------------------------------
   i = 3;
   int *pi = &i;
   printf( "косвенный вызов: %d\n", call( summ3, &i ) );
   set1( i );
   printf( "передача параметра: по значению -> %d,", i );
   set2( pi );
   printf( " по ссылке -> %d\n", i );
//------------------------------------------
   astruct_t before = {{ 1, 2, 3, 4, 5, 6, 7 }},
             after = {{ 10*(0) }};
   show_ba( &before, &after );
   printf( "revers ... ... ...\n" );
   after = revers( before );
   show_ba( &before, &after );
//------------------------------------------
   after = before;
   mod( &after );
   printf( "вложенные описания функций (GCC):\n" );
   show_ba( &before, &after );
//------------------------------------------
   return 0;
}
И что из этого получается:

Код: Выделить всё

bash-4.2$ ./exe4
2 4 6 
9 9 10 11 
косвенный вызов: 6
передача параметра: по значению -> 3, по ссылке -> 4
before: 1, 2, 3, 4, 5, 6, 7, 0, 0, 0 | after: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
revers ... ... ...
before: 1, 2, 3, 4, 5, 6, 7, 0, 0, 0 | after: 0, 0, 0, 7, 6, 5, 4, 3, 2, 1
10
вложенные описания функций (GCC):
before: 1, 2, 3, 4, 5, 6, 7, 0, 0, 0 | after: 1, 4, 9, 16, 25, 36, 49, 0, 0, 0

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 09 окт 2013, 21:52

Кроме того, на GCC в Linux "свет клином не сошёлся" (особенно последний 1-2 года ;-) ), поэтому всё это можно (попробовать!) собрать новым компилятором Clang:

Код: Выделить всё

bash-4.2$ make clang
clang -xc -Wall 1.c -o exe1l
clang -xc -Wall 2.c -o exe2l
clang -xc -Wall 3.c -o exe3l
clang -xc -Wall 4.c -o exe4l
4.c:50:21: error: expected ';' at end of declaration
   void pow2( void ) {
                    ^
                    ;
1 error generated.
make: *** [exe4l] Ошибка 1
... и убедиться, что не все расширения GCC Clang готов проглотить, в частности, вложенные определения функций ему не понравились... Или, по крайней мере, это не так просто, и должно оговариваться как-то опциями.
Иначе не очень понятно, как они тогда с помощью Clang скомпилировали ядро Linux, о чём сообщалось несколько месяцев назад?

Но здесь же можно убедиться, что программы, собранные Clang, выполняются точно так же как GCC, а заодно можно их сравнить по параметрам...
Хотя бы, для начала, в том, что размером то они отличаются ;-) :

Код: Выделить всё

bash-4.2$ ls -l exe*
-rwxrwxr-x 1 olej olej 5206 окт.   9 21:52 exe1
-rwxrwxr-x 1 olej olej 5074 окт.   9 21:48 exe1l
-rwxrwxr-x 1 olej olej 6187 окт.   9 21:52 exe2
-rwxrwxr-x 1 olej olej 6155 окт.   9 21:48 exe2l
-rwxrwxr-x 1 olej olej 5545 окт.   9 21:52 exe3
-rwxrwxr-x 1 olej olej 5430 окт.   9 21:48 exe3l
-rwxrwxr-x 1 olej olej 7233 окт.   9 21:52 exe4
P.S. Для любителей поразвлекаться архив всего рассказанного выше - прилагается:
Вложения
examples.tgz
(2.95 КБ) 689 скачиваний

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 15 окт 2013, 14:47

Подсказали (в тему):
- есть такая книжка (даже в переводе):
Керниган Б., Ритчи Д., Фьэр А.
Язык программирования Си. Задачи по языку Си
Пер.с англ. Д.Б.Подшивалова и В.А.Иващенко. -
М.:Финансы и статистика, 1985. - с.193-278.
Она вдвое толще, чем оригинал K&R - это те задачи и упражнения, что Фьэр добавил.
(как утверждает человек, которому я не могу не доверять ;-) - это лучший сборник задач)

Вот электронный вариант именно самого задачника: А.Фьюэр, Задачи по языку С.
Пользуйтесь!

P.S. Мне сообщили, что в некоторых браузерах (Safari на MacOS) этот URL не открывается (что-то в записях DNS серверов намудрено).
Этот URL - это ХПИ (Харьковский Политехнический Институт) ... сейчас он как-то по-другому называется ... университе-е-е... ;-) (но DNS нормально зарегистрировать не в состоянии).
Тогда можете открывать этот текст по IP адресу:

Код: Выделить всё

$ nslookup khpi-iip.mipk.kharkiv.edu
Server:		192.168.1.1
Address:	192.168.1.1#53

Non-authoritative answer:
Name:	khpi-iip.mipk.kharkiv.edu
Address: 194.44.157.122

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 15 окт 2013, 14:53

Olej писал(а): (как утверждает человек, которому я не могу не доверять ;-) - это лучший сборник задач)
Процесс изучения языка программирования можно представить как последовательное прохождение трех этапов (каждый этап, несомненно, может повторяться неоднократно). Первый этап состоит в освоении синтаксиса языка, по крайней мере настолько, что транслятор перестает "ругаться", обнаружив в вашей программе бессмысленные конструкции. Второй этап состоит в осмыслении правильно построенных транслятором конструкций языка. На третьем этапе вырабатывается определенный стиль программирования, соответствующий духу языка, т.е. умение писать ясные, краткие и правильные программы.

Головоломки в этой книге предназначены для того, чтобы помочь читателю на втором этапе обучения языку. Они бросают вызов искусству владения читателем основными правилами языка, заводят его в "редко посещаемые закоулки" языка, подводят к граничным условиям и знакомят с немногими откровенными ловушками. (Конечно, С, как всякий язык программирования, имеет свою долю неясностей, которая познается на опыте.)

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

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 15 окт 2013, 15:13

Olej писал(а):Этот URL - это ХПИ (Харьковский Политехнический Институт) ... сейчас он как-то по-другому называется ...
Там вообще шикарная (по подборке) библиотека: Каталог библиотеки кафедры "Информатика и интеллектуальная собственность"
Изображение
- по операционным системам
- ... особенно по UNIX
- особенно все знаменитые статьи Эдсгара Дэйкстры в переводе на русский - это обязаны все читать!
Изображение
Изображение
- и особенно Э.Дейкстра Взаимодействие последовательных процессов, что есть вообще просто классика!

Аватара пользователя
Olej
Писатель
Сообщения: 21336
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: язык C в Linux: вопросы начального уровня

Непрочитанное сообщение Olej » 15 окт 2013, 20:13

Olej писал(а): P.S. Мне сообщили, что в некоторых браузерах (Safari на MacOS) этот URL не открывается (что-то в записях DNS серверов намудрено).
Этот URL - это ХПИ (Харьковский Политехнический Институт) ... сейчас он как-то по-другому называется ... университе-е-е... ;-) (но DNS нормально зарегистрировать не в состоянии).
Тогда можете открывать этот текст по IP адресу:
Наблюдаемое с этим URL не поддаётся объяснению, это нельзя понять:
- обращение из Opera (v.12.16) по имени http://khpi-iip.mipk.kharkiv.edu/librar ... index.html заканчивается ошибкой 404
- обращение из Firefox (v.24.0) , в тот же момент времени, по http://khpi-iip.mipk.kharkiv.edu/librar ... index.html - ОК и мгновенно, влёт...
- обращение из Opera по имени (IP) http://194.44.157.122/library/extent/pr ... index.html - всё OK

Я такого цирка ещё не видел :-o

Ответить

Вернуться в «Программирование»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость