Discussion:
Przekazywanie tablic do funkcji
(Wiadomość utworzona zbyt dawno temu. Odpowiedź niemożliwa.)
Gambit
2004-01-18 13:01:16 UTC
Permalink
Hi!

Jestem tu nowy, więc na początek witam wszystkich grupowiczów!
Dopiero zacząłem uczyć się C++ i mam pewien problem.
Najlepiej będzie jak pokażę o co mi chodzi na przykładzie programu:

#include <iostream>
using namespace std;

void test(int a[]) {
cout << "sizeof(a) = " << sizeof(a) << endl;
}

int main() {
int a[20];
cout << "sizeof(a) = " << sizeof(a) << endl;
test(a);
}

Dlaczego w main wyświetla wszystko dobrze tzn. że tablica ma rozmiar 80
bitów, a w metodzie test traktuje wskaźnik do tablicy jako (jak
przypuszczam) pierwszy element tej tablicy i zwraca że rozmiar "a" jest
równy 4bity? Dlaczego nie traktuje wskaźnika jako tablicę, tylko jako po
prostu jakieś miejsce w pamięci, które równie dobrze może być wskaźnikiem
do int'a? A może moje przypuszczenia są błędne i takie zachowanie jest "mile
widziane" (nie wiedziałem jakiego słowa tu użyć :)?

Mam nadzieję, że moje pytanie nie jest zbyt lamerskie.

Pozdrawiam!
Gambit
Maciej
2004-01-18 13:29:35 UTC
Permalink
Post by Gambit
Hi!
Jestem tu nowy, więc na początek witam wszystkich grupowiczów!
Dopiero zacząłem uczyć się C++ i mam pewien problem.
#include <iostream>
using namespace std;
void test(int a[]) {
cout << "sizeof(a) = " << sizeof(a) << endl;
}
int main() {
int a[20];
cout << "sizeof(a) = " << sizeof(a) << endl;
test(a);
}
Dlaczego w main wyświetla wszystko dobrze tzn. że tablica ma rozmiar 80
bitów, a w metodzie test traktuje wskaźnik do tablicy jako (jak
przypuszczam) pierwszy element tej tablicy i zwraca że rozmiar "a" jest
równy 4bity? Dlaczego nie traktuje wskaźnika jako tablicę, tylko jako po
prostu jakieś miejsce w pamięci, które równie dobrze może być wskaźnikiem
do int'a? A może moje przypuszczenia są błędne i takie zachowanie jest "mile
widziane" (nie wiedziałem jakiego słowa tu użyć :)?
Mam nadzieję, że moje pytanie nie jest zbyt lamerskie.
Pozdrawiam!
Gambit
dlatego ze "nazwa tablicy jest adresem jej zerowego element". jeden
element int=4bajty
Post by Gambit
pozdr();
Maciej
***@wp.pl
Maciej
2004-01-18 13:39:48 UTC
Permalink
Post by Maciej
Post by Gambit
Hi!
Jestem tu nowy, więc na początek witam wszystkich grupowiczów!
Dopiero zacząłem uczyć się C++ i mam pewien problem.
#include <iostream>
using namespace std;
void test(int a[]) {
cout << "sizeof(a) = " << sizeof(a) << endl;
}
int main() {
int a[20];
cout << "sizeof(a) = " << sizeof(a) << endl;
test(a);
}
Dlaczego w main wyświetla wszystko dobrze tzn. że tablica ma rozmiar 80
bitów, a w metodzie test traktuje wskaźnik do tablicy jako (jak
przypuszczam) pierwszy element tej tablicy i zwraca że rozmiar "a" jest
równy 4bity? Dlaczego nie traktuje wskaźnika jako tablicę, tylko jako po
prostu jakieś miejsce w pamięci, które równie dobrze może być
wskaźnikiem
Post by Maciej
Post by Gambit
do int'a? A może moje przypuszczenia są błędne i takie zachowanie jest
"mile
Post by Gambit
widziane" (nie wiedziałem jakiego słowa tu użyć :)?
Mam nadzieję, że moje pytanie nie jest zbyt lamerskie.
Pozdrawiam!
Gambit
dlatego ze "nazwa tablicy jest adresem jej zerowego element". jeden
element int=4bajty
Post by Gambit
pozdr();
Maciej
dlatego nie traktuje ci zmiennej jako calej tablicy tylko jako jeden
element
Post by Maciej
pozdr();
Maciej
***@wp.pl
Gambit
2004-01-18 13:46:18 UTC
Permalink
Post by Maciej
dlatego nie traktuje ci zmiennej jako calej tablicy tylko jako jeden
element
A dlaczego w pierwszym przypadku traktuje zmienną "a"
jako tablicę, przecież podobno zawsze nazwa tablicy jest
wskaźnikiem do jej pierwszego elementu? Dlaczego
kompilator nie zachowuje się tak samo w obydwu
przypadkach? Dla mnie jest to co najmniej trochę nie
logiczne zachowanie.

