mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-23 17:41:41 +00:00
[c/ru] some fixes and improves
This commit is contained in:
parent
ed09da6cdd
commit
b548dad5ee
@ -50,10 +50,10 @@ int main() {
|
|||||||
// int обычно имеет длину 4 байта
|
// int обычно имеет длину 4 байта
|
||||||
int x_int = 0;
|
int x_int = 0;
|
||||||
|
|
||||||
// shorts обычно имеет длину 2 байта
|
// short обычно имеет длину 2 байта
|
||||||
short x_short = 0;
|
short x_short = 0;
|
||||||
|
|
||||||
// chars гарантированно имеет длину 1 байта
|
// char гарантированно имеет длину 1 байта
|
||||||
char x_char = 0;
|
char x_char = 0;
|
||||||
char y_char = 'y'; // Символьные литералы заключаются в кавычки ''
|
char y_char = 'y'; // Символьные литералы заключаются в кавычки ''
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ int main() {
|
|||||||
int a = 1;
|
int a = 1;
|
||||||
// size_t это беззнаковый целый тип который использует как минимум 2 байта
|
// size_t это беззнаковый целый тип который использует как минимум 2 байта
|
||||||
// для записи размера объекта
|
// для записи размера объекта
|
||||||
size_t size = sizeof(a++); // a++ считается во время компиляции
|
size_t size = sizeof(a++); // a++ не выполнится
|
||||||
printf("sizeof(a++) = %zu, где a = %d\n", size, a);
|
printf("sizeof(a++) = %zu, где a = %d\n", size, a);
|
||||||
// выведет строку "sizeof(a++) = 4, где a = 1" (на 32-битной архитектуре)
|
// выведет строку "sizeof(a++) = 4, где a = 1" (на 32-битной архитектуре)
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ int main() {
|
|||||||
// Операторы
|
// Операторы
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
|
|
||||||
// Можно использовать множественное объявление
|
// Можно использовать множественное объявление.
|
||||||
int i1 = 1, i2 = 2;
|
int i1 = 1, i2 = 2;
|
||||||
float f1 = 1.0, f2 = 2.0;
|
float f1 = 1.0, f2 = 2.0;
|
||||||
|
|
||||||
@ -184,10 +184,9 @@ int main() {
|
|||||||
0x02 >> 1; // => 0x01 (побитовый сдвиг вправо (на 1))
|
0x02 >> 1; // => 0x01 (побитовый сдвиг вправо (на 1))
|
||||||
|
|
||||||
// Будьте осторожны при сдвиге беззнакового int, эти операции не определены:
|
// Будьте осторожны при сдвиге беззнакового int, эти операции не определены:
|
||||||
// - shifting into the sign bit of a signed integer (int a = 1 << 32)
|
// - сдвиг в знаковый бит у целого числа (int a = 1 << 32)
|
||||||
// - сдвиг влево отрицательных чисел (int a = -1 << 2)
|
// - сдвиг влево отрицательных чисел (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) {
|
switch (some_integral_expression) {
|
||||||
case 0: // значения должны быть целыми константами (могут быть выражениями)
|
case 0: // значения должны быть целыми константами (и могут быть выражениями)
|
||||||
do_stuff();
|
do_stuff();
|
||||||
break; // если не написать break; то управление будет передено следующему блоку
|
break; // если не написать break; то управление будет передено следующему блоку
|
||||||
case 1:
|
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", x_hex); // => Prints 1
|
||||||
printf("%d\n", (short) x_hex); // => Prints 1
|
printf("%d\n", (short) x_hex); // => Prints 1
|
||||||
printf("%d\n", (char) 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)
|
printf("%d\n", (unsigned char) 257); // => 1 (Max char = 255 if char is 8 bits long)
|
||||||
|
|
||||||
// Для определения максимального значения типов `char`, `signed char` и `unisigned char`,
|
// Для определения максимального значения типов `char`, `signed char` и `unisigned char`,
|
||||||
// соответственно используйте CHAR_MAX, SCHAR_MAX и UCHAR_MAX макросы из <limits.h>
|
// соответственно используйте CHAR_MAX, SCHAR_MAX и UCHAR_MAX макросы из <limits.h>
|
||||||
|
|
||||||
// Целые типы могут быть приведены к вещественным и наоборот
|
// Целые типы могут быть приведены к вещественным и наоборот.
|
||||||
printf("%f\n", (float)100); // %f formats a float
|
printf("%f\n", (float)100); // %f formats a float
|
||||||
printf("%lf\n", (double)100); // %lf formats a double
|
printf("%lf\n", (double)100); // %lf formats a double
|
||||||
printf("%d\n", (char)100.0);
|
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;
|
int x = 0;
|
||||||
printf("%p\n", (void *)&x); // => Напечатает адрес в памяти, где лежит переменная x
|
printf("%p\n", (void *)&x); // => Напечатает адрес в памяти, где лежит переменная x
|
||||||
// (%p выводит указатель на void *)
|
// (%p выводит указатель на void *)
|
||||||
@ -295,37 +291,37 @@ int main() {
|
|||||||
// => Напечатает "8, 4" в 64 битной системе
|
// => Напечатает "8, 4" в 64 битной системе
|
||||||
|
|
||||||
// Для того, чтобы получить знаечние по адресу, напечатайте * перед именем.
|
// Для того, чтобы получить знаечние по адресу, напечатайте * перед именем.
|
||||||
// Да, использование * при объявлении указателя и получении значения по адресу,
|
// Да, использование * при объявлении указателя и получении значения по адресу
|
||||||
// немного запутано, но вы привыкнете.
|
// немного запутано, но вы привыкнете.
|
||||||
printf("%d\n", *px); // => Напечаатет 0, значение перемененной x
|
printf("%d\n", *px); // => Напечаатет 0, значение перемененной x
|
||||||
|
|
||||||
// Вы также можете изменять значение, на которое указывает указатель.
|
// Вы также можете изменять значение, на которое указывает указатель.
|
||||||
(*px)++; // Инкрементирует значение на которое указывает px на еденицу
|
(*px)++; // Инкрементирует значение на которое указывает px на единицу
|
||||||
printf("%d\n", *px); // => Напечатает 1
|
printf("%d\n", *px); // => Напечатает 1
|
||||||
printf("%d\n", x); // => Напечатает 1
|
printf("%d\n", x); // => Напечатает 1
|
||||||
|
|
||||||
// массивы хорошо использовать для болшого количества однотипных данных
|
// Массивы удобно использовать для болшого количества однотипных данных.
|
||||||
int x_array[20];
|
int x_array[20];
|
||||||
int xx;
|
int xx;
|
||||||
for (xx = 0; xx < 20; xx++) {
|
for (xx = 0; xx < 20; xx++) {
|
||||||
x_array[xx] = 20 - xx;
|
x_array[xx] = 20 - xx;
|
||||||
} // Объявление x_array с значениями 20, 19, 18,... 2, 1
|
} // Объявление x_array с значениями 20, 19, 18,... 2, 1
|
||||||
|
|
||||||
// Инициализация указателя на int с адресом массива.
|
// Объявление указателя на int с адресом массива.
|
||||||
int* x_ptr = x_array;
|
int* x_ptr = x_array;
|
||||||
// x_ptr сейчас x_ptr указывает на первый элемент массива (со значением 20).
|
// x_ptr сейчас указывает на первый элемент массива (со значением 20).
|
||||||
// Это рабоатет, потому что имя массива возвращает указатель на первый элемент.
|
// Это рабоатет, потому что имя массива возвращает указатель на первый элемент.
|
||||||
// Например, когда массив передаётся в функцию или назначается указателю, он
|
// Например, когда массив передаётся в функцию или назначается указателю, он
|
||||||
// невявно преобразуется в указатель.
|
// невявно преобразуется в указатель.
|
||||||
// Исключения: когда массив является аргументом для оператор '&':
|
// Исключения: когда массив является аргументом для оператор '&':
|
||||||
int arr[10];
|
int arr[10];
|
||||||
int (*ptr_to_arr)[10] = &arr; // &arr не является 'int *'!
|
int (*ptr_to_arr)[10] = &arr; // &arr не является 'int *'!
|
||||||
// он является "указатель на массив" (из десяти 'int'ов).
|
// он является "указателем на массив" (из десяти 'int'ов).
|
||||||
// или когда массив это строчный литерал или при объявлении массива символов:
|
// или когда массив это строчный литерал, используемый при объявлении массива символов:
|
||||||
char arr[] = "foobarbazquirk";
|
char arr[] = "foobarbazquirk";
|
||||||
// или когда массив является аргументом `sizeof` или `alignof` операторов:
|
// или когда массив является аргументом `sizeof` или `alignof` операторов:
|
||||||
int arr[10];
|
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"
|
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_ptr + 1)); // => Напечатает 19
|
||||||
printf("%d\n", x_array[1]); // => Напечатает 19
|
printf("%d\n", x_array[1]); // => Напечатает 19
|
||||||
|
|
||||||
// Вы также можете динамически выделять несколько боков памяти с помощью
|
// Вы также можете динамически выделять несколько блоков памяти с помощью
|
||||||
// функции malloc из стандартной библиотеки, которая принимает один
|
// функции malloc из стандартной библиотеки, которая принимает один
|
||||||
// аргумент типа size_t – количество байт необходимых для выделения.
|
// аргумент типа size_t – количество байт необходимых для выделения.
|
||||||
int *my_ptr = malloc(sizeof(*my_ptr) * 20);
|
int *my_ptr = malloc(sizeof(*my_ptr) * 20);
|
||||||
@ -347,13 +343,13 @@ int main() {
|
|||||||
// Скорей всего программа вылетит.
|
// Скорей всего программа вылетит.
|
||||||
|
|
||||||
// Когда вы закончили работать с памятью, которую ранее выделили, вам необходимо
|
// Когда вы закончили работать с памятью, которую ранее выделили, вам необходимо
|
||||||
// освободить её, иначе это может вызвать утечку памяти.
|
// освободить её, иначе это может вызвать утечку памяти или ошибки.
|
||||||
free(my_ptr);
|
free(my_ptr);
|
||||||
|
|
||||||
// Строки это массивы символов, но обычно они представляются как
|
// Строки это массивы символов, но обычно они представляются как
|
||||||
// указатели на символ (как указатели на первый элемент массива).
|
// указатели на символ (как указатели на первый элемент массива).
|
||||||
// Хорошей практикой считается использование `const char *' при объявлении
|
// Хорошей практикой считается использование `const char *' при объявлении
|
||||||
// строчоного литерала. При таком подходе литерал не может быть изменён.
|
// строчного литерала. При таком подходе литерал не может быть изменён.
|
||||||
// (например "foo"[0] = 'a' вызовет ошибку!)
|
// (например "foo"[0] = 'a' вызовет ошибку!)
|
||||||
|
|
||||||
const char *my_str = "This is my very own string literal";
|
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)
|
void str_reverse(char *str_in)
|
||||||
{
|
{
|
||||||
char tmp;
|
char tmp;
|
||||||
@ -409,11 +405,11 @@ printf("%s\n", c); // => Выведет ".tset a si sihT"
|
|||||||
// Типы и структуры определяемые пользователем
|
// Типы и структуры определяемые пользователем
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
|
|
||||||
// typedef исапользуется для задания стандартным типам своих названий
|
// typedef используется для задания стандартным типам своих названий
|
||||||
typedef int my_type;
|
typedef int my_type;
|
||||||
my_type my_type_var = 0;
|
my_type my_type_var = 0;
|
||||||
|
|
||||||
// Структыры это просто коллекция данных, память выделяется последовательно,
|
// Структуры это просто коллекция данных, память выделяется последовательно,
|
||||||
// в том порядке в котором записаны данные.
|
// в том порядке в котором записаны данные.
|
||||||
struct rectangle {
|
struct rectangle {
|
||||||
int width;
|
int width;
|
||||||
@ -421,7 +417,7 @@ struct rectangle {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// sizeof(struct rectangle) == sizeof(int) + sizeof(int) – не всегда верно
|
// sizeof(struct rectangle) == sizeof(int) + sizeof(int) – не всегда верно
|
||||||
// из-за особенностей компиляции (проблема в отступах)[1].
|
// из-за особенностей компиляции (необычное поведение при отступах)[1].
|
||||||
|
|
||||||
void function_1()
|
void function_1()
|
||||||
{
|
{
|
||||||
@ -441,7 +437,7 @@ void function_1()
|
|||||||
my_rec_ptr->height = 10; // то же что и "(*my_rec_ptr).height = 10;"
|
my_rec_ptr->height = 10; // то же что и "(*my_rec_ptr).height = 10;"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Вы можете применить typedef к структуре, для удобства
|
// Вы можете применить typedef к структуре, для удобства.
|
||||||
typedef struct rectangle rect;
|
typedef struct rectangle rect;
|
||||||
|
|
||||||
int area(rect r)
|
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 по указателю
|
Пример: использование str_reverse по указателю
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void str_reverse_through_pointer(char *str_in) {
|
void str_reverse_through_pointer(char *str_in) {
|
||||||
// Определение функции через указатель.
|
// Определение функции через указатель.
|
||||||
void (*f)(char *); // Сигнатура должна полность совпадать с целевой функцией.
|
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)
|
Лучше всего найдите копию [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/).
|
Другой хороший ресурс: [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) – ваши хорошие друзья.
|
Также не забывайте, что [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
|
Loading…
Reference in New Issue
Block a user