IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

Diskusia – 3. diel - Aritmetika ukazovateľov v jazyku C

Späť

Upozorňujeme, že diskusie pod našimi online kurzami sú nemoderované a primárne slúžia na získavanie spätnej väzby pre budúce vylepšenie kurzov. Pre študentov našich rekvalifikačných kurzov ponúkame možnosť priameho kontaktu s lektormi a študijným referentom pre osobné konzultácie a podporu v rámci ich štúdia. Toto je exkluzívna služba, ktorá zaisťuje kvalitnú a cielenú pomoc v prípade akýchkoľvek otázok alebo projektov.

Komentáre
Avatar
coells
Tvůrce
Avatar
coells:19.10.2014 20:59
int *p_pozice;
for (p_pozice = p_i; p_pozice < p_i + 100; p_pozice++)
        *p_pozice = 0;

int i;
for (i = 0; i < 100; i++)
        p_i[i] = 0;

Tvrdíš, že "První způsob pomocí pointerové aritmetiky je rychlejší, jelikož Céčko jen přičítá k adrese bajty."

Můžeš to něčím podložit? Na základě disassembly je druhý způsob rychlejší v debug módu a stejně rychlý v release - oba kódy vygenerují 4 instrukce, ale druhý způsob umožní použití MMX instrukcí.

První způsob zápisu je navíc častým omylem začátečníků, kteří se snaží o premature optimalizace. Kratší a jednodušší zápis je v C vždy ten správný bez ohledu na počet instrukcí.

 
Odpovedať
19.10.2014 20:59
Avatar
David Hartinger
Vlastník
Avatar
Odpovedá na coells
David Hartinger:19.10.2014 21:03

Pokud je to stejně rychlé, tak tam udělal překladač optimalizaci, to je dost možné. Otázka je jak moc s tímhle počítat, uvádím oba způsoby, přijde mi to ok.

Odpovedať
19.10.2014 21:03
New kid back on the block with a R.I.P
Avatar
Odpovedá na David Hartinger
Libor Šimo (libcosenior):10.11.2014 14:34

Už sa teším na ďalší diel. :-)

Odpovedať
10.11.2014 14:34
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Lukáš Hypša:15.5.2016 21:35

Mám pár dotazů:

p_i = (int *) malloc(sizeof(int) * 100);

1,Výrazem "(int *)" říkám metodě malloc() aby v uvolněné paměti vytvořila inty?
2,p_i je pointer na začátek uvolněného bloku paměti nebo na celý blok?
3,Pamatuje si pointer velikost uvolněného bloku?
4,Pokud ne, jak ví metoda free() kolik paměti má uvolnit?

 
Odpovedať
15.5.2016 21:35
Avatar
Jan Vargovský
Tvůrce
Avatar
Odpovedá na Lukáš Hypša
Jan Vargovský:15.5.2016 21:43
  1. Ne
  2. Na začátek
  3. Ne
  4. Součást toho bloku je i informace, jak velký ten blok je.
 
Odpovedať
15.5.2016 21:43
Avatar
Jan Matura
Člen
Avatar
Jan Matura:9.11.2019 15:21

Mam dotaz
Pri urcitem ohodnoceni (npr. 2050 a 7800) me konzole vypise spravny interval(program probehne spravne) ale take s hlaskou :
"double free or corruption ( prev)
aborted"
Proc se to deje?
Proc pouze jen u nejakych cisel?

#include <stdio.h>
#include <cstdlib>
int main (void)
//program ma vypsat cisla zadaneho intervalu
{
  int dolni, horni, *p_data1, i;
  printf("zadejte dolni mez intervalu\n");
  if (scanf("%d", &dolni) !=1)
    printf("spatny vstup\n");
  printf("zadejte horni mez intervalu\n");
  if (scanf("%d", &horni) !=1)
    printf("spatny vstup\n");
  int velInt = horni - dolni;
  p_data1 = (int * ) malloc(sizeof(int) * velInt);
  if (p_data1 == NULL)
  {
    printf("nedostatek pameti\n");
    exit(1);
  }
  for (i = 0; i <= velInt; i++)
  {
    p_data1[i] = dolni + i;
  }
  for (i = 0; i <= velInt; i++)
  {
    printf("%d\n", p_data1[i]);
  }
free(p_data1);
p_data1 = NULL;
return 0;
}
 
Odpovedať
9.11.2019 15:21
Avatar
DarkCoder
Člen
Avatar
Odpovedá na Jan Matura
DarkCoder:9.11.2019 20:35

K tvému programu:

Pokud překládáš program jako program psaný v C a nikoli v C++, pak následující řádek

#include <cstdlib>

je chybný. Místo toho použij

#include <stdlib.h>

Pokud provádíš kontrolu vstupu, pak ji zpracuj i v programu, ne jen informuj uživatele. I přes zadání neplatného vstupu (fce scanf()) Ti program pokračuje směle dál. Buď vypiš chybovou hlášku a program ukonči pomocí funkce exit() tak jak to máš u testu na přidělení paměti nebo lépe zopakuj výzvu a nechej uživatele načíst znova hodnotu.

V zadání není uvedeno v jakých typech intervalu má program pracovat. Pokud program má pracovat v typu zleva uzavřeno, zprava otevřeno, pak výraz

int velInt = horni - dolni;

je správný. V opačném případě chybný. Dobré by bylo otestovat na polaritu mezí (zda-li dolní mez není větší než horní mez). Tato informace je nezbytná pro další testování (test přidělení paměti). Pokud by byla nesprávná polarita, pak Ti funkce malloc() selže se záporným argumentem. To ale neznamená, že je nedostatek paměti. Proto je tento test důležitý.