Pozdrawiam!
Gambit
Sullivan
2004-01-18 13:52:33 UTC
Permalink
Post by Gambit
A dlaczego w pierwszym przypadku traktuje zmienną "a"
jako tablicę, przecież podobno zawsze nazwa tablicy jest
wskaźnikiem do jej pierwszego elementu? Dlaczego
kompilator nie zachowuje się tak samo w obydwu
przypadkach? Dla mnie jest to co najmniej trochę nie
logiczne zachowanie.
Napisalem ci 2-3 minuty temu :)
Sullivan
2004-01-18 13:44:21 UTC
Permalink
Post by Gambit
Dlaczego w main wyświetla wszystko dobrze tzn. że tablica ma rozmiar 80
bitów, a w metodzie test traktuje wskaźnik do tablicy jako (jak
przypuszczam) pierwszy element tej tablicy i zwraca że rozmiar "a" jest
równy 4bity? Dlaczego nie traktuje wskaźnika jako tablicę, tylko jako po
prostu jakieś miejsce w pamięci, które równie dobrze może być wskaźnikiem
do int'a? A może moje przypuszczenia są błędne i takie zachowanie jest "mile
widziane" (nie wiedziałem jakiego słowa tu użyć :)?
Bo funkcja test nie wie jakiego rozmiaru jest ta tablica, własciwie jedyne
co jej przekazujesz to adres pierwszego elementu tablicy (int a[] czyli int
*a). Dlatego zwraca
taki wynik. W funkcji main przy deklarowaniu tablicy "na sztywno" podajesz
rozmiar tablicy wiec program wie, ze tablica ma 20 elementow i stad poprawny
wynik. Ogolnie tablice typu typ a[]; np. int a[]; nie "przechowuja" nigdzie
rozmiaru tablicy. Podajac tablice jako argument do funkcji przekazujesz
tylko, jak juz wspomnialem, tylko "adres" tej tablicy. Rozmiar musisz podac
wiec jako osobny argument np.:

void test(int a[], int rozmiar) {
cout << "rozmiar a = " << rozmiar << endl;
for(int i = 0; i < rozmiar; i++)
cout << "a [" << i << "] = " << a[i] << endl;
}

Mozesz tez uzywac np. vectora z biblioteki standardowej ale mysle, ze na
razie lepiej zrozumiec takie tablice.

Pozdrawiam
Gambit
2004-01-18 14:36:24 UTC
Permalink
Post by Sullivan
Bo funkcja test nie wie jakiego rozmiaru jest ta tablica, własciwie jedyne
co jej przekazujesz to adres pierwszego elementu tablicy (int a[] czyli int
*a). Dlatego zwraca
taki wynik. W funkcji main przy deklarowaniu tablicy "na sztywno" podajesz
rozmiar tablicy wiec program wie, ze tablica ma 20 elementow i stad poprawny
wynik. Ogolnie tablice typu typ a[]; np. int a[]; nie "przechowuja" nigdzie
rozmiaru tablicy. Podajac tablice jako argument do funkcji przekazujesz
tylko, jak juz wspomnialem, tylko "adres" tej tablicy. Rozmiar musisz podac
Nie ma jak Java, gdzie tablice mają własną składową length, a jak wyjdziesz
po za zakres tablicy to wyrzucany jest IndexOutOfArrayException... No, ale
za takie udogodnienia płaci się szybkością...
Dzięki za pomoc!

