mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-23 09:41:36 +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 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)
|
||||
@ -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
|
Loading…
Reference in New Issue
Block a user