Tvůj program počítá s intervaly zleva uzavřený, zprava otevřený. Pokud těch prvků je N a alokuješ prostor pro N prvků, pak není přípustné, aby si přiřazoval do alokovaného pole N+1 prvků. Toto je nejvážnější chyba celého programu.

Řádky

for (i = 0; i <= velInt; i++)

nahraď tímto

for (i = 0; i < velInt; i++)
Odpovedať
9.11.2019 20:35
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Odpovedá na DarkCoder
Martin Russin:6.7.2021 19:51

Ahoj, chcel by som ťa poprosiť o vysvetlenie k týmto veciam:

1, Prečo v nasledujúcom kóde nie je použitý dereferenčný operátor* ? Veď platí p_i -> pracujem s hodnotou adresy, * p_i -> pracujem s hodnotou na danej adrese. Chceme predsa uložiť hodnotu 0 na každú jednu adresu pridelenej pamäti, alebo to chápem zle?

int i;
for (i = 0; i < 100; i++)
{
    p_i[i] = 0;
}

Tomuto kódu chápem, hodnotu adresy postupne zvyšujeme a pomocou dereferenčného operátora* následne priradím na danú hodnotu v cykle vždy hodnotu 0.

int *p_pozice;
for (p_pozice = p_i; p_pozice < p_i + 100; p_pozice++)
{
    *p_pozice = 0;
}

2,

Možná by nás ale mohlo zajímat, co udělá operace sizeof(p_i) (všimněte si chybějící hvězdičky). V tomto případě získáme velikost ukazatele samotného, ne hodnoty, na kterou ukazuje. Velikost ukazatele bude stejná pro všechny typy, tedy sizeof(char*) se rovná sizeof(int*). To je tím, že z principu ukazatel pouze ukazuje na místo paměti. Pro uložení adresy do paměti potřebujeme vždy stejně velký typ. Například pro 32-bitovou architekturu bude velikost ukazatele 4bajty, pro 64-bitovou architekturu 8 bajtů.

Pro uložení adresy do paměti potřebujeme vždy stejně velký typ. -> aký je to konkrétny typ? ako si ho mám predstaviť?

Například pro 32-bitovou architekturu bude velikost ukazatele 4bajty, pro 64-bitovou architekturu 8 bajtů. -> čiže stačí mi vedieť v akej bitovej architektúre pracujem a hneď viem veľkosť pointera? Napr. používam 64-bitovú architektúru, tak veľkosť operátora bude vždy 8 bajtov?

Vopred ďakujem za Tvoje odpovede.

 
Odpovedať
6.7.2021 19:51
Avatar
DarkCoder
Člen
Avatar
Odpovedá na Martin Russin
DarkCoder:7.7.2021 14:05

Existují 3 typy způsobů, jak přistupovat k hodnotě uložené v poli. A to pomocí indexování, ukazatelové aritmetiky a kombinací obou předchozích způsobů (vícerozměrná pole).

Pokud se používá čistě indexace, žádné dereferencování se neprovádí. Nutno podotknout, že indexace má 2 varianty - indexování proměnné, indexovánání ukazatele.

Pokud se používá ukazatelová aritmetika, je třeba ukazatel dereferencovat. Opět jsou tu 2 varianty - dereference u konstantního ukazatele (názvu proměnné pole) a dereference u ukazatele na pole.

Pro představu:
Následující program vypíše hodnotu 3 prvku pole 4 možnými způsoby uvedenými výše.

#include <stdio.h>

int main(void) {
        int nums[] = { 1,2,3,4,5 };
        int *p = nums;

        printf("%d\n", nums[2]); // indexace promenne
        printf("%d\n", p[2]); // indexace ukazatele
        printf("%d\n", *(nums + 2)); // dereference u konstatniho ukzatele
        printf("%d\n", *(p + 2)); // dereference u ukazatele na pole

        return 0;
}

Co se týká typu pro uložení adresy do paměti, jedná se o bezznaménkový celočíselný typ který se obvykle označuje jako size_t. Pro určení velikosti ukazatele, pokud je to třeba, se vždy používá operátor preprocesoru sizeof, který vyhodnocuje velikost typu nebo proměnné v době překladu. Je třeba mít na paměti, že aplikace napsaná pro 32bit prostředí může běžet i v 64bit prostředí. Bylo by chybou se spoléhat na něco, co nemusí být vždy zaručeno. Velmi dobrým příkladem použití sizeof je při zjišťování velikosti struktur.

Odpovedať
7.7.2021 14:05
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Odpovedá na DarkCoder
Martin Russin:7.7.2021 16:38
int nums[] = { 1,2,3,4,5 };
int *p = nums;

V prvom riadku kódu si deklaroval pole typu int s názvom nums a ručne si ho naplnil hodnotami.

V druhom riadku si deklaroval pointer s dereferenčným operátorom a pridelil si do neho všetky hodnoty z poľa nums?
Ak áno, tie hodnoty sa uložili na adresy v pamäti postupne za sebou? Pointer *p ukazuje na adresu prvej hodnoty pola nums, teda na adresu, na ktorej je uložená hodnota 1?
V tomto prípade nie je potrebné dynamické alokovanie pamäte, teda si od OS vypýtať určité množstvo pamäte?

 
Odpovedať
7.7.2021 16:38
Robíme čo je v našich silách, aby bola tunajšia diskusia čo najkvalitnejšia. Preto do nej tiež môžu prispievať len registrovaní členovia. Pre zapojenie sa do diskusie sa zaloguj. Ak ešte nemáš účet, zaregistruj sa, je to zadarmo.

Zatiaľ nikto nevložil komentár - buď prvý!