abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
AbcLinuxu hledá autory!
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    3.12. 23:33 | Zajímavý článek

    Na stránkách Syst3m Failure byl publikován článek o využití 16leté bezpečnostní chyby CVE-2021-42008 v Linuxu v ovladači 6pack k získání roota. Chyba byla do Linuxu zanesena v roce 2005 a v upstreamu opravena letos v létě.

    Ladislav Hagara | Komentářů: 24
    3.12. 19:00 | Nová verze

    Byl vydán Blender 3.0. Oznámení vydání obsahuje vizualizace změn. Plány pro vydání byly shrnuty v dřívějším zápisku.

    Fluttershy, yay! | Komentářů: 0
    3.12. 16:44 | Nová verze

    Představen byl CentOS Stream 9. Jedná se o průběžně aktualizovanou linuxovou distribuci umístěnou mezi Fedora Linuxem a Red Hat Enterprise Linuxem (RHEL). Podpora CentOS Linuxu 8 končí s koncem letošního roku.

    Ladislav Hagara | Komentářů: 8
    3.12. 13:22 | Nová verze

    Byla vydána nová major verze 3.0.0 knihovny Notcurses pro vývoj programů s vylepšeným textovým uživatelským rozhraním (TUI). Ukázka možností na YouTube. Více o knihovně v knize Hacking The Planet! with Notcurses (pdf).

    Ladislav Hagara | Komentářů: 2
    3.12. 13:00 | Nová verze

    V červenci letošního roku byl představen 3D open source herní a simulační engine Open 3D Engine (O3DE). Včera byla vydána první major verze 21.11. Z novinek lze zdůraznit podporu Linuxu.

    Ladislav Hagara | Komentářů: 0
    3.12. 09:00 | Komunita

    Nedávno byl vydán nový Raspberry Pi OS založený na Debianu 11 Bullseye. Řadě uživatelů ale novinky nevyhovují, viz například problém s kamerami. Vývojáři se proto rozhodli vedle Raspberry Pi OS podporovat také Raspberry Pi OS (Legacy) založený na Debianu 10 Buster. Uživatelé požadující knihovnu picamera mohou nově používat také Raspberry Pi OS a knihovnu si povolit v nastavení raspi-config (YouTube).

    Ladislav Hagara | Komentářů: 0
    3.12. 08:00 | Nová verze

    Byla vydána verze 1.7.0 dynamického programovacího jazyka Julia (Wikipedie) určeného zejména pro vědecké výpočty. Přehled novinek v příspěvku na blogu a v poznámkách k vydání. Aktualizována byla také dokumentace. Současně bylo oznámeno, že větev 1.6 (aktuálně verze 1.6.4) je nově LTS.

    Ladislav Hagara | Komentářů: 0
    3.12. 07:00 | Nová verze Ladislav Hagara | Komentářů: 0
    2.12. 21:22 | Nová verze

    Byla vydána nová verze 6 integrovaného vývojového prostředí (IDE) Qt Creator. Podrobný přehled novinek v cgitu. Zdůraznit lze podporu vícekurzorové editace (gif).

    Ladislav Hagara | Komentářů: 5
    2.12. 20:55 | Nová verze

    Byla vydána verze 1.57.0 programovacího jazyka Rust (Wikipedie). Podrobnosti v poznámkách k vydání. Vyzkoušet Rust lze například na stránce Rust by Example.

    Ladislav Hagara | Komentářů: 0
    Pracujete z domu?
     (32%)
     (34%)
     (16%)
     (1%)
     (15%)
     (2%)
    Celkem 129 hlasů
     Komentářů: 16, poslední dnes 15:02
    Rozcestník

    Ukazatele - Jazyk C

    4.2. 18:48 | Přečteno: 2053× | Programování | Výběrový blog

    Ukazatel je proměnná, jejíž hodnota je adresa. Dereferencující operátor * zpřístupňuje proměnnou, na kterou ukazatel ukazuje. Operátor & umožňuje získat adresu proměnné.
    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.

    Při deklaraci můžeme ukazatel rovnou inicializovat:
    int *ip = &x;
    

    Ukazatele a pole

    int a[10];
    int *pa;
    
    pa = &a[0];
    
    Nyní přiřazení
    x = *pa;
    
    zkopíruje obsah a[0] do x.

    pa+i je adresa a[i] (tedy &a[i]) a *(pa+i) je obsah a[i].

    Jelikož jméno pole je adresa prvního prvku, přiřazení
    pa = &a[0];  
    
    a
    pa = a;          
    
    jsou ekvivalentní.

    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) a &a[i] jako a+i, a naopak ukazatel *(pa+i) jako pa[i]. Nicméně výrazy jako a=pa nebo a++ nejsou správné, jelikož jméno pole není proměnná.

    Opět můžeme ukazatel rovnou inicializovat:
    int *pa = a;
    

    Ukazatele a funkce


    Jelikož se funkcím předávají pouze kopie argumentů, funkce nemohou měnit jejich hodnoty. Nicméně funkce může změnit hodnotu argumentů nepřímo přes jejich adresu pomocí ukazatelů.

    Prohození hodnot v a a b:
    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.

    Kvůli větší bezpečnosti funkce strlen ze standardní knihovny vrací typ size_t, což je typedef pro neznaménkový typ.

    Funkci je také možné předat pouze část pole. Pokud a je pole,
    f(&a[2]);
    
    nebo
    f(a+2);
    
    předají funkci f adresu podpole, které začíná na a[2].


    Řetězcové konstanty


    Nejčastěji se řetězcové konstanty objevují jako argumenty funkcí:
    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.

    Z řetězcových konstant je také možné vytvářet pole:
    char *colors[] = {
        "red",
        "green",
        "blue",
        NULL
    };
    

    Dynamická alokace


    Pokud chceme alokovat proměnné dynamicky (během běhu programu), použijeme funkci malloc, která vrací adresu paměti přidělenou operačním systémem. K uvolnění paměti slouží funkce free. Paměť je nutné uvolňovat, aby nevznikaly memory leaky. Dobrou praxí je po uvolnění paměti nastavit ukazatel na NULL, abychom neměli takzvaný "dangling pointer", tedy ukazatel, který ukazuje do paměti, která nám již nepatří, takový ukazatel se nesmí dereferencovat. Rovněž je zakázané uvolňovat dvakrát stejnou paměť. Nicméně pokud funkci free předáme hodnotu NULL, nic se nestane.

    Funkce estrdup dynamicky alokuje pole typu char:
    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.


    Pole ukazatelů


    Vzhledem k tomu, že ukazatel je vlastně obyčejná proměnná, je možné z ukazatelů vytvářet pole.

    Následující program načítá jednotlivé řádky a poté je vypíše. Načítání řádků ukončí stisk CTRL+D, který vyvolá EOF hodnotu.
    #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ěť.

    Hlavičku funkce
    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).

    Parametr ukazatel na ukazatel typu char (adresa ukazatele typu char) má například i funkce strtol ze standardní knihovny, její parametr mění hodnotu ukazatele, tedy adresu, na kterou ukazatel ukazuje. Funkce strtol převádí řetězec na číslo a má tuto hlavičku:
    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).


    Ukazatele na funkce


    Ukazatele na funkce je možné přiřazovat, předávat funkcím, funkce je mohou vracet a také z nich lze vytvářet pole. Hodnota ukazatele na funkci je adresa funkce a při dereferenci je funkce, na kterou ukazatel ukazuje, zavolána.
    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);
    
    #endif
    
    Už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.

    V případě ukazatelů na struktury existují dvě možnosti, jak přistupovat k položkám struktur:
    (*p).x
    
    nebo pohodlnější
    p->x 
    
    Funkce 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)->rows 
    
    můžeme napsat i jako
    (**m).rows
    
    A syntaxe pro přístup k hodnotám u 2D polí přes ukazatele je
    *(*(a+i)+j)
    
           

    Hodnocení: 86 %

            špatnédobré        

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    Komentáře

    Vložit další komentář

    Jendа avatar 4.2. 19:48 Jendа | skóre: 77 | blog: Jenda | JO70FB
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    V případě ukazatelů na struktury existují dvě možnosti, jak přistupovat k položkám struktur:
    (*p).x
    nebo pohodlnější
    p->x
    Jsem jediný, komu chybí p-->x (ekvivalent zmíněného (*m)->rowsm-->rows)? Šlo by na to napsat makro? :-D
    4.2. 23:05 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    Nemyslím že by to nějak zvlášť přispělo čitelnosti. Navíc takhle by ten operátor určitě vypadat nemohl, protože 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]
    4.2. 23:06 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    protože m-->rows se parsuje jako (m--)->rows

    Oprava: mělo tam být "…jako (m--) > rows".

    Gréta avatar 5.2. 12:28 Gréta | skóre: 34 | blog: Grétin blogísek | Stockholm
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C

    děte si mršit c++ jóóó??? :O >:C

    jestli to teda eště jako nějak víc de :D :D ;D ;D

    4.2. 19:49 debian+ | skóre: 27 | blog: analyzy
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    Ukazatel je špecialná premenná, ktorá pracuje s adresami. 
    debian.plus@protonmail.com
    A TL;DR verze?
    Čekám na 3. dávku
    4.2. 20:58 podlesh
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    jen retro vzpomínky na to, jak se programovalo v minulém tisíciletí
    4.2. 21:49 Ariczek | skóre: 5
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    Třeba v embedded světě je to běžné i dneska.

    Tam, kde dělám cca 8 let, je nejnovější možný výstřelek C++03 v gcc-4.3 ;)
    4.2. 22:51 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    No, nebýt těch hlaviček funkcí, měl bych pocit, že je velká část příkladů opsaná z Kernighana a Richieho. A jsou tam i věci, které by dneska asi při review narazily. Třeba ta hromada chybějících const (hlavně ten nekonstantní pointer ukazující do string literal) nebo zbytečné přetypovávání pointerů vracených malloc().
    5.2. 00:46 kvr
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    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 const. Stejně tak string constants jsou jako const char * ), nějakých optimalizací jako memcpy místo strcpy, když už je známa délka. Typ size_t není kvůli bezpečnosti, ale kvůli přenositelnosti (zdravím Microsoft s jejich neslavným DWORD), i když v korektní přenositelnost má eventuelně na bezpečnost vliv taky.

    Nicméně, je to jen takový jemný úvod, který si asi přečtou studenti v první kapitole jazyka C. Čekal bych nějakou sondu do třešniček, jako třeba deklarace pole ukazatelů vs ukazatel na pole, funkce vracející ukazatel na pole apod. Ve své době, kdy jsem ještě dělal v C++, tohle byly moje noční můry, které jsem bez manuálu zpaměti obvykle nedal :-D .

    5.2. 20:01 johnyK | blog: uxblog
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    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 cons
    co 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. :-) Taky bych se vsadil, ze 99,99% C-programatoru by nedokazalo z fleku napsat tu deklaraci toho nemeneho pointru na ten nemeny retezec. (ja bych to tedy nedokazal :-))

    Dlouho se rikalo, ze to const muze urychlit program. Na netu je rada clanku, ktere to vyvraci.

    5.2. 22:28 kvr
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    To není ani tak o tom, zda člověk používáním selského rozumu dokáže sám odhadnout, zda funkce nemění data. Ale je to hlavně informace pro kompilátor, který dokáže odchytit potenciální chyby, což je důležité zvláště u komplexnějších projektů.

    Neměnný pointer na neměnný řetězec je celkem jednoduchý - prostě se dá const před cílový typ i před samotnou proměnnou. Prakticky je ale důležitý ten cílový typ, co si funkce dělá s parametrem vevnitř (kopií proměnné předávanou volajícím), mi může být ukradené (i když best practice říká, že parametry se neměnní).

    Ohledně vlivu na výkon - viz výše, to není hlavním cílem. Ale nevyvracel bych to, samozřejmě ne v triviálních případech jako strlen. Kompilátor si může uložit kopii do registru nebo její část v případě struktur apod., takže lepší výkon může být důsledkem taky.
    6.2. 12:06 kralyk z abclinuxu | skóre: 29 | blog:
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    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é :-D)
    The earliness with which a country left the gold standard reliably predicted its economic recovery [1].
    5.2. 23:25 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    Jeden příklad z reálné praxe: tenhle commit opravuje nenápadnou regresi, kvůli které spousta lidí po upgradu na jádro 5.10 nenabootovala (doporučuji pozornosti zejména položku Duplicates). A to jen proto, že někdo kvůli celkem zbytečnému přidanému debugovacímu 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).
    5.2. 11:21 kralyk z abclinuxu | skóre: 29 | blog:
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    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 jako a=pa nebo a++ nejsou správné, jelikož jméno pole není proměnná.
    No, proměnná to je, ale to přiřazení neprojde, protože, AFAIK
    1. Není dovoleno přiřazovat do proměnných/výrazů s typem pole.
    2. Typ pole implicitně kovertuje na pointer, ale opačná konverze není povolená.
    The earliness with which a country left the gold standard reliably predicted its economic recovery [1].
    5.2. 13:31 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C

    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));
    
    5.2. 17:42 debian+ | skóre: 27 | blog: analyzy
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    Pointer a polia su to iste.

    Plus ale tento specialny zapis definovania polia hovori aj, ze vznika na zasobniku z vopred danou velkostou. Pokial vie sizeof() velkost, tak vracia velkost prvku, inac velkost datoveho typu. A tym ze si presne definoval velkost, tak vie aj jeho presnu velkost.

    Z definicie nevies, ci sa odkazuje na jednosmerne pole dat, alebo jeden prvok:
    void boo(char *bar) {…}
    debian.plus@protonmail.com
    5.2. 18:23 kralyk z abclinuxu | skóre: 29 | blog:
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    Pointer a polia su to iste.
    Ne, nejsou, jsou to různé datové typy.
    The earliness with which a country left the gold standard reliably predicted its economic recovery [1].
    Agent avatar 6.2. 11:36 Agent | blog: Life_in_Pieces | HC city
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    Chápu to tak, že když udělám:

    char *retezec1 = "Nazdar";

    char retezec2[] = "Nazdar";

    Tak bych řekl, že rozdíl je hlavně v tom, že s prvním nemohu manipulovat, je jen pro čtení, s druhým ano. Nevím, jak je ta která struktura reprezentovaná na nízké úrovni, na úrovni strojáku, ale nedivil bych se, kdyby to bylo stejný akorát tam bude nějaká "omáčka" okolo dávající tomu nějaké vlastnosti. Ale nevim.
    Nevěděl zpočátku, co si počít, jak žít, co dělat, ale brzy se vpravil do role samotáře.
    6.2. 15:15 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C

    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í.

    Agent avatar 6.2. 11:23 Agent | blog: Life_in_Pieces | HC city
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    Ukazatel je proměnná, jejíž hodnota je adresa.

    A ukazatel sám o sobě je adresa, která leží na nějaké adrese. A ta adresa leží na nějaké adrese. A ta adresa......
    Nevěděl zpočátku, co si počít, jak žít, co dělat, ale brzy se vpravil do role samotáře.
    6.2. 15:56 debian+ | skóre: 27 | blog: analyzy
    Rozbalit Rozbalit vše Re: Ukazatele - Jazyk C
    Aspon co sa tyka ukladania do pamete, tak pointer moze byt premenna. Ale co sa tyka vykonavania, tak sa s nou nemusi uz pracovat ako s obycajnou premennou. Totiz, nejake instrukcia v ASM pracuju len s adresou a adresa nemusi byt formatovo rovnaka ako premenna (napr. vecsia dlzka, ukladana v RAW ako offset+posun).
    debian.plus@protonmail.com
    xkucf03 avatar 6.2. 16:08 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Ukazatele – kam psát hvězdičku
    <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>
    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    6.2. 17:19 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Ukazatele – kam psát hvězdičku

    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.

    9.2. 15:15 Kate | skóre: 9
    Rozbalit Rozbalit vše Re: Ukazatele – kam psát hvězdičku
    Osobně je raději ani nepoužívám. Přijde mi to čitelnější i za cenu vyššího počtu řádků.

    Založit nové vláknoNahoru

    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.