Pointeri et stringovi
Select messages from
# through # FAQ
[/[Print]\]

Forum@DeGiorgi -> Programiranje 1 i 2

#1: Pointeri et stringovi Autor/ica: krilo PostPostano: 14:52 pon, 24. 4. 2017
    —
Da ne švrljam po topicu o "rekurzijama"...

Malo me zbunjuju funkcije iz <ctype.h> datoteke... Zašto piše u njihovom prototipu da primaju int ako provjeravaju char? (Nije mi baš jasno kako poziv funkcionira u računalu, tj. kako se to unutra interpretira.)

Rješavam zadatak iz kolokvija i imam problem s pointerima:
Napišite program koji učitava broj prodavača n jedne trgovine, a zatim, redom, iznose računa koje je pojedini prodavač naplatio. Iznos je realni broj strogo veći od nula. Između iznosa svaka dva prodavača unosi se 0.

(a) Potrebno je kreirati dinamički alocirano polje prodavaci, u kojem će, u i-tom retku, na prvom mjestu biti oznaka prodavača (na početku je to upravo i), zatim iznosi naplaćenih računa i-tog prodavača, i = 0, . . . , n−1, a posljednji element svakog retka ima vrijednost 0 i označava kraj retka. Pri tom, alocirajte točno onoliko memorije koliko vam je potrebno.

Za to pravim funkciju al_uc_racune koja bi alocirala memoriju za "manje" nizove i postavila njihove prve elemente kao oznake prodavača. (Note: prije poziva dotične funkcije u glavnom programu već imam učitan broj prodavača i alocirano polje prodavaci: prodavaci=(double**)malloc(sizeof(double)*n);.)

Kod:
void al_uc_racune(double **prodavaci, int n)
{
    int i, j;
    for (i=0; i<n; i++)
        {
            prodavaci[i][0]=i;        //prvi u manjem nizu je broj (oznaka) prodavaca
            for (j=1; ; j++)
                {
                    prodavaci[i][j]=(double*)malloc(sizeof(double));            (*)
                    scanf ("%g", prodavaci[i][j]);
                    if (prodavaci[i][j]==0) break;
                }
        }
}

1) Nije mi jasno zašto neće compiler alocirati memoriju za svaki pojedini račun (*). Probala sam isto s pointerima, umjesto prodavaci[i][j] staviti (*(prodavaci+i)[j]) ali ni to ne štima, pa je očito da ne kužim pointersku aritmetiku i kretanje po "matrici" pomoću pointera. Koliko postoji ekvivalentrnih zapisa za dvodimenzionalno polje kad zapisujemo pomoću pointera i sa klasičnim zagradama ([][])?

2) Neka je u nekom xy programu inicijaliziran int *ptr. Jasno mi je da (*ptr) označava vrijednost na koju pointer pokazuje, ali koje je značenje (ptr) u toj "sintagmi"? Vječito malloc-om (ptr)-u (a ne (*ptr)-u) pridružujem nešto, a iskreno nemam pojma što (ptr) jest, osim imena samog pointera. Prvo sam mislila da je to neka adresa, ali mi to nema smisla je *ptr baš pointer, a ne varijabla. Može neko objašnjenje?

#2: Re: Pointeri et stringovi Autor/ica: mdokoLokacija: Heriot-Watt University, Edinburgh PostPostano: 21:23 pon, 24. 4. 2017
    —
krilo (napisa):

Kod:
void al_uc_racune(double **prodavaci, int n)
{
    /* ... */
    prodavaci[i][j]=(double*)malloc(sizeof(double));
    /* ... */
}


Ako je varijabla prodavaci tipa double**, onda je prodavaci[i][j] tipa double.

S druge strane (double*)malloc(sizeof(double)) je (očito) tipa double*.

Dakle, ti pokušavaš vrijedost tipa double* pridružiti varijabli tipa double, što nema nikakvog smisla i normalno je da se kompajler buni.

#3: Re: Pointeri et stringovi Autor/ica: vsegoLokacija: /sbin/init PostPostano: 21:36 pon, 24. 4. 2017
    —
krilo (napisa):
Malo me zbunjuju funkcije iz <ctype.h> datoteke... Zašto piše u njihovom prototipu da primaju int ako provjeravaju char? (Nije mi baš jasno kako poziv funkcionira u računalu, tj. kako se to unutra interpretira.)


For all intents and purposes, ponasaj se kao da rade s char-ovima. Rijec je o kompatibilnim tipovima, jer se char cuvao kao ASCII vrijednost. Zasto su stavili int je pomalo tehnicka stvar; zagooglaj ako te zanimaju detalji.

