Summary Files Commits Branches @commit @diff @stats
path: root / src
diff options
context:
space:
mode:
Commitfd3df635a72e7c7491a447ba5adea5167cfa38b8 (patch)
Author
 Syndamia <kamen@syndamia.com>
2025-11-23 16:02:40 +0200
Committer
 Syndamia <kamen@syndamia.com>
2025-11-23 16:03:20 +0200
Files1131f0d6defd09cda3ee35b7df39e25391feadf2 /src
syndamia.com-fd3df635a72e7c7491a447ba5adea5167cfa38b8.tar
syndamia.com-fd3df635a72e7c7491a447ba5adea5167cfa38b8.tar.gz
syndamia.com-fd3df635a72e7c7491a447ba5adea5167cfa38b8.zip
Parent40826a9fa6e5c2e08bb6898bef11525e319a79ed (diff)
feat(teachin/upp-2025/cpp-pitfalls): Reorganized sections and added info about VLA and array brace init
1 files changed, 120 insertions, 49 deletions
-rw-r--r--src/teaching/upp-2025/cpp-pitfalls/index.du169
diff --git a/src/teaching/upp-2025/cpp-pitfalls/index.du b/src/teaching/upp-2025/cpp-pitfalls/index.du
index 5e2c118..3f04b01 100644
--- a/src/teaching/upp-2025/cpp-pitfalls/index.du
+++ b/src/teaching/upp-2025/cpp-pitfalls/index.du
@@ -1,13 +1,13 @@
# Капани в C++ - УПП, КН, 2025-2026
-'define expected-reading 13 min
+'define expected-reading 15 min
'define created 22 November 2025
-'define edited 22 November 2025
+'define edited 23 November 2025
[$pagenav]
.warn
Този документ ще бъде обновяван до края на курса.
-Добавки ще бъдат правени!
+Моля, следете за промени!
[$br2]
@@ -17,15 +17,21 @@
.numbered
1. [url #section-2 Записване/връщане на булеви стойности]
-2. [url #section-3 Типове на аритметични операции]
+2. [url #section-3 Оператори]
+ .numbered
+ 1. [url #section-4 Типове на аритметични операции]
+ 2. [url #section-5 Лениво оценяване на булеви изрази]
3. [url #undefined-behaviour Undefined behaviour]
.numbered
- 1. [url #section-4 Приоритет на скоби спрямо аритметични оператори]
+ 1. [url #section-6 Приоритет на скоби спрямо аритметични оператори]
-4. [url #section-5 Лениво оценяване на булеви изрази]
-5. [url #section-6 Връщане на масиви/матрици]
-6. [url #section-7 Тип на матрици]
+5. [url #section-7 Масиви и матрици]
+ .numbered
+ 1. [url #section-8 Връщане на масиви]
+ 2. [url #section-9 Инициализация на масиви]
+ 3. [url #section-10 Масиви с неконстантен размер]
+ 4. [url #-int73-vs-int3-vs-int Тип на матрици (int[7\][3\] vs int(*)[3\] vs int**)]
@@ -103,7 +109,9 @@ bool f() {
return !condition;
}
-## Типове на аритметични операции
+## Оператори
+
+### Типове на аритметични операции
При събиране, изваждане, умножение и деление, винаги имплицитно се конвертира към най-големия тип!
И върната стойност е от този тип.
@@ -126,6 +134,45 @@ std::cout << (double)(x / y); // резултата от деление вече
std::cout << ((double)x / y); // едното вече е с плаваща запетая,
// резултата също става double и няма закръгляне
+## Лениво оценяване на булеви изрази
+
+Всички булеви изрази се оценяват (изпълняват) лениво (мързеливо).
+Това означава, че ако израза е в състояние, където не е нужно да проверим останалите условия, няма да ги проверим.
+
+Двата главни примера се срещат при оператори "и" и "или".
+
+[$br2]
+
+```c++
+a || b || c || d
+
+Ако `[a]` е истина, тогава другите няма да се изпълнят, защото тяхната стойност не е от значение, общия израз ще си остане истина.
+Аналогично, ако `[a]` е лъжа, но `[b]` е истина, тогава `[c]` и `[d]` няма да се изпълнят.
+
+[$br2]
+
+```c++
+a && b && c && d
+
+Напълно еквивалентно работи и "или".
+Ако `[a]` е лъжа, тогава другите няма да се изпълнят, защото общия израз ще си остане лъжа.
+
+[$br2]
+
+Това е релевантно когато използваме присвояващи оператори в логически условия, например:
+
+```c++
+if (condition1 && ((myvar += 5) == 8))
+
+и когато използваме функции:
+
+```c++
+if (condition1 && f())
+
+И в двата случая, ако `[condition1]` е лъжа, тогава присвояването и извикването на функцията няма да се изпълнят.
+
+Дали това е желан ефект или не зависи от кода.
+
## Undefined behaviour
C++ наследява идеята от C, че някои неща в стандарта на езика не са дефинирани.
@@ -174,46 +221,12 @@ int y = (x += 5) * (x += 1) * (x -= 8);
Първия метод се изпълнява от компилатора на Visual Studio, втория метод от gcc (много популярен C++ компилатор под Linux/MacOS).
-## Лениво оценяване на булеви изрази
-
-Всички булеви изрази се оценяват (изпълняват) лениво (мързеливо).
-Това означава, че ако израза е в състояние, където не е нужно да проверим останалите условия, няма да ги проверим.
-
-Двата главни примера се срещат при оператори "и" и "или".
-
-[$br2]
-
-```c++
-a || b || c || d
-
-Ако `[a]` е истина, тогава другите няма да се изпълнят, защото тяхната стойност не е от значение, общия израз ще си остане истина.
-Аналогично, ако `[a]` е лъжа, но `[b]` е истина, тогава `[c]` и `[d]` няма да се изпълнят.
-
-[$br2]
-
-```c++
-a && b && c && d
-
-Напълно еквивалентно работи и "или".
-Ако `[a]` е лъжа, тогава другите няма да се изпълнят, защото общия израз ще си остане лъжа.
-
-[$br2]
-
-Това е релевантно когато използваме присвояващи оператори в логически условия, например:
-
-```c++
-if (condition1 && ((myvar += 5) == 8))
-
-и когато използваме функции:
-
-```c++
-if (condition1 && f())
-
-И в двата случая, ако `[condition1]` е лъжа, тогава присвояването и извикването на функцията няма да се изпълнят.
+## Масиви и матрици
-Дали това е желан ефект или не зависи от кода.
+.important
+Всички неща, които важат за статично-заделени масиви (`[int arr[5];]`), важат и за статично-заделени матрици (`[int mat[5][6];]`)!
-## Връщане на масиви/матрици
+### Връщане на масиви
Всяка променлива, която е декларирана или дефинирана (без помощта на динамича памет) съществува в определен обхват (scope) и всички обхвати в него.
@@ -278,9 +291,66 @@ int main() {
/* ... */
}
-Всичко това важи и при матрици.
+### Инициализация на масиви
+
+Често използваме нотацията за къдрави скоби да инициализираме елементите на масив:
+
+```c++
+int arr1[3] = { 1, 2, 3 };
+
+Ако искаме да напълним масива с нули, често правим:
+
+```c++
+int arr2[3] = { 0 };
+
+Обаче, ако примерно се опитаме да напълним масива с единици, тогава следното =[няма]= да проработи:
+
+```c++
+int arr3[3] = { 1 };
+
+[$br2]
+
+Инициализацията чрез къдрави скоби работи по следния начин: всички елементи в масива се попълват спрямо подадените елементи в къдравите скоби.
+
+=[Ако в къдравите скоби има по-малко елементи отколкото е голям масива, останалите елементи се попълват с нули!]=
+
+Тоест, в `[arr2]` ние попъляваме първия елемент да е нула, и останалите стават нули по подразбиране.
+В `[arr3]` попълваме първия елемент да е единица и останалите стават нули по подразбиране.
+
+Това навява на мисълта, дали не можем в C++ да пропуснем записването на първия елемент, когато искаме всичко да е нула?
+Можем!
+
+```c++
+int arr4[3] = { }; // попълва arr4 с нули
+
+[$br2]
+
+Коректния метод, ако искаме да напълним масива с друг елемент, е да използваме цикъл.
+Например:
+
+```c++
+for (int i = 0; i < 3; i++)
+ arr[i] = 1;
+
+### Масиви с неконстантен размер
+
+=[Не]= позволяваме в този курс да правите такива неща:
-## Тип на матрици
+```c++
+int size;
+std::cin >> size;
+int arr[size];
+
+Въпреки че това *[може]* да се компилира и да работи.
+
+Причината е защото този тип масиви се наричат [url https://en.wikipedia.org/wiki/Variable-length_array VLA].
+И в =[C++ VLA-ове не са позволени!]=
+
+Въпреки това, много компилатори ги поддържат, главно защото много C++ компилатори са и C компилатори (и VLA-ове са позволени в C).
+
+=[Единствения]= коректен метод да създадем масив, чиито размер не знаем предварително, е чрез динамича памет.
+
+### Тип на матрици (int[7][3] vs int(*)[3] vs int**)
```c++
int mat[7][3];
@@ -399,3 +469,4 @@ void g(int (*matrix)[2]) {
Тогава, матриците ни няма да бъдат последователност от елементи, ами ще бъдат последователност от (указатели към) масиви.
Тоест всеки ред в матрицата ще може да се намира на напълно различни позиции в паметта.
+