Byla vydána beta verze openSUSE Leap 16. Ve výchozím nastavení s novým instalátorem Agama.
Devadesátková hra Brány Skeldalu prošla portací a je dostupná na platformě Steam. Vyšel i parádní blog autora o portaci na moderní systémy a platformy včetně Linuxu.
Lidi dělají divné věci. Například spouští Linux v Excelu. Využít je emulátor RISC-V mini-rv32ima sestavený jako knihovna DLL, která je volaná z makra VBA (Visual Basic for Applications).
Revolut nabídne neomezený mobilní tarif za 12,50 eur (312 Kč). Aktuálně startuje ve Velké Británii a Německu.
Společnost Amazon miliardáře Jeffa Bezose vypustila na oběžnou dráhu první várku družic svého projektu Kuiper, který má z vesmíru poskytovat vysokorychlostní internetové připojení po celém světě a snažit se konkurovat nyní dominantnímu Starlinku nejbohatšího muže planety Elona Muska.
Poslední aktualizací začal model GPT-4o uživatelům příliš podlézat. OpenAI jej tak vrátila k předchozí verzi.
Google Chrome 136 byl prohlášen za stabilní. Nejnovější stabilní verze 136.0.7103.59 přináší řadu novinek z hlediska uživatelů i vývojářů. Podrobný přehled v poznámkách k vydání. Opraveno bylo 8 bezpečnostních chyb. Vylepšeny byly také nástroje pro vývojáře.
Homebrew (Wikipedie), správce balíčků pro macOS a od verze 2.0.0 také pro Linux, byl vydán ve verzi 4.5.0. Na stránce Homebrew Formulae lze procházet seznamem balíčků. K dispozici jsou také různé statistiky.
Byl vydán Mozilla Firefox 138.0. Přehled novinek v poznámkách k vydání a poznámkách k vydání pro vývojáře. Řešeny jsou rovněž bezpečnostní chyby. Nový Firefox 138 je již k dispozici také na Flathubu a Snapcraftu.
Šestnáctý ročník ne-konference jOpenSpace se koná 3. – 5. října 2025 v Hotelu Antoň v Telči. Pro účast je potřeba vyplnit registrační formulář. Ne-konference neznamená, že se organizátorům nechce připravovat program, ale naopak dává prostor všem pozvaným, aby si program sami složili z toho nejzajímavějšího, čím se v poslední době zabývají nebo co je oslovilo. Obsah, který vytvářejí všichni účastníci, se skládá z desetiminutových
… více »int x = 1; int *ip; /* deklarace ukazatele */ ip = &x; /* ip je 0x7ffd87ef82b4 */ *ip = 0; /* x je 0 */Zvýšení hodnoty, na kterou ip ukazuje:
(*ip)++; /* x je 1 */ ++*ip; /* x je 2 */Ukazatel ukazuje na specifický datový typ, s výjimkou ukazatele na void, ten může ukazovat na jakýkoliv typ, ale nesmí být dereferencován. Rovněž nesmí být dereferencován ukazatel, který má hodnotu NULL.
int *ip = &x;
int a[10]; int *pa; pa = &a[0];Nyní přiřazení
x = *pa;zkopíruje obsah a[0] do x.
pa = &a[0];a
pa = a;jsou ekvivalentní.
int *pa = a;
int a = 3; int b = 5; swap(&a, &b); void swap(int *px, int *py) { int temp; temp = *px; *px = *py; *py = temp; }Pokud funkci předáváme pole, předáváme adresu prvního prvku.
int strlen(char *s) { int n; for (n = 0; *s != '\0'; s++) n++; return n; }Všechna tato volání fungují:
strlen("hello world"); /* retezcova konstanta */ strlen(array); /* char array[100]; */ strlen(ptr); /* char *ptr; */Parametr char *s ve funkci strlen můžeme napsat i jako char s[], nicméně dáváme přednost prvnímu způsobu, jelikož přesněji vyjadřuje, že je parametrem ukazatel.
f(&a[2]);nebo
f(a+2);předají funkci f adresu podpole, které začíná na a[2].
printf("hello, world\n");Ale lze je definovat i jako běžné proměnné:
char *greeting; greeting = "hello, world";nebo přímo
char *greeting = "hello, world";Na rozdíl od pole se znaky v řetězcových konstantách nesmějí měnit, změna znaku způsobí nedefinované chování. Nicméně je možné změnit adresu ukazatele, aby ukazoval někam jinam.
char *colors[] = { "red", "green", "blue", NULL };
char *estrdup(char *s) { char *t; if ((t = (char *) malloc(strlen(s)+1)) == NULL) { printf("estrdup(\"%.20s\") failed!\n", s); return NULL; } strcpy(t, s); return t; }Funkce malloc alokuje dostatek místa, včetně nulového znaku, pro řetězec (pole znaků) s a funkce strcpy tento řetězec na toto místo zkopíruje.
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXLINES 5000 char *lines[MAXLINES]; int readlines(char *lines[], int maxlines); void printlines(char *lines[], int n); int main() { int nlines; if ((nlines = readlines(lines, MAXLINES)) < 0) { printf("readlines() failed!\n"); return 1; } printlines(lines, nlines); return 0; } #define MAXBUF 1000 char *estrdup(char *); int readlines(char *lines[], int maxlines) { char buf[MAXBUF], *s; int nlines = 0; while (fgets(buf, MAXBUF, stdin) != NULL) { if (nlines >= maxlines || (s = estrdup(buf)) == NULL) return -1; if (s[strlen(s)-1] == '\n') s[strlen(s)-1] = '\0'; lines[nlines++] = s; } return nlines; } void printlines(char *lines[], int n) { while (n-- > 0) printf("%s\n", *lines++); }Definice char *lines[MAXLINES] představuje pole ukazatelů a funkce estrdup ukazatelům během načítání jednotlivých řádků přiděluje paměť.
int readlines(char *lines[], int maxlines)je možná napsat i jako:
int readlines(char **lines, int maxlines)Vzhledem k tomu, že název pole je adresa prvního prvku a v tomto případě je prvním prvkem ukazatel, předáváme adresu ukazatele, což odpovídá parametru char **lines (ukazatel na ukazatel typu char).
long strtol(const char *s, char **endp, int base)Funkce get_long načítá řetezec ze standardního vstupu a poté jej převede na číslo typu long. Pokud řetězec obsahuje nečíselné znaky, funkce vrátí chybu.
int get_long(long *x) { enum { MAX = 20 }; char s[MAX], *endp; if (fgets(s, MAX, stdin) == NULL) { printf("get_long() exit 1\n"); exit(1); } if (s[strlen(s)-1] == '\n') s[strlen(s)-1] = '\0'; errno = 0; *x = strtol(s, &endp, 10); if (errno != 0 || *endp != '\0' || *s == '\0') { printf("bad input!\n"); return 0; } return 1; }Možné použití funkce get_long:
long x; while (!get_long(&x)) ;Pole ukazatelů lze vytvořit i dynamicky. Funkce alloc2d alokuje dvourozměrné pole typu long.
long **alloc2d(size_t r, size_t c) { long i, **p; p = (long **) malloc(r * sizeof(long *)); for (i = 0; i < r; i++) p[i] = (long *) malloc(c * sizeof(long)); return p; }Parametry r a c představují počty řádků (rows) a sloupců (columns).
char str[10]; char *(*fn)(char *, const char *) = strcpy; (*fn)(str, "Hello");Funkce vracející ukazatel na funkci:
char *(*get_strcpy(void))(char *, const char *) { return strcpy; }Pole ukazatelů na funkce:
void (*funcs[])(void) = { func1, func2, func3, NULL }; process(funcs); void process(void (*funcs[])(void)) { while (*funcs != NULL) (*(*funcs++))(); }Následující příklad ukazuje interface pro matici. Funkce apply má jako parametr ukazatel na funkci, takže vlastně vkládáme další kód do funkce. Ve funkci apply jsou dvě smyčky for, které používáme při práci s maticí, a při inicializaci nebo výpisu matice tyto smyčky v ostatních funkcích již nemusíme opakovat.
main.c #include "matrix.h" int main() { MT *m; m = MT_new(5, 5); MT_print(m, "%ld\t"); MT_set_all(m, 7); MT_print(m, "%ld\t"); return 0; } matrix.c #include <stdio.h> #include <stdlib.h> #include "matrix.h" static long **alloc2d(size_t r, size_t c); static MT *alloc(void); static void apply(MT *m, void (*fn)(MT *, int, int, void *), void *arg); static void set_all(MT *m, int i, int j, void *arg); static void print(MT *m, int i, int j, void *arg); struct MT { int rows; int cols; long **data; }; MT *MT_new(int r, int c) { MT *m; m = alloc(); m->rows = r; m->cols = c; m->data = alloc2d(r, c); MT_set_all(m, 0); return m; } static MT *alloc(void) { return (MT *) malloc(sizeof(MT)); } static void apply(MT *m, void (*fn)(MT *, int, int, void *), void *arg) { int i, j; for (i = 0; i < m->rows; i++) for (j = 0; j < m->cols; j++) (*fn)(m, i, j, arg); } static void set_all(MT *m, int i, int j, void *arg) { m->data[i][j] = *(int *) arg; } static void print(MT *m, int i, int j, void *arg) { printf((char *) arg, m->data[i][j]); } void MT_set_all(MT *m, int n) { apply(m, set_all, &n); } void MT_print(MT *m, void *arg) { apply(m, print, arg); } matrix.h #ifndef MT_H #define MT_H typedef struct MT MT; MT *MT_new(int r, int c); void MT_set_all(MT *m, int n); void MT_print(MT *m, void *arg); #endifUživatel neinkluduje celý typ struktury, ale pouze její typedef, což je neúplný typ, takže uživatel nemá přístup k položkám struktury, jsou tedy privátní. Ukazatel na void nesmí být dereferencován, proto je nutné jej přetypovat na správný typ a až poté tento typ dereferencovat.
(*p).xnebo pohodlnější
p->xFunkce na uvolnění paměti by mohla mít parametr ukazatel na ukazatel, takže by nastavila ukazatel pro interface na NULL.
void MT_free(MT **m) { int i; for (i = 0; i < (*m)->rows; i++) free((*m)->data[i]); free((*m)->data); free(*m); *m = NULL; } int main() ... MT_free(&m); /* m je NULL */Mimochodem
(*m)->rowsmůžeme napsat i jako
(**m).rowsA syntaxe pro přístup k hodnotám u 2D polí přes ukazatele je
*(*(a+i)+j)
Tiskni
Sdílej:
V případě ukazatelů na struktury existují dvě možnosti, jak přistupovat k položkám struktur:Jsem jediný, komu chybí(*p).xnebo pohodlnějšíp->x
p-->x
(ekvivalent zmíněného (*m)->rows
→ m-->rows
)? Šlo by na to napsat makro? m-->rows
se parsuje jako (m--)->rows
a asi by mi i víc smyslu dávalo m->>rows
. Pocit chybějícího operátoru mám spíš u konstrukcí typu (*p)[idx]
protožem-->rows
se parsuje jako(m--)->rows
Oprava: mělo tam být "…jako (m--) > rows
".
děte si mršit c++ jóóó??? :O >:C
jestli to teda eště jako nějak víc de :D :D ;D ;D
Ukazatel je špecialná premenná, ktorá pracuje s adresami.
const
(hlavně ten nekonstantní pointer ukazující do string literal) nebo zbytečné přetypovávání pointerů vracených malloc()
.
Kromě chybějících const všude možně (například strlen v základní knihovně a všechny ostatní mají u vstupních proměnných všude consco se prakticnosti tyce bych mel jednu pripominku: kvuli tem miliardam dotazum na internetu, jak to s tim const hlavne u tech pointru na char vlastne je, jsem toho nazoru, ze my, kteri jsme s K&R zacinali se bez tech const dost dobre muzeme obejit. To ze me ten const u strlen-funkce ubezpecuje, ze ta funkce ten string pri zjistovani te delky nezmeni mi nijak zvlast nevzrusuje a ani neuklidnuje, nas starsi by v zivote nenapadlo, ze by nekdo mohl napsat funkci, ktera by to delela.
co si funkce dělá s parametrem vevnitř (kopií proměnné předávanou volajícím), mi může být ukradenéNóóó... úplně jedno to taky není, z tohohle důvodu byl přidán
restrict
, kterým se vývojář zaklíná, že nebude vytvářet aliasy (kopie pointerů apod.), což umožňuje optimalizace přístupu do paměti / lepší cachování...
(Je to tak trochu směrem, kterým šel Rust, kde jsou pravidla aliasingu ještě o dost striktnější a jejich dodržování tvrdě vymáháno kompilátorem, v C jde jen o optimalizační hint a kompilátor maximálně háže warningy. Paradoxně Rust aktuálně ten optimalizační potenciál nevyuživá, protože v LLVM to je rozbité printk()
v jedné funkci modifikoval data, která ta funkce vůbec neměla co měnit - a která za určitých okolností byla opravdu read only. Kdyby tam byl const
, tak by ho chyba při překladu hned trkla, že dělá něco špatného, a řešil by to jinak (nebo by tam ten ladící příkaz vůbec nedal).
Výrazy s poli a indexy jsou ekvivalentní výrazům s ukazateli a posunem, tudíž je možné napsat pole a[i] jako *(a+i)Můžeš to napsat i jako
i[a]
... kolegové to jistě ocení Nicméně výrazy jakoNo, proměnná to je, ale to přiřazení neprojde, protože, AFAIKa=pa
neboa++
nejsou správné, jelikož jméno pole není proměnná.
IMHO nejnázornější příklad ukazující, že pole a pointer opravdu není totéž (i když to spolu úzce souvisí), je
T *ptr; T array[10]; printf("%zu, %zu\n", sizeof(ptr), sizeof(array));
void boo(char *bar) {…}
Pointer a polia su to iste.Ne, nejsou, jsou to různé datové typy.
Rozdíl tam bude, protože v prvním případě "Nazdar" bude globální konstanta, která v závislosti na kompilátoru může být i v read only sekci. Navíc překladač může dělat i taková kouzla, že např.
char *str1 = "Nazdar"; char *str2 = "zdar";
použije jen jeden řetězec "Nazdar" a druhý pointer nechá ukazovat do něj. To je možné právě díky tomu, že string literal je automaticky only. Proto je v takovém případě lepší použít const
, aby vás překladač varoval, pokud byste ho zkusil přepisovat.
Oproti tomu to druhé je inicializace lokálního pole znaků, které je defaultně přepisovatelné. V praxi ale samozřejmě závisí na zbytku kódu, co s tím řetězcem dělá, protože po optimalizaci tam ve skutečnosti žádný string "Nazdar" nikde být ani nemusí.
<flame-war>
Chápu, že článek se věnuje C a ne C++, ale to jsem vážně jediný, komu vadí psát tu hvězdičku k názvu proměnné a kdo by ji psal raději k typu? </flame-war>
Tohle je bohužel věc, která je navržená dost nešťastně. Na jednu stranu je pravda, že psát hvězdičku k typu je logičtější, hlavně když je tam inicializace:
T *p = &x; // kam že to tu adresu přiřazujeme? T* p = &x; // tady je to jasné, do p
Jenže problém nastává u vícenásobných deklarací:
T* p, x; // tohle vypadá, jako by p a x měly stejný typ T *p, x; // ale mají ho *p a x T* p, *q; // a kam napsat tu druhou hvězdičku tady?
Osobně se ale těm násobným deklaracím s pointery snažím vyhýbat.