diff options
author | Andrew Popov <evlogij@gmail.com> | 2013-11-17 16:35:17 +0400 |
---|---|---|
committer | Andrew Popov <evlogij@gmail.com> | 2013-11-17 16:35:17 +0400 |
commit | b548dad5ee5d1c13f9cb61d6ce43a3141f7a8004 (patch) | |
tree | 67cdc95cacda30410175965acfd0f8b79d7c38f3 | |
parent | ed09da6cdd4092e72e0fb094773103f814cb3279 (diff) |
[c/ru] some fixes and improves
-rw-r--r-- | ru-ru/c-ru.html.markdown | 87 |
1 files changed, 37 insertions, 50 deletions
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 макросы из <limits.h> - // Целые типы могут быть приведены к вещественным и наоборот + // Целые типы могут быть приведены к вещественным и наоборот. 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) @@ -461,22 +457,13 @@ 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 -*/ - - -/* Во время исполнения функции находятся по известным адресам в памяти. Указатель на функцию может быть использован для непосредственного вызова функции. Однако синтаксис может сбивать с толку. Пример: использование 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 |