Search
— 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;
clang -g
valgrind
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ř.
i*j
int
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.
long
j
Každopádně mnohonásobné použití magické konstanty 1000000 lze vhodně nahradit např.
1000000
#define SIEVE_SIZE 1000000
Dotazy z přednášky
Q: Co udělá realloc() při zmenšení velikost nebo nastavení velikosti na 0?
realloc()
Zmenší alokované místo a v případě 0, např. realloc(ptr, 0); uvolní paměť a odpovídá tak volání free(ptr);.
realloc(ptr, 0);
free(ptr);
Q: Je nutné nebo vhodné explicitně typovat ukazatel návratové hodnoty z volání funkce malloc()?
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:
void*
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:
Je to tak spíše věc osobního vkusu, preferencí, případně používaného kódovacího stylu.