From ed09da6cdd4092e72e0fb094773103f814cb3279 Mon Sep 17 00:00:00 2001 From: Andrew Popov Date: Sun, 17 Nov 2013 04:51:34 +0400 Subject: [c/ru] translate c manual to russian --- ru-ru/c-ru.html.markdown | 506 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 506 insertions(+) create mode 100644 ru-ru/c-ru.html.markdown (limited to 'ru-ru/c-ru.html.markdown') diff --git a/ru-ru/c-ru.html.markdown b/ru-ru/c-ru.html.markdown new file mode 100644 index 00000000..80f79ffd --- /dev/null +++ b/ru-ru/c-ru.html.markdown @@ -0,0 +1,506 @@ +--- +language: c +filename: learnc.c +contributors: + - ["Adam Bard", "http://adambard.com/"] + - ["Árpád Goretity", "http://twitter.com/H2CO3_iOS"] +translators: + - ["Evlogy Sutormin", "http://evlogii.com"] +lang: ru-ru +--- + +Что ж, Си всё ещё является лидером среди современных высокопроизводительных языков. + +Для большинствоа программистов, Си – это самый низкоуровневый язык на котором они когда-либо писали, +но этот язык даёт больше, чем просто повышение производительности. +Держите это руководство в памяти и вы сможете использовать Си максимально эффективно. + +```c +// Однострочный комментарий начинается с // - доступно только после С99. + +/* +Многострочный комментарий выглядит так. Работает начиная с С89. +*/ + +// Импорт файлов происходит с помощью **#include** +#include +#include +#include + +// Файлы <в угловых скобочках> будут подключаться из стандартной библиотеки. +// Свои файлы необходимо подключать с помощью "двойных кавычек". +#include "my_header.h" + +// Объявление функций должно происходить в .h файлах или вверху .c файла. +void function_1(); +void function_2(); + +// Точка входа в программу – это функция main. +int main() { + // для форматированного вывода в консоль используется printf + // %d – означает, что будем выводить целое число, \n переводит указатель вывода + // на новую строчку + printf("%d\n", 0); // => напечатает "0" + // Каждый оператор заканчивается точкой с запятой. + + /////////////////////////////////////// + // Типы + /////////////////////////////////////// + + // int обычно имеет длину 4 байта + int x_int = 0; + + // shorts обычно имеет длину 2 байта + short x_short = 0; + + // chars гарантированно имеет длину 1 байта + char x_char = 0; + char y_char = 'y'; // Символьные литералы заключаются в кавычки '' + + // long как правило занимает от 4 до 8 байт + // long long занимает как минимум 64 бита + long x_long = 0; + long long x_long_long = 0; + + // float это 32-битное число с плавающей точкой + float x_float = 0.0; + + // double это 64-битное число с плавающей точкой + double x_double = 0.0; + + // Целые типы могут быть беззнаковыми. + unsigned short ux_short; + unsigned int ux_int; + unsigned long long ux_long_long; + + // sizeof(T) возвращает размер переменной типа Т в байтах. + // sizeof(obj) возвращает размер объекта obj в байтах. + printf("%zu\n", sizeof(int)); // => 4 (на большинстве машин int занимает 4 байта) + + // Если аргуметом sizeof будет выражение, то этот аргумент вычисляется + // ещё во время компиляции кода (кроме динамических массивов). + int a = 1; + // size_t это беззнаковый целый тип который использует как минимум 2 байта + // для записи размера объекта + size_t size = sizeof(a++); // a++ считается во время компиляции + printf("sizeof(a++) = %zu, где a = %d\n", size, a); + // выведет строку "sizeof(a++) = 4, где a = 1" (на 32-битной архитектуре) + + // Можно задать размер массива при объявлении. + char my_char_array[20]; // Этот массив занимает 1 * 20 = 20 байт + int my_int_array[20]; // Этот массив занимает 4 * 20 = 80 байт (сумма 4-битных слов) + + // Можно обнулить массив при объявлении. + char my_array[20] = {0}; + + // Индексация массива происходит также как и в других Си-подобных языках. + my_array[0]; // => 0 + + // Массивы изменяемы. Это просто память как и другие переменные. + my_array[1] = 2; + printf("%d\n", my_array[1]); // => 2 + + // В C99 (а также опционально в C11), массив может быть объявлен динамически. + // Размер массива не обязательно должен быть рассчитан на этапе компиляции. + printf("Enter the array size: "); // спрашиваем юзера размер массива + char buf[0x100]; + fgets(buf, sizeof buf, stdin); + size_t size = strtoul(buf, NULL, 10); // strtoul парсит строку в беззнаковое целое + int var_length_array[size]; // объявление динамического массива + printf("sizeof array = %zu\n", sizeof var_length_array); + + // Вывод программы (в зависимости от архитектуры) будет таким: + // > Enter the array size: 10 + // > sizeof array = 40 + + + // Строка – это просто массив символов, оканчивающийся нулевым (NUL (0x00)) байтом + // представляемым в строке специальным символом '\0'. + // Нам не нужно вставлять нулевой байт в строковой литерал, + // компилятор всё сделает за нас. + char a_string[20] = "This is a string"; + printf("%s\n", a_string); // %s обозначает вывод строки + + printf("%d\n", a_string[16]); // => 0 + // байт #17 тоже равен 0 (а также 18, 19, и 20) + + // Если между одинарными кавычками есть символ – это символьный литерал, + // но это тип int, а не char (по историческим причинам). + + int cha = 'a'; // хорошо + char chb = 'a'; // тоже хорошо (подразумевается преобразование int в char) + + /////////////////////////////////////// + // Операторы + /////////////////////////////////////// + + // Можно использовать множественное объявление + int i1 = 1, i2 = 2; + float f1 = 1.0, f2 = 2.0; + + // Арифметика обычная + i1 + i2; // => 3 + i2 - i1; // => 1 + i2 * i1; // => 2 + i1 / i2; // => 0 (0.5, но обрезается до 0) + + f1 / f2; // => 0.5, плюс-минус погрешность потому что, + // цифры с плавающей точкой вычисляются неточно! + + // Модуль + 11 % 3; // => 2 + + // Операции сравнения вам уже знакомы, но в Си нет булевого типа. + // Вместо него используется int. 0 это false, всё остальное это true. + // Операции сравнения всегда возвращают 1 или 0. + 3 == 2; // => 0 (false) + 3 != 2; // => 1 (true) + 3 > 2; // => 1 + 3 < 2; // => 0 + 2 <= 2; // => 1 + 2 >= 2; // => 1 + + // Си это не Питон – операции сравнения могут быть только парными. + int a = 1; + // ОШИБКА: + int between_0_and_2 = 0 < a < 2; + // Правильно: + int between_0_and_2 = 0 < a && a < 2; + + // Логика + !3; // => 0 (логическое НЕ) + !0; // => 1 + 1 && 1; // => 1 (логическое И) + 0 && 1; // => 0 + 0 || 1; // => 1 (лигическое ИЛИ) + 0 || 0; // => 0 + + // Битовые операторы + ~0x0F; // => 0xF0 (побитовое отрицание) + 0x0F & 0xF0; // => 0x00 (побитовое И) + 0x0F | 0xF0; // => 0xFF (побитовое ИЛИ) + 0x04 ^ 0x0F; // => 0x0B (исключающее ИЛИ (XOR)) + 0x01 << 1; // => 0x02 (побитовый сдвиг влево (на 1)) + 0x02 >> 1; // => 0x01 (побитовый сдвиг вправо (на 1)) + + // Будьте осторожны при сдвиге беззнакового int, эти операции не определены: + // - shifting into the sign bit of a signed integer (int a = 1 << 32) + // - сдвиг влево отрицательных чисел (int a = -1 << 2) + // - shifting by an offset which is >= the width of the type of the LHS: + // int a = 1 << 32; // UB if int is 32 bits wide + + /////////////////////////////////////// + // Структуры ветвления + /////////////////////////////////////// + + // Условный оператор + if (0) { + printf("I am never run\n"); + } else if (0) { + printf("I am also never run\n"); + } else { + printf("I print\n"); + } + + // Цикл с предусловием + int ii = 0; + while (ii < 10) { + printf("%d, ", ii++); // инкрементация происходит после того как + // знаечние ii передано ("postincrement") + } // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " + + printf("\n"); + + //Цикл с постусловием + int kk = 0; + do { + printf("%d, ", kk); + } while (++kk < 10); // инкрементация происходит перед тем как + // передаётся знаечние kk ("preincrement") + // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " + + printf("\n"); + + // Цикл со счётчиком + int jj; + for (jj=0; jj < 10; jj++) { + printf("%d, ", jj); + } // => prints "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " + + printf("\n"); + + // Ветвление с множественным выбором + switch (some_integral_expression) { + case 0: // значения должны быть целыми константами (могут быть выражениями) + do_stuff(); + break; // если не написать break; то управление будет передено следующему блоку + case 1: + do_something_else(); + break; + default: + // если не было совпадения, то выполняется блок default: + fputs("ошибка!\n", stderr); + exit(-1); + break; + } + + + /////////////////////////////////////// + // Форматирование вывода + /////////////////////////////////////// + + // Каждое выражение в Си имеет тип, но вы можете привести один тип к другому + // если хотите (с некоторыми константами). + + int x_hex = 0x01; // Вы можете назначать переменные с помощью шеснадцатеричного кода + + // Приведение типов будет пытаться сохранять цифровые значения + printf("%d\n", x_hex); // => Prints 1 + printf("%d\n", (short) x_hex); // => Prints 1 + printf("%d\n", (char) x_hex); // => Prints 1 + + // Типы могут переполняться без предупреждения + printf("%d\n", (unsigned char) 257); // => 1 (Max char = 255 if char is 8 bits long) + + // Для определения максимального значения типов `char`, `signed char` и `unisigned char`, + // соответственно используйте CHAR_MAX, SCHAR_MAX и UCHAR_MAX макросы из + + // Целые типы могут быть приведены к вещественным и наоборот + printf("%f\n", (float)100); // %f formats a float + printf("%lf\n", (double)100); // %lf formats a double + printf("%d\n", (char)100.0); + + /////////////////////////////////////// + // Указатели + /////////////////////////////////////// + + // A pointer is a variable declared to store a memory address. Its declaration will + // also tell you the type of data it points to. You can retrieve the memory address + // of your variables, then mess with them. + + + // Указатель – это переменная которая хранит адрес в памяти. При объявлении указателя указывается тип данных переменной на которую он будет ссылаться. Вы можете получить адрес любой переменной, а потом работать с ним. + + // Используйте & для получения адреса переменной + int x = 0; + printf("%p\n", (void *)&x); // => Напечатает адрес в памяти, где лежит переменная x + // (%p выводит указатель на void *) + + + // Для объявления указателя нужно поставить * перед именем. + int *px, not_a_pointer; // px это указатель на int + px = &x; // сохранит адрес x в px + printf("%p\n", (void *)px); // => Напечатает адрес в памяти, где лежит переменная px + printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer)); + // => Напечатает "8, 4" в 64 битной системе + + // Для того, чтобы получить знаечние по адресу, напечатайте * перед именем. + // Да, использование * при объявлении указателя и получении значения по адресу, + // немного запутано, но вы привыкнете. + printf("%d\n", *px); // => Напечаатет 0, значение перемененной x + + // Вы также можете изменять значение, на которое указывает указатель. + (*px)++; // Инкрементирует значение на которое указывает px на еденицу + printf("%d\n", *px); // => Напечатает 1 + printf("%d\n", x); // => Напечатает 1 + + // массивы хорошо использовать для болшого количества однотипных данных + int x_array[20]; + int xx; + for (xx = 0; xx < 20; xx++) { + x_array[xx] = 20 - xx; + } // Объявление x_array с значениями 20, 19, 18,... 2, 1 + + // Инициализация указателя на int с адресом массива. + int* x_ptr = x_array; + // x_ptr сейчас x_ptr указывает на первый элемент массива (со значением 20). + // Это рабоатет, потому что имя массива возвращает указатель на первый элемент. + // Например, когда массив передаётся в функцию или назначается указателю, он + // невявно преобразуется в указатель. + // Исключения: когда массив является аргументом для оператор '&': + int arr[10]; + int (*ptr_to_arr)[10] = &arr; // &arr не является 'int *'! + // он является "указатель на массив" (из десяти 'int'ов). + // или когда массив это строчный литерал или при объявлении массива символов: + char arr[] = "foobarbazquirk"; + // или когда массив является аргументом `sizeof` или `alignof` операторов: + int arr[10]; + int *ptr = arr; // то же самое что и int *ptr = &arr[0];" + printf("%zu %zu\n", sizeof arr, sizeof ptr); // напечатает "40, 4" или "40, 8" + + // Декрементация и инкрементация указателей зависит от их типа + // (это называется арифметика указателей) + printf("%d\n", *(x_ptr + 1)); // => Напечатает 19 + printf("%d\n", x_array[1]); // => Напечатает 19 + + // Вы также можете динамически выделять несколько боков памяти с помощью + // функции malloc из стандартной библиотеки, которая принимает один + // аргумент типа size_t – количество байт необходимых для выделения. + int *my_ptr = malloc(sizeof(*my_ptr) * 20); + for (xx = 0; xx < 20; xx++) { + *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx + } // Выделяет память для 20, 19, 18, 17... 2, 1 (как int'ы) + + // Работа с памятью с помощью указателей может давать неожиданные и + // непредсказуемые результаты. + printf("%d\n", *(my_ptr + 21)); // => Напечатает кто-нибудь-знает-что? + // Скорей всего программа вылетит. + + // Когда вы закончили работать с памятью, которую ранее выделили, вам необходимо + // освободить её, иначе это может вызвать утечку памяти. + free(my_ptr); + + // Строки это массивы символов, но обычно они представляются как + // указатели на символ (как указатели на первый элемент массива). + // Хорошей практикой считается использование `const char *' при объявлении + // строчоного литерала. При таком подходе литерал не может быть изменён. + // (например "foo"[0] = 'a' вызовет ошибку!) + + const char *my_str = "This is my very own string literal"; + printf("%c\n", *my_str); // => 'T' + + // Это не работает, если строка является массивом + // (потенциально задаваемой с помощью строкового литерала) + // который находиться в перезаписываемой части памяти: + + char foo[] = "foo"; + foo[0] = 'a'; // это выполнится и строка теперь "aoo" + + void function_1() +} // конец функции main() + +/////////////////////////////////////// +// Функции +/////////////////////////////////////// + +// Синтаксис объявления функции: +// <возвращаемый тип> <имя функции>(аргументы) + +int add_two_ints(int x1, int x2) +{ + return x1 + x2; // Используйте return для возврата значения +} + +/* +Данные в функицию передаются "по значению", но никто не мешает +вам передавать в функцию указатели и менять данные по указателям. + +Например: инвертировать строку прямо в функции +*/ + +// void орзначает, что функция ничего не возвражщает +void str_reverse(char *str_in) +{ + char tmp; + int ii = 0; + size_t len = strlen(str_in); // `strlen()` является частью стандартной библиотеки + for (ii = 0; ii < len / 2; ii++) { + tmp = str_in[ii]; + str_in[ii] = str_in[len - ii - 1]; // ii-тый символ с конца + str_in[len - ii - 1] = tmp; + } +} + +char c[] = "This is a test."; +str_reverse(c); +printf("%s\n", c); // => Выведет ".tset a si sihT" + +/////////////////////////////////////// +// Типы и структуры определяемые пользователем +/////////////////////////////////////// + +// typedef исапользуется для задания стандартным типам своих названий +typedef int my_type; +my_type my_type_var = 0; + +// Структыры это просто коллекция данных, память выделяется последовательно, +// в том порядке в котором записаны данные. +struct rectangle { + int width; + int height; +}; + +// sizeof(struct rectangle) == sizeof(int) + sizeof(int) – не всегда верно +// из-за особенностей компиляции (проблема в отступах)[1]. + +void function_1() +{ + struct rectangle my_rec; + + // Доступ к структурам через точку + my_rec.width = 10; + my_rec.height = 20; + + // Вы можете объявить указатель на структуру + struct rectangle *my_rec_ptr = &my_rec; + + // Можно доступаться к структуре и через указатель + (*my_rec_ptr).width = 30; + + // ... или ещё лучше: успользуйте -> оператор для лучшей читабельночти + my_rec_ptr->height = 10; // то же что и "(*my_rec_ptr).height = 10;" +} + +// Вы можете применить typedef к структуре, для удобства +typedef struct rectangle rect; + +int area(rect r) +{ + return r.width * r.height; +} + +// Если вы имеете большую структуру, можно доступаться к ней "по указателю", +// чтобы избежать копирования всей структуры. +int area(const rect *r) +{ + return r->width * r->height; +} + +/////////////////////////////////////// +// Указатели на функции +/////////////////////////////////////// + +/* +At runtime, functions are located at known memory addresses. Function pointers are +much like any other pointer (they just store a memory address), but can be used +to invoke functions directly, and to pass handlers (or callback functions) around. +However, definition syntax may be initially confusing. + +Example: use str_reverse from a pointer +*/ + + +/* +Во время исполнения функции находятся по известным адресам в памяти. +Указатель на функцию может быть использован для непосредственного вызова функции. +Однако синтаксис может сбивать с толку. + +Пример: использование str_reverse по указателю +*/ +void str_reverse_through_pointer(char *str_in) { + // Определение функции через указатель. + void (*f)(char *); // Сигнатура должна полность совпадать с целевой функцией. + f = &str_reverse; // Присвоить фактический адрес (во время исполнения) + // "f = str_reverse;" тоже будет работать. + //Имя функции (как и массива) возвращает указатель на начало. + (*f)(str_in); // Просто вызываем функцию через указатель. + // "f(str_in);" или вот так +} +``` + +## На почитать + +Лучше всего найдите копию [K&R, aka "The C Programming Language"](https://en.wikipedia.org/wiki/The_C_Programming_Language) +Это *книга* написанная создателями Си. Но будьте осторожны, она содержит которые больше не считаются хорошими. + +Другой хороший ресурс: [Learn C the hard way](http://c.learncodethehardway.org/book/). + +Если у вас появился вопрос, почитайте [compl.lang.c Frequently Asked Questions](http://c-faq.com). + +Очень важно использовать правильные отступы и ставить пробелы в нужных местах. +Читаемый код лучше чем красивый или быстрый код. +Чтобы научиться писать хороший код, почитайте [Linux kernel coding stlye](https://www.kernel.org/doc/Documentation/CodingStyle). + +Также не забывайте, что [Google](http://google.com) и [Яндекс](http://yandex.ru) – ваши хорошие друзья. + +[1] http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member -- cgit v1.2.3 From b548dad5ee5d1c13f9cb61d6ce43a3141f7a8004 Mon Sep 17 00:00:00 2001 From: Andrew Popov Date: Sun, 17 Nov 2013 16:35:17 +0400 Subject: [c/ru] some fixes and improves --- ru-ru/c-ru.html.markdown | 87 ++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 50 deletions(-) (limited to 'ru-ru/c-ru.html.markdown') diff --git a/ru-ru/c-ru.html.markdown b/ru-ru/c-ru.html.markdown index 80f79ffd..0b39586a 100644 --- a/ru-ru/c-ru.html.markdown +++ b/ru-ru/c-ru.html.markdown @@ -50,10 +50,10 @@ int main() { // int обычно имеет длину 4 байта int x_int = 0; - // shorts обычно имеет длину 2 байта + // short обычно имеет длину 2 байта short x_short = 0; - // chars гарантированно имеет длину 1 байта + // char гарантированно имеет длину 1 байта char x_char = 0; char y_char = 'y'; // Символьные литералы заключаются в кавычки '' @@ -82,7 +82,7 @@ int main() { int a = 1; // size_t это беззнаковый целый тип который использует как минимум 2 байта // для записи размера объекта - size_t size = sizeof(a++); // a++ считается во время компиляции + size_t size = sizeof(a++); // a++ не выполнится printf("sizeof(a++) = %zu, где a = %d\n", size, a); // выведет строку "sizeof(a++) = 4, где a = 1" (на 32-битной архитектуре) @@ -134,7 +134,7 @@ int main() { // Операторы /////////////////////////////////////// - // Можно использовать множественное объявление + // Можно использовать множественное объявление. int i1 = 1, i2 = 2; float f1 = 1.0, f2 = 2.0; @@ -184,10 +184,9 @@ int main() { 0x02 >> 1; // => 0x01 (побитовый сдвиг вправо (на 1)) // Будьте осторожны при сдвиге беззнакового int, эти операции не определены: - // - shifting into the sign bit of a signed integer (int a = 1 << 32) + // - сдвиг в знаковый бит у целого числа (int a = 1 << 32) // - сдвиг влево отрицательных чисел (int a = -1 << 2) - // - shifting by an offset which is >= the width of the type of the LHS: - // int a = 1 << 32; // UB if int is 32 bits wide + /////////////////////////////////////// // Структуры ветвления @@ -231,7 +230,7 @@ int main() { // Ветвление с множественным выбором switch (some_integral_expression) { - case 0: // значения должны быть целыми константами (могут быть выражениями) + case 0: // значения должны быть целыми константами (и могут быть выражениями) do_stuff(); break; // если не написать break; то управление будет передено следующему блоку case 1: @@ -249,23 +248,23 @@ int main() { // Форматирование вывода /////////////////////////////////////// - // Каждое выражение в Си имеет тип, но вы можете привести один тип к другому - // если хотите (с некоторыми константами). + // Каждое выражение в Си имеет тип, но вы можете привести один тип к другому, + // если хотите (с некоторыми искажениями). - int x_hex = 0x01; // Вы можете назначать переменные с помощью шеснадцатеричного кода + int x_hex = 0x01; // Вы можете назначать переменные с помощью шеснадцатеричного кода. - // Приведение типов будет пытаться сохранять цифровые значения + // Приведение типов будет пытаться сохранять цифровые значения. printf("%d\n", x_hex); // => Prints 1 printf("%d\n", (short) x_hex); // => Prints 1 printf("%d\n", (char) x_hex); // => Prints 1 - // Типы могут переполняться без предупреждения + // Типы могут переполняться без вызова предупреждения. printf("%d\n", (unsigned char) 257); // => 1 (Max char = 255 if char is 8 bits long) // Для определения максимального значения типов `char`, `signed char` и `unisigned char`, // соответственно используйте CHAR_MAX, SCHAR_MAX и UCHAR_MAX макросы из - // Целые типы могут быть приведены к вещественным и наоборот + // Целые типы могут быть приведены к вещественным и наоборот. printf("%f\n", (float)100); // %f formats a float printf("%lf\n", (double)100); // %lf formats a double printf("%d\n", (char)100.0); @@ -274,14 +273,11 @@ int main() { // Указатели /////////////////////////////////////// - // A pointer is a variable declared to store a memory address. Its declaration will - // also tell you the type of data it points to. You can retrieve the memory address - // of your variables, then mess with them. - - - // Указатель – это переменная которая хранит адрес в памяти. При объявлении указателя указывается тип данных переменной на которую он будет ссылаться. Вы можете получить адрес любой переменной, а потом работать с ним. + // Указатель – это переменная которая хранит адрес в памяти. + // При объявлении указателя указывается тип данных переменной на которую он будет ссылаться. + // Вы можете получить адрес любой переменной, а потом работать с ним. - // Используйте & для получения адреса переменной + // Используйте & для получения адреса переменной. int x = 0; printf("%p\n", (void *)&x); // => Напечатает адрес в памяти, где лежит переменная x // (%p выводит указатель на void *) @@ -295,37 +291,37 @@ int main() { // => Напечатает "8, 4" в 64 битной системе // Для того, чтобы получить знаечние по адресу, напечатайте * перед именем. - // Да, использование * при объявлении указателя и получении значения по адресу, + // Да, использование * при объявлении указателя и получении значения по адресу // немного запутано, но вы привыкнете. printf("%d\n", *px); // => Напечаатет 0, значение перемененной x // Вы также можете изменять значение, на которое указывает указатель. - (*px)++; // Инкрементирует значение на которое указывает px на еденицу + (*px)++; // Инкрементирует значение на которое указывает px на единицу printf("%d\n", *px); // => Напечатает 1 printf("%d\n", x); // => Напечатает 1 - // массивы хорошо использовать для болшого количества однотипных данных + // Массивы удобно использовать для болшого количества однотипных данных. int x_array[20]; int xx; for (xx = 0; xx < 20; xx++) { x_array[xx] = 20 - xx; } // Объявление x_array с значениями 20, 19, 18,... 2, 1 - // Инициализация указателя на int с адресом массива. + // Объявление указателя на int с адресом массива. int* x_ptr = x_array; - // x_ptr сейчас x_ptr указывает на первый элемент массива (со значением 20). + // x_ptr сейчас указывает на первый элемент массива (со значением 20). // Это рабоатет, потому что имя массива возвращает указатель на первый элемент. // Например, когда массив передаётся в функцию или назначается указателю, он // невявно преобразуется в указатель. // Исключения: когда массив является аргументом для оператор '&': int arr[10]; int (*ptr_to_arr)[10] = &arr; // &arr не является 'int *'! - // он является "указатель на массив" (из десяти 'int'ов). - // или когда массив это строчный литерал или при объявлении массива символов: + // он является "указателем на массив" (из десяти 'int'ов). + // или когда массив это строчный литерал, используемый при объявлении массива символов: char arr[] = "foobarbazquirk"; // или когда массив является аргументом `sizeof` или `alignof` операторов: int arr[10]; - int *ptr = arr; // то же самое что и int *ptr = &arr[0];" + int *ptr = arr; // то же самое что и "int *ptr = &arr[0];" printf("%zu %zu\n", sizeof arr, sizeof ptr); // напечатает "40, 4" или "40, 8" // Декрементация и инкрементация указателей зависит от их типа @@ -333,7 +329,7 @@ int main() { printf("%d\n", *(x_ptr + 1)); // => Напечатает 19 printf("%d\n", x_array[1]); // => Напечатает 19 - // Вы также можете динамически выделять несколько боков памяти с помощью + // Вы также можете динамически выделять несколько блоков памяти с помощью // функции malloc из стандартной библиотеки, которая принимает один // аргумент типа size_t – количество байт необходимых для выделения. int *my_ptr = malloc(sizeof(*my_ptr) * 20); @@ -347,13 +343,13 @@ int main() { // Скорей всего программа вылетит. // Когда вы закончили работать с памятью, которую ранее выделили, вам необходимо - // освободить её, иначе это может вызвать утечку памяти. + // освободить её, иначе это может вызвать утечку памяти или ошибки. free(my_ptr); // Строки это массивы символов, но обычно они представляются как // указатели на символ (как указатели на первый элемент массива). // Хорошей практикой считается использование `const char *' при объявлении - // строчоного литерала. При таком подходе литерал не может быть изменён. + // строчного литерала. При таком подходе литерал не может быть изменён. // (например "foo"[0] = 'a' вызовет ошибку!) const char *my_str = "This is my very own string literal"; @@ -382,13 +378,13 @@ int add_two_ints(int x1, int x2) } /* -Данные в функицию передаются "по значению", но никто не мешает +Данные в функцию передаются "по значению", но никто не мешает вам передавать в функцию указатели и менять данные по указателям. Например: инвертировать строку прямо в функции */ -// void орзначает, что функция ничего не возвражщает +// void означает, что функция ничего не возвращает void str_reverse(char *str_in) { char tmp; @@ -409,11 +405,11 @@ printf("%s\n", c); // => Выведет ".tset a si sihT" // Типы и структуры определяемые пользователем /////////////////////////////////////// -// typedef исапользуется для задания стандартным типам своих названий +// typedef используется для задания стандартным типам своих названий typedef int my_type; my_type my_type_var = 0; -// Структыры это просто коллекция данных, память выделяется последовательно, +// Структуры это просто коллекция данных, память выделяется последовательно, // в том порядке в котором записаны данные. struct rectangle { int width; @@ -421,7 +417,7 @@ struct rectangle { }; // sizeof(struct rectangle) == sizeof(int) + sizeof(int) – не всегда верно -// из-за особенностей компиляции (проблема в отступах)[1]. +// из-за особенностей компиляции (необычное поведение при отступах)[1]. void function_1() { @@ -441,7 +437,7 @@ void function_1() my_rec_ptr->height = 10; // то же что и "(*my_rec_ptr).height = 10;" } -// Вы можете применить typedef к структуре, для удобства +// Вы можете применить typedef к структуре, для удобства. typedef struct rectangle rect; int area(rect r) @@ -460,16 +456,6 @@ int area(const rect *r) // Указатели на функции /////////////////////////////////////// -/* -At runtime, functions are located at known memory addresses. Function pointers are -much like any other pointer (they just store a memory address), but can be used -to invoke functions directly, and to pass handlers (or callback functions) around. -However, definition syntax may be initially confusing. - -Example: use str_reverse from a pointer -*/ - - /* Во время исполнения функции находятся по известным адресам в памяти. Указатель на функцию может быть использован для непосредственного вызова функции. @@ -477,6 +463,7 @@ Example: use str_reverse from a pointer Пример: использование str_reverse по указателю */ + void str_reverse_through_pointer(char *str_in) { // Определение функции через указатель. void (*f)(char *); // Сигнатура должна полность совпадать с целевой функцией. @@ -491,7 +478,7 @@ void str_reverse_through_pointer(char *str_in) { ## На почитать Лучше всего найдите копию [K&R, aka "The C Programming Language"](https://en.wikipedia.org/wiki/The_C_Programming_Language) -Это *книга* написанная создателями Си. Но будьте осторожны, она содержит которые больше не считаются хорошими. +Это **книга** написанная создателями Си. Но будьте осторожны, она содержит идеи которые больше не считаются хорошими. Другой хороший ресурс: [Learn C the hard way](http://c.learncodethehardway.org/book/). @@ -503,4 +490,4 @@ void str_reverse_through_pointer(char *str_in) { Также не забывайте, что [Google](http://google.com) и [Яндекс](http://yandex.ru) – ваши хорошие друзья. -[1] http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member +[1] http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member \ No newline at end of file -- cgit v1.2.3 From 92faa7ce01ce727a2f7fc6d8bcf407e8547dfe1b Mon Sep 17 00:00:00 2001 From: Andrew Popov Date: Mon, 18 Nov 2013 05:08:17 +0400 Subject: [c/ru] some improves --- ru-ru/c-ru.html.markdown | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) (limited to 'ru-ru/c-ru.html.markdown') diff --git a/ru-ru/c-ru.html.markdown b/ru-ru/c-ru.html.markdown index 0b39586a..59d3c3b5 100644 --- a/ru-ru/c-ru.html.markdown +++ b/ru-ru/c-ru.html.markdown @@ -16,7 +16,7 @@ lang: ru-ru Держите это руководство в памяти и вы сможете использовать Си максимально эффективно. ```c -// Однострочный комментарий начинается с // - доступно только после С99. +// Однострочный комментарий начинается с // - доступен только после С99. /* Многострочный комментарий выглядит так. Работает начиная с С89. @@ -108,12 +108,10 @@ int main() { size_t size = strtoul(buf, NULL, 10); // strtoul парсит строку в беззнаковое целое int var_length_array[size]; // объявление динамического массива printf("sizeof array = %zu\n", sizeof var_length_array); - // Вывод программы (в зависимости от архитектуры) будет таким: // > Enter the array size: 10 // > sizeof array = 40 - // Строка – это просто массив символов, оканчивающийся нулевым (NUL (0x00)) байтом // представляемым в строке специальным символом '\0'. // Нам не нужно вставлять нулевой байт в строковой литерал, @@ -187,7 +185,6 @@ int main() { // - сдвиг в знаковый бит у целого числа (int a = 1 << 32) // - сдвиг влево отрицательных чисел (int a = -1 << 2) - /////////////////////////////////////// // Структуры ветвления /////////////////////////////////////// @@ -243,7 +240,6 @@ int main() { break; } - /////////////////////////////////////// // Форматирование вывода /////////////////////////////////////// @@ -282,7 +278,6 @@ int main() { printf("%p\n", (void *)&x); // => Напечатает адрес в памяти, где лежит переменная x // (%p выводит указатель на void *) - // Для объявления указателя нужно поставить * перед именем. int *px, not_a_pointer; // px это указатель на int px = &x; // сохранит адрес x в px @@ -372,8 +367,7 @@ int main() { // Синтаксис объявления функции: // <возвращаемый тип> <имя функции>(аргументы) -int add_two_ints(int x1, int x2) -{ +int add_two_ints(int x1, int x2) { return x1 + x2; // Используйте return для возврата значения } @@ -385,8 +379,7 @@ int add_two_ints(int x1, int x2) */ // void означает, что функция ничего не возвращает -void str_reverse(char *str_in) -{ +void str_reverse(char *str_in) { char tmp; int ii = 0; size_t len = strlen(str_in); // `strlen()` является частью стандартной библиотеки @@ -417,10 +410,9 @@ struct rectangle { }; // sizeof(struct rectangle) == sizeof(int) + sizeof(int) – не всегда верно -// из-за особенностей компиляции (необычное поведение при отступах)[1]. +// из-за особенностей компиляции ([необычное поведение при отступах][1]). -void function_1() -{ +void function_1() { struct rectangle my_rec; // Доступ к структурам через точку @@ -440,15 +432,13 @@ void function_1() // Вы можете применить typedef к структуре, для удобства. typedef struct rectangle rect; -int area(rect r) -{ +int area(rect r) { return r.width * r.height; } // Если вы имеете большую структуру, можно доступаться к ней "по указателю", // чтобы избежать копирования всей структуры. -int area(const rect *r) -{ +int area(const rect *r) { return r->width * r->height; } @@ -490,4 +480,4 @@ void str_reverse_through_pointer(char *str_in) { Также не забывайте, что [Google](http://google.com) и [Яндекс](http://yandex.ru) – ваши хорошие друзья. -[1] http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member \ No newline at end of file +[1]: http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member \ No newline at end of file -- cgit v1.2.3 From 14d637ddfe16d37de79b6723117f286ecc3d18b8 Mon Sep 17 00:00:00 2001 From: Andrew Popov Date: Mon, 18 Nov 2013 05:14:47 +0400 Subject: [c/ru] 413 line link fix --- ru-ru/c-ru.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ru-ru/c-ru.html.markdown') diff --git a/ru-ru/c-ru.html.markdown b/ru-ru/c-ru.html.markdown index 59d3c3b5..6ef1dc2f 100644 --- a/ru-ru/c-ru.html.markdown +++ b/ru-ru/c-ru.html.markdown @@ -410,7 +410,7 @@ struct rectangle { }; // sizeof(struct rectangle) == sizeof(int) + sizeof(int) – не всегда верно -// из-за особенностей компиляции ([необычное поведение при отступах][1]). +// из-за особенностей компиляции (необычное поведение при отступах)[1]. void function_1() { struct rectangle my_rec; @@ -480,4 +480,4 @@ void str_reverse_through_pointer(char *str_in) { Также не забывайте, что [Google](http://google.com) и [Яндекс](http://yandex.ru) – ваши хорошие друзья. -[1]: http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member \ No newline at end of file +[1] http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member \ No newline at end of file -- cgit v1.2.3 From 79eda34b3398f51f8c029ef2807845379583b009 Mon Sep 17 00:00:00 2001 From: Andrew Popov Date: Fri, 22 Nov 2013 04:40:34 +0400 Subject: [c/ru] some fixes --- ru-ru/c-ru.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ru-ru/c-ru.html.markdown') diff --git a/ru-ru/c-ru.html.markdown b/ru-ru/c-ru.html.markdown index 6ef1dc2f..874e0821 100644 --- a/ru-ru/c-ru.html.markdown +++ b/ru-ru/c-ru.html.markdown @@ -425,7 +425,7 @@ void function_1() { // Можно доступаться к структуре и через указатель (*my_rec_ptr).width = 30; - // ... или ещё лучше: успользуйте -> оператор для лучшей читабельночти + // ... или ещё лучше: используйте оператор -> для лучшей читабельночти my_rec_ptr->height = 10; // то же что и "(*my_rec_ptr).height = 10;" } -- cgit v1.2.3 From 0b2a283db4bc622aaca3c23daa3c39dfd9297db1 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 29 Jan 2014 23:30:28 -0800 Subject: Updated a lot of filenames --- ru-ru/c-ru.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ru-ru/c-ru.html.markdown') diff --git a/ru-ru/c-ru.html.markdown b/ru-ru/c-ru.html.markdown index 874e0821..5988b159 100644 --- a/ru-ru/c-ru.html.markdown +++ b/ru-ru/c-ru.html.markdown @@ -1,6 +1,6 @@ --- language: c -filename: learnc.c +filename: learnc-ru.c contributors: - ["Adam Bard", "http://adambard.com/"] - ["Árpád Goretity", "http://twitter.com/H2CO3_iOS"] @@ -480,4 +480,4 @@ void str_reverse_through_pointer(char *str_in) { Также не забывайте, что [Google](http://google.com) и [Яндекс](http://yandex.ru) – ваши хорошие друзья. -[1] http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member \ No newline at end of file +[1] http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member -- cgit v1.2.3