krilo (napisa):
Rješavam zadatak iz kolokvija i imam problem s pointerima:
Napišite program koji učitava broj prodavača n jedne trgovine, a zatim, redom, iznose računa koje je pojedini prodavač naplatio. Iznos je realni broj strogo veći od nula. Između iznosa svaka dva prodavača unosi se 0.
(a) Potrebno je kreirati dinamički alocirano polje prodavaci, u kojem će, u i-tom retku, na prvom mjestu biti oznaka prodavača (na početku je to upravo i), zatim iznosi naplaćenih računa i-tog prodavača, i = 0, . . . , n−1, a posljednji element svakog retka ima vrijednost 0 i označava kraj retka. Pri tom, alocirajte točno onoliko memorije koliko vam je potrebno.
Za to pravim funkciju al_uc_racune koja bi alocirala memoriju za "manje" nizove i postavila njihove prve elemente kao oznake prodavača. (Note: prije poziva dotične funkcije u glavnom programu već imam učitan broj prodavača i alocirano polje prodavaci: prodavaci=(double**)malloc(sizeof(double)*n);.)
Kod:
void al_uc_racune(double **prodavaci, int n)
{
    int i, j;
    for (i=0; i<n; i++)
        {
            prodavaci[i][0]=i;        //prvi u manjem nizu je broj (oznaka) prodavaca
            for (j=1; ; j++)
                {
                    prodavaci[i][j]=(double*)malloc(sizeof(double));            (*)
                    scanf ("%g", prodavaci[i][j]);
                    if (prodavaci[i][j]==0) break;
                }
        }
}

1) Nije mi jasno zašto neće compiler alocirati memoriju za svaki pojedini račun (*). Probala sam isto s pointerima, umjesto prodavaci[i][j] staviti (*(prodavaci+i)[j]) ali ni to ne štima, pa je očito da ne kužim pointersku aritmetiku i kretanje po "matrici" pomoću pointera. Koliko postoji ekvivalentrnih zapisa za dvodimenzionalno polje kad zapisujemo pomoću pointera i sa klasičnim zagradama ([][])?


prodavaci treba biti pointer na niz, a svaki njegov element treba opet biti pointer na niz. Dakle, treba alocirati prodavaci (sto mozda radis izvan funkcije), a zatim i svaki prodavaci[i]. Elementi prodavaci[i][j] su najobicniji brojevi; njih ne alociramo.

Posto ne znamo unaprijed koliko prodavaci[i] ima elemenata, treba koristiti realloc.

krilo (napisa):
2) Neka je u nekom xy programu inicijaliziran int *ptr. Jasno mi je da (*ptr) označava vrijednost na koju pointer pokazuje, ali koje je značenje (ptr) u toj "sintagmi"? Vječito malloc-om (ptr)-u (a ne (*ptr)-u) pridružujem nešto, a iskreno nemam pojma što (ptr) jest, osim imena samog pointera. Prvo sam mislila da je to neka adresa, ali mi to nema smisla je *ptr baš pointer, a ne varijabla. Može neko objašnjenje?


To je tzv. implicitna deklaracija. Basically, kad deklariras int *ptr, kazes "zelim alocirati *ptr koji je tipa int". No, compiler zna da je *ptr "ono na sto ptr pokazuje", pa "pametno" zakljuci da zapravo zelis deklarirati "pointer na int koji ces zvati ptr".

Kad kazes
Kod:
ptr = (double*)malloc(n * sizeof(double));

Zapravo kazes:
  1. malloc(n * size(double)) sto znaci "alociraj n * size(double) byteova memorije", tj. "alociraj onoliko memorije koliko mi treba da pospremim n vrijednosti tipa double".
  2. Posto malloc(...) vraca "pointer na memoriju neodredjenog tipa" (tzv. void-pointer, odnosno void*), a ptr je tipa double*, onda zelimo compileru reci da ne pridruzujemo "razlicite" tipove slucajno. Tome sluzi cast operator (double*) koji kaze "vrijednost s desne strane tretiraj kao da je tipa double*. Posto su svi pointeri jednake velicine, ti tipovi su kompatibilni, pa nema problema.
Dakle, adresa novoalocirane memorije (ilitiga "pointer na tu memoriju") se sprema u varijablu ptr.

#4:  Autor/ica: krilo PostPostano: 6:43 uto, 25. 4. 2017
    —
Thank you Hvala lijepo na objašnjenju! Thank you

Citat:
Posto ne znamo unaprijed koliko prodavaci[i] ima elemenata, treba koristiti realloc.


Ma bi ja to koristila, ali sam u skripti pročitala da je realloc spor, pa sam ga odlučila ne upotrijebiti unless absolutely neccessary. Nadalje budem.