Pozdrawiam!
Gambit
Gambit
2004-01-18 14:46:26 UTC
Permalink
Sorry za zdublowaną wiadomość. #$^%& m$ oUTLOOK... niby raz wysłał, a tu...
Jeszcze raz sorry.

Pozdrawiam!
Gambit
Gambit
2004-01-18 14:36:24 UTC
Permalink
Post by Sullivan
Bo funkcja test nie wie jakiego rozmiaru jest ta tablica, własciwie jedyne
co jej przekazujesz to adres pierwszego elementu tablicy (int a[] czyli int
*a). Dlatego zwraca
taki wynik. W funkcji main przy deklarowaniu tablicy "na sztywno" podajesz
rozmiar tablicy wiec program wie, ze tablica ma 20 elementow i stad poprawny
wynik. Ogolnie tablice typu typ a[]; np. int a[]; nie "przechowuja" nigdzie
rozmiaru tablicy. Podajac tablice jako argument do funkcji przekazujesz
tylko, jak juz wspomnialem, tylko "adres" tej tablicy. Rozmiar musisz podac
Nie ma jak Java, gdzie tablice mają własną składową length, a jak wyjdziesz
po za zakres tablicy to wyrzucany jest IndexOutOfArrayException... No, ale
za takie udogodnienia płaci się szybkością...
Dzięki za pomoc!

Pozdrawiam!
Gambit
Sullivan
2004-01-18 14:54:24 UTC
Permalink
Post by Gambit
Nie ma jak Java, gdzie tablice mają własną składową length, a jak wyjdziesz
po za zakres tablicy to wyrzucany jest IndexOutOfArrayException... No, ale
za takie udogodnienia płaci się szybkością...
Dzięki za pomoc!
Ano... zawsze mozesz napisac wlasna klase Tablica, np. jako wzorcowa :)
Dobre i proste cwiczenie z C++.

Pozdrawiam
Gambit
2004-01-18 15:01:18 UTC
Permalink
Post by Sullivan
Ano... zawsze mozesz napisac wlasna klase Tablica, np. jako wzorcowa :)
Dobre i proste cwiczenie z C++.
Hmmm... dobry pomysł - zrobie sobie taką klasę jako ćwiczenie.
Dzięki za inspirację.

Pozdrawiam!
Gambit
Micha³ R.
2004-01-18 15:36:08 UTC
Permalink
Użyj std:vector<typ> gdzie też jest metoda zwracająca
długość.
Jest także metoda at(int index), która rzuci wyjątek jak wyjedziesz
poza tablicę.
Oraz dużo, dużo innych funkcji....

