===== 4. Pole, ukazatel, textový řetězec ===== * prezentace: {{courses:b3b36prg:lectures:b3b36prg-lec04-slides.pdf|}} * zkrácená verze: {{courses:b3b36prg:lectures:b3b36prg-lec04-handout.pdf|}} * zkrácená verze 2x2: {{courses:b3b36prg:lectures:b3b36prg-lec04-handout-2x2.pdf|}} * zkrácená verze 3x3: {{courses:b3b36prg:lectures:b3b36prg-lec04-handout-3x3.pdf|}} * přiložené demonstrační programy: {{:courses:b3b36prg:lectures:b3b36prg-lec04-codes.zip|}} --- //[[faiglj@fel.cvut.cz|Jan Faigl]] 2026/03/23 08:27// ++++ Příklad z přednášky | Příklad na přednášce demonstrující použití kompilace s debug, např. ''clang -g'' a ''valgrind'' pro rychlé nalezení problémového místa nám pomohl ukázat na zápis mimo přidělenou paměť na řádku 13, tj. ''sieve[i*j] = 0;'' 10 for (int i = 2; i < 1000000; ++i) { 11 if (sieve[i]) { 12 for (int j = i; i*j < 1000000; ++j) { 13 sieve[i*j] = 0; 14 } 15 } 16 } Přestože řádek vypadá relativně neškodně, je nutné uvažovat jakou hodnotu bude mít výraz ''i*j'' pokud jsou obě proměnné typu ''int''. Zcela jistě se totiž hodnota výrazu, např. 47000 * 47000, do rozsahu typu ''int'' reprezentovaného 32-bity nevejde. Možných řešení je více, jedno z nich může být využít automatické typové konverze na větší z typů, např. 10 for (int i = 2; i < 1000000; ++i) { 11 if (sieve[i]) { 12 for (long j = i; i*j < 1000000; ++j) { 13 sieve[i*j] = 0; 14 } 15 } 16 } Rozdíl je na řádku 12 v použití typu ''long'' pro řídicí proměnnou ''j''. V tomto případě je hodnota výrazu ''i*j'' typu ''long'' a problém je vyřešen. Každopádně mnohonásobné použití magické konstanty ''1000000'' lze vhodně nahradit např. #define SIEVE_SIZE 1000000 ++++ ++++ Dotazy z přednášky | Q: //Co udělá ''realloc()'' při zmenšení velikost nebo nastavení velikosti na 0?// Zmenší alokované místo a v případě 0, např. ''realloc(ptr, 0);'' uvolní paměť a odpovídá tak volání ''free(ptr);''. Q: //Je nutné nebo vhodné explicitně typovat ukazatel návratové hodnoty z volání funkce ''malloc''()?// Vyloženě nutné to v současných verzích Cčka není, přestože pro některé kompilátory (zvláště pak před standarem) to nutné bylo. V současné době je typ ''void*'' chápan jako generický ukazatel, jehož přetypování na konktrétní typ ukazatel na proměnné příslušné typu je zřejmé dle typu proměnné a není tak nutné explicitní přetypování uvádět. Jestli je vhodné explicitně přetypovat, tak na to se názory různí. Například v knize //S.G.Kochan: Programming in C (3rd Edition), Sams Publishing, 2005// je uváděn ''malloc'' vždy s explicitním přetypováním: int *a = (int*)malloc(10 * sizeof(int)); Naproti tomu v knize //K.N. King: C Programming A Modern Approach, Second Edition. W. W. Norton & Company, Inc., 2008// je preferována varianta bez přetypování: int *b = malloc(10 * sizeof(int)); Obě varianty jsou přípustné, argumenty proti explicitnímu přetypování jsou uváděny například: přehlednější kód a je to zbytečné, neboť dochází k přetypování automaticky. Na druhé straně relativně silné argumenty pro explicitní přetypování uvedené v diskusi [[http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc]] jsou například: You do cast, because: * It makes your code more portable between C and C++, and as SO experience shows, a great many programmers claim they are writing in C when they are really writing in C++ (or C plus local compiler extensions). * Failing to do so can hide an error: note all the SO examples of confusing when to write type * versus type **. * The idea that it keeps you from noticing you failed to #include an appropriate header file misses the forest for the trees. It's the same as saying "don't worry about the fact you failed to ask the compiler to complain about not seeing prototypes -- that pesky stdlib.h is the REAL important thing to remember!" * It forces an extra cognitive cross-check. It puts the (alleged) desired type right next to the arithmetic you're doing for the raw size of that variable. I bet you could do an SO study that shows that malloc() bugs are caught much faster when there's a cast. As with assertions, annotations that reveal intent decrease bugs. * Repeating yourself in a way that the machine can check is often a great idea. In fact, that's what an assertion is, and this use of cast is an assertion. Assertions are still the most general technique we have for getting code correct, since Turing came up with the idea so many years ago. Je to tak spíše věc osobního vkusu, preferencí, případně používaného kódovacího stylu. ++++