I još jedna sitnica, da budem 100% sigurna: Kad inicijaliziram i alociram int **niz, onda je u zapisu jednog elementa "većeg" niza niz[i]==**(niz+i) ili niz[i]==*(*niz+i) ili pak niz[i]==(**niz)+i? Ovo potonje mislim da nije, ali u globalu mi nije jasno kako da se properly krećem po "matrici" pomoću pointerske aritmetike. (I kako tek onda moram pisati za niz[i][j]?)

(I koja je fora s unosom nule između računa dva prodavača? Cijelo vrijeme unosim doubleove, ali ne mogu prekinuti petlju unosa jer ne znam kako da unesem int 0 u double niz a da program ne pošandrca. Znam da ne mogu konvertirati (double) prodavaci[i][j] u int pa to usporediti jer postoje mogućnosti računa poput 0.00005; probala sam usporediti u if-u double i float, ali malo radi pa malo ne radi. Trudim Se Objasniti... )

#5:  Autor/ica: vsegoLokacija: /sbin/init PostPostano: 16:49 uto, 25. 4. 2017
    —
krilo (napisa):
Ma bi ja to koristila, ali sam u skripti pročitala da je realloc spor, pa sam ga odlučila ne upotrijebiti unless absolutely neccessary. Nadalje budem.


Nema spasa ako duljina niza nije poznata unaprijed. Postoje nacini da se ubrza, ali nemojmo komplicirati. Wink Poanta te opaske je da ne alocirate element po element ako duljinu znate unaprijed, te da ste svjesni da postoji performance problem.

krilo (napisa):
I još jedna sitnica, da budem 100% sigurna: Kad inicijaliziram...


Imam dojam da brkas "deklarirati" (najaviti compileru da ces koristiti adresu nekog tipa i s nekim imenom) i "inicijalizirati" (zadati varijabli pocetnu vrijednost).

krilo (napisa):
...i alociram int **niz, onda je u zapisu jednog elementa "većeg" niza niz[i]==**(niz+i) ili niz[i]==*(*niz+i) ili pak niz[i]==(**niz)+i?


Ni jedno. Ako je niz tipa "pointer na pointer na nesto", onda je **niz tipa "nesto" dok je niz[i] tipa "pointer na nesto".

Ima negdje u skripti to raspisano (Napomene 4.2.2. i 4.2.3.), ali za element slobodno pisi niz[i][j], osim ako se bas explicitno trazi pointerski (sumnam da bude).

krilo (napisa):
(I koja je fora s unosom nule između računa dva prodavača? Cijelo vrijeme unosim doubleove, ali ne mogu prekinuti petlju unosa jer ne znam kako da unesem int 0 u double niz a da program ne pošandrca. Znam da ne mogu konvertirati (double) prodavaci[i][j] u int pa to usporediti jer postoje mogućnosti računa poput 0.00005; probala sam usporediti u if-u double i float, ali malo radi pa malo ne radi. Trudim Se Objasniti... )


Nula je nula. Probaj na jednostavnom primjeru:

Kod:
#include<stdio.h>

int main(void) {
    double x;
    scanf("%lf", &x);
    printf("%s nula\n", (x == 0 ? "Je" : "Nije"));
    return 0;
}


Dakle, ucitas double x. Ako je x == 0 prekines ucitavanje tok prodavaca; ako nije, doalociras niz i pridruziz vrijednost varijable x novom elementu.


Zadnja promjena: vsego; 23:14 uto, 25. 4. 2017; ukupno mijenjano 1 put.

#6:  Autor/ica: krilo PostPostano: 19:30 uto, 25. 4. 2017
    —
vsego (napisa):
Imam dojam da brkas "deklarirati" (najaviti compileru da ces koristiti adresu nekog tipa i s nekim imenom) i "inicijalizirati" (zadati varijabli pocetnu vrijednost).


Imaš dobar dojam. O, kuku meni...

Ne znam kako sam previdjela spomenute napomene, hvala na uputi.

vsego (napisa):
Dakle, ucitas double x. Ako je x == 0 prekines ucitavanje tok prodavaca; ako nije, doalociras niz i pridruziz vrijednost varijable x novom elementu.


Upravo sam i to radila 'till it hit me da je problem u scanf-u, tj. slovima %g, %f i %lf... Stajao mi je tamo %g koji očito ne valja.
Što dalje idem, to više kužim da ne kužim elementarno. Nuts
Thank you

#7:  Autor/ica: vsegoLokacija: /sbin/init PostPostano: 23:15 uto, 25. 4. 2017
    —
double = long float, pa je format %lf. Wink



Forum@DeGiorgi -> Programiranje 1 i 2


output generated using printer-friendly topic mod. Vremenska zona: GMT + 01:00.

Stranica 1 / 1.

Powered by phpBB © 2001,2002 phpBB Group
Theme created by Vjacheslav Trushkin