Pozdrawiam
Maciej
2004-01-18 13:55:38 UTC
Permalink
Post by Gambit
Hi!
Jestem tu nowy, więc na początek witam wszystkich grupowiczów!
Dopiero zacząłem uczyć się C++ i mam pewien problem.
#include <iostream>
using namespace std;
void test(int a[]) {
cout << "sizeof(a) = " << sizeof(a) << endl;
}
int main() {
int a[20];
cout << "sizeof(a) = " << sizeof(a) << endl;
test(a);
}
Dlaczego w main wyświetla wszystko dobrze tzn. że tablica ma rozmiar 80
bitów, a w metodzie test traktuje wskaźnik do tablicy jako (jak
przypuszczam) pierwszy element tej tablicy i zwraca że rozmiar "a" jest
równy 4bity? Dlaczego nie traktuje wskaźnika jako tablicę, tylko jako po
prostu jakieś miejsce w pamięci, które równie dobrze może być wskaźnikiem
do int'a? A może moje przypuszczenia są błędne i takie zachowanie jest "mile
widziane" (nie wiedziałem jakiego słowa tu użyć :)?
Mam nadzieję, że moje pytanie nie jest zbyt lamerskie.
Pozdrawiam!
Gambit
musisz zrozumiec to ze nie przesyla sie calej tablicy do funkcji,
wystarczy jej ades, i masz wszystko zalatwione tzn. mozesz z niej korzystac
w tej funkcji.
Post by Gambit
pozdr();
Maciej
***@wp.pl
Marcin 'Qrczak' Kowalczyk
2004-01-18 15:49:34 UTC
Permalink
Post by Gambit
void test(int a[]) {
Deklaracja parametru funkcji postaci "typ a[]" jest równoważna "typ *a".
Taka składnia to zaszłość historyczna - w antycznym C tak wyglądała
deklaracja każdej zmiennej wskaźnikowej. Parametr funkcji nigdy nie jest
typu tablicowego.

To dotyczy tylko parametrów funkcji! Deklaracja zmiennej globalnej
albo lokalnej postaci "typ a[]" oznacza tablicę, a nie wskaźnik (przy
czym jeśli nie podajemy jej rozmiaru, to musimy albo podać początkowe
wartości elementów, albo to musi być tylko deklaracja tablicy z innego
pliku, ze słowem extern).
Post by Gambit
cout << "sizeof(a) = " << sizeof(a) << endl;
Więc tutaj jest rozmiar wskaźnika, a nie tablicy (ani elementu tablicy,
jak ktoś tu błędnie powiedział).
Post by Gambit
int a[20];
cout << "sizeof(a) = " << sizeof(a) << endl;
test(a);
Natomiast tutaj wyrażenie "a" typu tablicowego jest konwertowane
na wskaźnik do pierwszego elementu. Taka konwersja jest wykonywana
w większości sytuacji, w których wyrażenie typu tablicowego jest użyte
(poza argumentem &, argumentem sizeof i - w przypadku C++ - spodziewania
się referencji na tablicę).

Nieporozumienia dotyczące tablic i wskaźników są w nauce C/C++ bardzo
częste. Ciekawe, dlaczego. Może dlatego, że reguły są zakręcone
i niespotykane w innych językach? Albo istnieją jakieś wprowadzające
w błąd książki? Albo książki za mało poruszają ten temat?
--
__("< Marcin Kowalczyk
\__/ ***@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
Rafal Dabrowa
2004-01-18 17:25:47 UTC
Permalink
Post by Marcin 'Qrczak' Kowalczyk
Nieporozumienia dotyczące tablic i wskaźników są w nauce C/C++ bardzo
częste. Ciekawe, dlaczego. Może dlatego, że reguły są zakręcone
i niespotykane w innych językach? Albo istnieją jakieś wprowadzające
w błąd książki? Albo książki za mało poruszają ten temat?
Tak, jest nieintuicyjne. Powiedzmy, ze masz:
int idx;
i jak wolasz:
f(idx)
to idx nie zamienia sie na wskaznik do inta. Podobnie jak masz:
struct MyStruct { int a, b; } ms;
to potem jak przekazukesz ms do funkcji:
f(ms);
to nie zamienia Ci sie to na wskaznik do struktury. Dlaczego wiec
gdy definujesz tablice:
int tab[100];
to gdy przekazujesz do funkcji:
f(tab);
to nagle robi ci sie z tego wskaznik ? W odroznieniu od np. Pascala,
gdzie tablica jest zawsze tablica. Tam jak przekazesz tab do
funkcji, to bedziesz mial w funkcji kopie tablicy. Chyba, ze
przekazujesz przez "zmienna" (odpowiednik referencji).


Rafal
--
sed -e s/s/a/g <my_address >my_right_address
Marcin 'Qrczak' Kowalczyk
2004-01-18 22:12:07 UTC
Permalink
Post by Rafal Dabrowa
Post by Marcin 'Qrczak' Kowalczyk
Nieporozumienia dotyczące tablic i wskaźników są w nauce C/C++ bardzo
częste. Ciekawe, dlaczego. Może dlatego, że reguły są zakręcone
i niespotykane w innych językach? Albo istnieją jakieś wprowadzające
w błąd książki? Albo książki za mało poruszają ten temat?
Tak, jest nieintuicyjne.
Hmm, to chyba było pytanie retoryczne :-)

Warto zwrócić uwagę, że to jest wskaźnik do pierwszego (zerowego)
*elementu* tablicy, a nie do całej tablicy. Wskaźnik do całej tablicy
można uzyskać pisząc &tablica i on ma inny typ! Rzadko się takich używa.
Typ wskaźnika do tablicy zawiera w sobie rozmiar tej tablicy, który musi
być statycznie znany.

BTW, to, że tablica jest przy przekazywaniu przez argument konwertowana
na wskaźnik, zostało wykorzystane przez bibliotekę GMP:

| When a GMP variable is used as a function parameter, it's
| effectively a call-by-reference, meaning if the function stores a value
| there it will change the original in the caller. Parameters which are
| input-only can be designated `const' to provoke a compiler error or
| warning on attempting to modify them.
|
| When a function is going to return a GMP result, it should designate
| a parameter that it sets, like the library functions do. More than one
| value can be returned by having more than one output parameter, again
| like the library functions. A `return' of an `mpz_t' etc doesn't return
| the object, only a pointer, and this is almost certainly not what's
| wanted.
[...]
| For interest, the GMP types `mpz_t' etc are implemented as
| one-element arrays of certain structures. This is why declaring a
| variable creates an object with the fields GMP needs, but then using it
| as a parameter passes a pointer to the object.

W powyższym opisie jest drobny błąd: próba zwrócenia mpz_t jako
wyniku bezpośrednio to błąd kompilacji - funkcja nie może zwrócić
tablicy - a nie zwrócenie wskaźnika. Chyba że zadeklarujemy typ wyniku
jako void *. Dlatego kiedy potrzebowałem malutkiej funkcji inline,
która zwraca wskaźnik mpz_t wyciągnięty z pewnej struktury, to żeby
było bezpieczniejsze pod względem typów zrobiłem makro zamiast funkcji.
Alternatywnie mógłbym zwrócić wskaźnik na strukturę, która jest typem
elementu tej jednoelementowej tablicy, ale ona ma nazwę __mpz_struct,
która jest prywatna dla GMP i nie należy jej używać.

Zabawniejsza sprawa jest ze wskaźnikami na funkcje. Tutaj wyrażenie,
które jest funkcją, może być niejawnie skonwertowane na wskaźnik do
tej funkcji (a z drugiej strony wskaźnik na funkcję można zaaplikować
do argumentów tak jakby to była funkcja). Ponieważ w odróżnieniu od
tablic nie mamy zamiany jednego kawałka typu na inny (tablicy na
wskaźnik), tylko dodanie jednego poziomu wskaźnikowości, można napisać
*****funkcja i to jest to samo co funkcja - wskaźnik na nią.
--
__("< Marcin Kowalczyk
\__/ ***@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
Rafal Dabrowa
2004-01-19 07:41:49 UTC
Permalink
Post by Marcin 'Qrczak' Kowalczyk
Warto zwrócić uwagę, że to jest wskaźnik do pierwszego (zerowego)
*elementu* tablicy, a nie do całej tablicy.
Rzeczywiscie, drobne przeoczenie.
BTW. Scisile związana jest z tym cala arytmetyka na wskaznikach.
Z ktorej (tak mysle) komitet ISO wycofalby sie, gdyby mogl.
Dlaczego ? Bo to sie nie sprawdza w przypadku dziedziczenia.
Są, powiedzmy, dwie klasy:

class A { int i; };
class B : A { int j; };
W kodzie mozesz napisac:
A *pAtab = new B[10];
A a = pAtab[3]; // bynajmniej, nie bedzie to trzeci element B[10].

Dlaczego nie bedzie to trzeci element B[10] ? Bo offset w pamieci
bedzie naliczany wedlug sizeof(A) !
Kompilator nawet nie wypisze ostrzezenia. A program w sposob
ewidentny sie wywali.


Rafal
--
sed -e s/s/a/g <my_address >my_right_address
Gambit
2004-01-18 19:44:20 UTC
Permalink
Post by Marcin 'Qrczak' Kowalczyk
Post by Gambit
void test(int a[]) {
Deklaracja parametru funkcji postaci "typ a[]" jest równoważna "typ *a".
Taka składnia to zaszłość historyczna - w antycznym C tak wyglądała
deklaracja każdej zmiennej wskaźnikowej. Parametr funkcji nigdy nie jest
typu tablicowego.
To dotyczy tylko parametrów funkcji! Deklaracja zmiennej globalnej
albo lokalnej postaci "typ a[]" oznacza tablicę, a nie wskaźnik (przy
czym jeśli nie podajemy jej rozmiaru, to musimy albo podać początkowe
wartości elementów, albo to musi być tylko deklaracja tablicy z innego
pliku, ze słowem extern).
Post by Gambit
cout << "sizeof(a) = " << sizeof(a) << endl;
Więc tutaj jest rozmiar wskaźnika, a nie tablicy (ani elementu tablicy,
jak ktoś tu błędnie powiedział).
Post by Gambit
int a[20];
cout << "sizeof(a) = " << sizeof(a) << endl;
test(a);
Natomiast tutaj wyrażenie "a" typu tablicowego jest konwertowane
na wskaźnik do pierwszego elementu. Taka konwersja jest wykonywana
w większości sytuacji, w których wyrażenie typu tablicowego jest użyte
(poza argumentem &, argumentem sizeof i - w przypadku C++ - spodziewania
się referencji na tablicę).
Nieporozumienia dotyczące tablic i wskaźników są w nauce C/C++ bardzo
częste. Ciekawe, dlaczego. Może dlatego, że reguły są zakręcone
i niespotykane w innych językach? Albo istnieją jakieś wprowadzające
w błąd książki? Albo książki za mało poruszają ten temat?
Czyli jak ktoś napisze bibliotekę i napiszę w niej funkcję której argumentem
jest np.: "int* i" to bez dokumentacji nie ma co nawet się próbować domyślać
czy chodzi o tablicę, czy poprostu wskaźnik do int'a... chyba że z nazwy
funkcji można wywnioskować jakie argumenty przekazać.... Bardzo łatwy sposób
na błędy.
A tak w ogóle to zwykły wskaźnik do int'a można potraktować jako pierwszy
index tablicy?

Pozdrawiam!
Gambit

ps. Ja programowałem wcześniej w języku gdzie tablica zawsze była tablicę i
nie dało się tego zmienić (i nic nie mogło udawać tablicy).
Rafal Dabrowa
2004-01-18 21:04:10 UTC
Permalink
Post by Gambit
Czyli jak ktoś napisze bibliotekę i napiszę w niej funkcję której argumentem
jest np.: "int* i" to bez dokumentacji nie ma co nawet się próbować domyślać
czy chodzi o tablicę, czy poprostu wskaźnik do int'a... chyba że z nazwy
funkcji można wywnioskować jakie argumenty przekazać.... Bardzo łatwy sposób
na błędy.
No, niestety - trzeba wiedziec co funkcja robi. A czy to jest sposob na
bledy...
Ja w swojej praktyce nigdy nie mialem z tym problemu. To kwestia wyuczenia.
Post by Gambit
A tak w ogóle to zwykły wskaźnik do int'a można potraktować jako pierwszy
index tablicy?
Tak. Jesli napiszesz:

int tab[5];
int *ptab;

ptab = tab; // niejawne kastowanie tablicy tab na wskaznik do
pierwszego elementu !

To *tab bedzie tym samym co tab[0] i tym samym co ptab[0] i tym samym co
*ptab.



Rafal
--
sed -e s/s/a/g <my_address >my_right_address
Marcin 'Qrczak' Kowalczyk
2004-01-18 21:56:49 UTC
Permalink
Post by Gambit
Czyli jak ktoś napisze bibliotekę i napiszę w niej funkcję której argumentem
jest np.: "int* i" to bez dokumentacji nie ma co nawet się próbować domyślać
czy chodzi o tablicę, czy poprostu wskaźnik do int'a...
Prawda.

Niektórzy stosują konwencję, że T param[] oznacza wskaźnik do tablicy,
a T *param - do pojedynczego elementu. Przy czym to jest tylko konwencja,
z punktu widzenia języka to to samo. Tej konwencji nie da się zastosować
do zwykłej zmiennej, pola struktury/klasy ani elementów tablicy - tylko
do parametrów funkcji.
Post by Gambit
A tak w ogóle to zwykły wskaźnik do int'a można potraktować jako pierwszy
index tablicy?
Tak - tablicy długości 1. p[0] to jest to samo co *p.

Nie dotyczy usuwania obiektów w C++, gdzie trzeba rozróżniać delete
i delete[], mimo że w typie rozróżnienia między elementem a tablicą
nie ma.
Post by Gambit
ps. Ja programowałem wcześniej w języku gdzie tablica zawsze była tablicę
i nie dało się tego zmienić (i nic nie mogło udawać tablicy).
Tak jest w każdym znanym mi języku poza C i C++.
--
__("< Marcin Kowalczyk
\__/ ***@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
Maciej
2004-01-18 20:24:43 UTC
Permalink
Post by Marcin 'Qrczak' Kowalczyk
Więc tutaj jest rozmiar wskaźnika, a nie tablicy (ani elementu tablicy,
jak ktoś tu błędnie powiedział).
dzieki, ze zwrociles mi uwage, ale chodzilo mi wlasnie o wskaznik do
tablicy, tj. jej adres
Post by Marcin 'Qrczak' Kowalczyk
pozdr();
Maciej
***@wp.pl
Gambit
2004-01-18 19:44:20 UTC
Permalink
Post by Marcin 'Qrczak' Kowalczyk
Post by Gambit
void test(int a[]) {
Deklaracja parametru funkcji postaci "typ a[]" jest równoważna "typ *a".
Taka składnia to zaszłość historyczna - w antycznym C tak wyglądała
deklaracja każdej zmiennej wskaźnikowej. Parametr funkcji nigdy nie jest
typu tablicowego.
To dotyczy tylko parametrów funkcji! Deklaracja zmiennej globalnej
albo lokalnej postaci "typ a[]" oznacza tablicę, a nie wskaźnik (przy
czym jeśli nie podajemy jej rozmiaru, to musimy albo podać początkowe
wartości elementów, albo to musi być tylko deklaracja tablicy z innego
pliku, ze słowem extern).
Post by Gambit
cout << "sizeof(a) = " << sizeof(a) << endl;
Więc tutaj jest rozmiar wskaźnika, a nie tablicy (ani elementu tablicy,
jak ktoś tu błędnie powiedział).
Post by Gambit
int a[20];
cout << "sizeof(a) = " << sizeof(a) << endl;
test(a);
Natomiast tutaj wyrażenie "a" typu tablicowego jest konwertowane
na wskaźnik do pierwszego elementu. Taka konwersja jest wykonywana
w większości sytuacji, w których wyrażenie typu tablicowego jest użyte
(poza argumentem &, argumentem sizeof i - w przypadku C++ - spodziewania
się referencji na tablicę).
Nieporozumienia dotyczące tablic i wskaźników są w nauce C/C++ bardzo
częste. Ciekawe, dlaczego. Może dlatego, że reguły są zakręcone
i niespotykane w innych językach? Albo istnieją jakieś wprowadzające
w błąd książki? Albo książki za mało poruszają ten temat?
Czyli jak ktoś napisze bibliotekę i napiszę w niej funkcję której argumentem
jest np.: "int* i" to bez dokumentacji nie ma co nawet się próbować domyślać
czy chodzi o tablicę, czy poprostu wskaźnik do int'a... chyba że z nazwy
funkcji można wywnioskować jakie argumenty przekazać.... Bardzo łatwy sposób
na błędy.
A tak w ogóle to zwykły wskaźnik do int'a można potraktować jako pierwszy
index tablicy?

Pozdrawiam!
Gambit

ps. Ja programowałem wcześniej w języku gdzie tablica zawsze była tablicę i
nie dało się tego zmienić (i nic nie mogło udawać tablicy).
Bronek Kozicki
2004-01-19 10:26:11 UTC
Permalink
Post by Gambit
#include <iostream>
using namespace std;
void test(int a[]) {
cout << "sizeof(a) = " << sizeof(a) << endl;
}
int main() {
int a[20];
cout << "sizeof(a) = " << sizeof(a) << endl;
test(a);
}
W C++ zamiast "a[]" powinieneś użyć typu std::vector. Jest
bezpieczniejszy.

#include <vector>
#include <iostream>

template <typename T>
void test(const std::vector<T>& v) {
std::cout << "size = " << v.size() << std::endl;
}

int main() {
std::vector<int> a(20);
std::cout << "size = " << a.size() << std::endl;
test(a);
}

Jeżeli z jakiś powodów musisz przekazać tablicę C do funkcji, możesz to
zrobić (nie tracą informacji o jej rozmiarze) korzystając z szablonu:

#include <iostream>

template <typename T, int SIZE>
void test(T (&v) [SIZE]) {
// przekazujemy tablice przez referencje
std::cout << "size = " << sizeof(v) << std::endl;
}

int main() {
int a[20];
std::cout << "size = " << sizeof(a) << std::endl;
test(a);
}

Acha, oczywiście widać na powyższym przykładzie że std::vector::size()
zwraca informację o liczbie elementów, podczas gdy sizeof(dane) zwraca
informację o całkowitej ilości bajtów zajętej przez tablicę.


B.
Gambit
2004-01-19 15:55:39 UTC
Permalink
Post by Bronek Kozicki
Post by Gambit
#include <iostream>
using namespace std;
void test(int a[]) {
cout << "sizeof(a) = " << sizeof(a) << endl;
}
int main() {
int a[20];
cout << "sizeof(a) = " << sizeof(a) << endl;
test(a);
}
W C++ zamiast "a[]" powinieneś użyć typu std::vector. Jest
bezpieczniejszy.
#include <vector>
#include <iostream>
template <typename T>
void test(const std::vector<T>& v) {
std::cout << "size = " << v.size() << std::endl;
}
int main() {
std::vector<int> a(20);
std::cout << "size = " << a.size() << std::endl;
test(a);
}
Jeżeli z jakiś powodów musisz przekazać tablicę C do funkcji, możesz to
#include <iostream>
template <typename T, int SIZE>
void test(T (&v) [SIZE]) {
// przekazujemy tablice przez referencje
std::cout << "size = " << sizeof(v) << std::endl;
}
int main() {
int a[20];
std::cout << "size = " << sizeof(a) << std::endl;
test(a);
}
Acha, oczywiście widać na powyższym przykładzie że std::vector::size()
zwraca informację o liczbie elementów, podczas gdy sizeof(dane) zwraca
informację o całkowitej ilości bajtów zajętej przez tablicę.
Do szablonów jeszcze nie doszedłem, ale zapowiada się imponująco. Dzięki za
pomoc!

Pozdrawiam!
Gambit

ps. sizeof zwraca ilość bajtów, czy bitów?
Bronek Kozicki
2004-01-19 16:46:30 UTC
Permalink
Post by Gambit
ps. sizeof zwraca ilość bajtów, czy bitów?
sizeof zawsze zwraca ilość bajtów. Z definicji char ma jeden bajt, czyli
zawsze sizeof(char) == 1. Liczbę bitów w bajcie określa makro CHAR_BIT z
nagłówka <climits>, czyli całkowita objętość typu w bitach to
sizeof(Klasa) * CHAR_BIT. Z zastrzeżeniem, że mierzenie zajętości
pamięci w bitach to bardzo orginalny pomysł :>


B.

Loading...