diff options
| Commit | fd3df635a72e7c7491a447ba5adea5167cfa38b8 (patch) | |
|---|---|---|
| Author | 2025-11-23 16:02:40 +0200 | |
| Committer | 2025-11-23 16:03:20 +0200 | |
| Files | 1131f0d6defd09cda3ee35b7df39e25391feadf2 | |
| syndamia.com-fd3df635a72e7c7491a447ba5adea5167cfa38b8.tar syndamia.com-fd3df635a72e7c7491a447ba5adea5167cfa38b8.tar.gz syndamia.com-fd3df635a72e7c7491a447ba5adea5167cfa38b8.zip | ||
| Parent | 40826a9fa6e5c2e08bb6898bef11525e319a79ed (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.du | 169 |
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]) { Тогава, матриците ни няма да бъдат последователност от елементи, ами ще бъдат последователност от (указатели към) масиви. Тоест всеки ред в матрицата ще може да се намира на напълно различни позиции в паметта. + |