Ĺadny brzuch
Witam, mam taką funkcję:
void wyswietl2(void *tab[]) { wyswietlWymierna(*(dlugaWymierna*)tab[0]); }
a w funkcji main wywołuje ją podając jej jako parametr tablice objektów typu dlugaWymierna. Funkcja wyswietlWymierna pobiera przez wartość obiekt typu dlugaWymierna i ladnie go wyswietla, jezeli jest wywolywana normalnie bez tych wszystkich rzutowań to działa ok. Kod się kompiluje, ale po uruchomieniu mam bład naruszenia ochrony pamięci! Wie ktoś co może być nie tak? Oczywiście funkcja którą tu napisałem ma tylko zilustrować mój problem przesyłania tablicy void* do funkcji i w której będzie traktowana jako obiekt innego typu.
Użytkownik mjetek edytował ten post 31 maj 2007, 18:44
Tak powinno być dobrze:
void wyswietl2(void** tab) { wyswietlWymierna(*((dlugaWymierna*)tab+0)); //0 to oczywiscie indeksy w tablicy }
Dzieki, faktycznie działa :)
jeszcze dodam, że
tab[] to to samo co *tab, a
tab[][] = **tab = *tab[]
może mi ktoś wyjaśnić dlaczego tab[0] wywala błąd naruszenia pamięci a tab+0 działa ok ?? I jeszcze jedno, do tej samej funkcji przesylam tez wskaznik do funkcji, czyli mam: void wyswietl2(void** tab , unsigned short int (*porownaj)(void*, void*)) no i w funkcji wyswietl2 wywoluje cos takiego: printf("\ntest funkcji porownajWymierne: %i\n", (*porownaj)(tab+0, tab+1)); co powoduje zawieszenie sie programu. Funkcja przesylana przez wskaźnik, jako argument z main do wyswietl2 jest funkcja o takiej deklaracji: unsigned short int porownajWymierne(void* l1, void* l2); oczywiście sama ta funkcja działa bez zarzutów w normalnych warunkach:)
Użytkownik mjetek edytował ten post 31 maj 2007, 22:14
Wychodzą tutaj róznice w kolejności operatorów. W zapisie z +. dzięki jego mniejszemu priorytetowi najpierw wykonywało się rzutowanie na określony typ a dopiero potem dodanie odpowiedniej wartości przesuwającej nas w pamięci o określoną ilość bajtów. W przypadku drugim, [] są najwidoczniej silniejszym operatorem i najpier wykonywało się przesunięcie w momencie gdy dla naszego programu typ tablicy był ciągle void czyli nijaki, więc wywalał błąd. Gdy najpierw zrzutujemy wskaźnik na tablicę na typ, a dopiero potem użyjemy [] będzie wszystko ok :)
void wyswietl2(void** tab) { wyswietlWymierna( ((dlugaWymierna*)tab)[0] ); }
ps. zapis void** tab czy void* tab[] nie robi rzadnej różnicy.
edit------------
ps2. ale błędów nasadziłem logiczno zdaniowych :)
Użytkownik reVis edytował ten post 31 maj 2007, 22:09
może mi ktoś wyjaśnić dlaczego tab[0]wywala błąd naruszenia pamięci a tab+0 działa ok ??
:)
Załóżmy, że mamy tablicę zadeklarowaną tak:
char tab[] = "abcd";
wtedy:
tab[1] == 'b',
tab + 1 == &tab[1] == "jakiśtampointerhexvalue"
//
jeżeli masz funkcję:
unsigned short int porownajWymierne(void*, void*);
i chcesz ją przekazać, to możesz zrobić to tak(:)):
wyswietl2(tab , porownajWymierne)
albo zrobić wskaźnik do niej tak:
unsigned short int (*ptopw)(void*, void*);
a, dalej przypisać wskaźnikowi funkcję:
ptopw = porownajWymierne;
Następnie tam gdzie printf:
void wyswietl2(void** tab, unsigned short int (*porownaj)(void*, void*)) { printf("\ntest funkcji porownajWymierne: %i\n", porownaj(tab+0, tab+1)); }
//
Jeszcze jedno: jak masz jakiś "objekt" typu "wymierna", to zadeklaruj go jako ten typ (typedef), a nie jako "jakiś tam" void. Będziesz miał mniej kłopotów przy sprawdzaniu jakichkolwiek błędów.
//
Użytkownik Radek edytował ten post 01 czerwiec 2007, 14:47
powiedzmy, że mam teraz taki kod:
void wyswietl2(void** tab) { int i, m; void* wsk1=&tab[0]; void* wsk2=&tab[1]; printf("\nwsk1: "); wyswietlWymierna(*(dlugaWymierna*)wsk1); printf("\nwsk2: "); wyswietlWymierna(*(dlugaWymierna*)wsk2); printf("\n"); }
no i po wywolaniu tej funkcji z parametrem tablicy liczb typu dlugaWymierna program zawiesza sie po wyswietleniu pierwszego wskaznika. Domyslam sie ze chodzi o to, że typ długaWymierna zajmuje większy obszar w pamięci niż typ void więc po zrzutowaniu wsk2 na typ dlugaWymierna wskazuje on na jakiś tam adres zajmowany jeszcze prawdopodobnie przez wsk1 no i program się wysypuje. Działać to będzie gdy zrzutuje sobie tab[1] na (dlugaWymierna*)i dopiero po tym przypisze go do zmiennej wsk2, ale niestety nie mogę tak zrobić ponieważ muszę napisać funkcje bardziej uniwersalna do ktorej bede wysylal obiekty inych typow nie tylko typu dlugaWymierna- musze zrealizowac swego rodzaju polimorfizm w C :)
Najprostszym substytutem będzie zastosowanie dodatkowego wskaźnika na funkcję tak jak zaproponował Radek. To jedyne sensowne wyjście w takiej sytuacji, bez zagłębiania się w strukturalny zapis OO z C++.
Chodzi ci o coś w tym stylu?
void wyswietl2(void** tab, void (*tmp)(void*, void*)) { int i, m; void* wsk1=tab+0; void* wsk2=tab+1; (*tmp)(wsk1, wsk2); printf("\n"); } void tmp(void *l1, void *l2) { printf("\nw funkcji tmp\n"); wyswietlWymierna(*(dlugaWymierna*)l1); printf("\n"); wyswietlWymierna(*(dlugaWymierna*)l2); printf("\nkoniec tmp\n"); }
i w main daje wyswietl2(&liczby, &tmp); i program wywali się po wyświetleniu:
w funkcji tmp i wartości z tab[0], zadziała dobrze jeśli zrzutuje tab[0] i tab[1] na (dlugaWymierna*) ale funkcja wyswietl2 ma radzic sobie z roznymi innymie strukturami wiec nie moge sobie na to pozwolic!
Przepraszam... Trochę jednak się zagalopowałem z poprzednim komentarzem. Fakt sama funkcja nic Ci nie da. Ale już przekazanie do funkcji wywołującej rozmiaru struktury, da już możliwość przesuwania się po pamięci. Ja to widzę mniej więcej tak:#include <stdio.h> #include <stdlib.h> typedef struct { int a; int b; } pair; void do_something(void* tab, int size, void (*fun)(void*)) { int i; for(i=0; i<10; i++) fun(tab+size*i); } void show_pair(void* _pair) { printf("%d = %d\n", ((pair*)_pair)->a, ((pair*)_pair)->b ); } int main(int argc, char** argv) { pair p[10]; int i; for(i=0; i<10; i++) { p[i].a=i; p[i].b=i*i; } do_something((void*)p, sizeof(pair), show_pair); return EXIT_SUCCESS; }
zanotowane.pl doc.pisz.pl pdf.pisz.pl zsf.htw.pl
void wyswietl2(void *tab[]) { wyswietlWymierna(*(dlugaWymierna*)tab[0]); }
a w funkcji main wywołuje ją podając jej jako parametr tablice objektów typu dlugaWymierna. Funkcja wyswietlWymierna pobiera przez wartość obiekt typu dlugaWymierna i ladnie go wyswietla, jezeli jest wywolywana normalnie bez tych wszystkich rzutowań to działa ok. Kod się kompiluje, ale po uruchomieniu mam bład naruszenia ochrony pamięci! Wie ktoś co może być nie tak? Oczywiście funkcja którą tu napisałem ma tylko zilustrować mój problem przesyłania tablicy void* do funkcji i w której będzie traktowana jako obiekt innego typu.
Użytkownik mjetek edytował ten post 31 maj 2007, 18:44
Tak powinno być dobrze:
void wyswietl2(void** tab) { wyswietlWymierna(*((dlugaWymierna*)tab+0)); //0 to oczywiscie indeksy w tablicy }
Dzieki, faktycznie działa :)
jeszcze dodam, że
tab[] to to samo co *tab, a
tab[][] = **tab = *tab[]
może mi ktoś wyjaśnić dlaczego tab[0] wywala błąd naruszenia pamięci a tab+0 działa ok ?? I jeszcze jedno, do tej samej funkcji przesylam tez wskaznik do funkcji, czyli mam: void wyswietl2(void** tab , unsigned short int (*porownaj)(void*, void*)) no i w funkcji wyswietl2 wywoluje cos takiego: printf("\ntest funkcji porownajWymierne: %i\n", (*porownaj)(tab+0, tab+1)); co powoduje zawieszenie sie programu. Funkcja przesylana przez wskaźnik, jako argument z main do wyswietl2 jest funkcja o takiej deklaracji: unsigned short int porownajWymierne(void* l1, void* l2); oczywiście sama ta funkcja działa bez zarzutów w normalnych warunkach:)
Użytkownik mjetek edytował ten post 31 maj 2007, 22:14
Wychodzą tutaj róznice w kolejności operatorów. W zapisie z +. dzięki jego mniejszemu priorytetowi najpierw wykonywało się rzutowanie na określony typ a dopiero potem dodanie odpowiedniej wartości przesuwającej nas w pamięci o określoną ilość bajtów. W przypadku drugim, [] są najwidoczniej silniejszym operatorem i najpier wykonywało się przesunięcie w momencie gdy dla naszego programu typ tablicy był ciągle void czyli nijaki, więc wywalał błąd. Gdy najpierw zrzutujemy wskaźnik na tablicę na typ, a dopiero potem użyjemy [] będzie wszystko ok :)
void wyswietl2(void** tab) { wyswietlWymierna( ((dlugaWymierna*)tab)[0] ); }
ps. zapis void** tab czy void* tab[] nie robi rzadnej różnicy.
edit------------
ps2. ale błędów nasadziłem logiczno zdaniowych :)
Użytkownik reVis edytował ten post 31 maj 2007, 22:09
może mi ktoś wyjaśnić dlaczego tab[0]wywala błąd naruszenia pamięci a tab+0 działa ok ??
:)
Załóżmy, że mamy tablicę zadeklarowaną tak:
char tab[] = "abcd";
wtedy:
tab[1] == 'b',
tab + 1 == &tab[1] == "jakiśtampointerhexvalue"
//
jeżeli masz funkcję:
unsigned short int porownajWymierne(void*, void*);
i chcesz ją przekazać, to możesz zrobić to tak(:)):
wyswietl2(tab , porownajWymierne)
albo zrobić wskaźnik do niej tak:
unsigned short int (*ptopw)(void*, void*);
a, dalej przypisać wskaźnikowi funkcję:
ptopw = porownajWymierne;
Następnie tam gdzie printf:
void wyswietl2(void** tab, unsigned short int (*porownaj)(void*, void*)) { printf("\ntest funkcji porownajWymierne: %i\n", porownaj(tab+0, tab+1)); }
//
Jeszcze jedno: jak masz jakiś "objekt" typu "wymierna", to zadeklaruj go jako ten typ (typedef), a nie jako "jakiś tam" void. Będziesz miał mniej kłopotów przy sprawdzaniu jakichkolwiek błędów.
//
Użytkownik Radek edytował ten post 01 czerwiec 2007, 14:47
powiedzmy, że mam teraz taki kod:
void wyswietl2(void** tab) { int i, m; void* wsk1=&tab[0]; void* wsk2=&tab[1]; printf("\nwsk1: "); wyswietlWymierna(*(dlugaWymierna*)wsk1); printf("\nwsk2: "); wyswietlWymierna(*(dlugaWymierna*)wsk2); printf("\n"); }
no i po wywolaniu tej funkcji z parametrem tablicy liczb typu dlugaWymierna program zawiesza sie po wyswietleniu pierwszego wskaznika. Domyslam sie ze chodzi o to, że typ długaWymierna zajmuje większy obszar w pamięci niż typ void więc po zrzutowaniu wsk2 na typ dlugaWymierna wskazuje on na jakiś tam adres zajmowany jeszcze prawdopodobnie przez wsk1 no i program się wysypuje. Działać to będzie gdy zrzutuje sobie tab[1] na (dlugaWymierna*)i dopiero po tym przypisze go do zmiennej wsk2, ale niestety nie mogę tak zrobić ponieważ muszę napisać funkcje bardziej uniwersalna do ktorej bede wysylal obiekty inych typow nie tylko typu dlugaWymierna- musze zrealizowac swego rodzaju polimorfizm w C :)
Najprostszym substytutem będzie zastosowanie dodatkowego wskaźnika na funkcję tak jak zaproponował Radek. To jedyne sensowne wyjście w takiej sytuacji, bez zagłębiania się w strukturalny zapis OO z C++.
Chodzi ci o coś w tym stylu?
void wyswietl2(void** tab, void (*tmp)(void*, void*)) { int i, m; void* wsk1=tab+0; void* wsk2=tab+1; (*tmp)(wsk1, wsk2); printf("\n"); } void tmp(void *l1, void *l2) { printf("\nw funkcji tmp\n"); wyswietlWymierna(*(dlugaWymierna*)l1); printf("\n"); wyswietlWymierna(*(dlugaWymierna*)l2); printf("\nkoniec tmp\n"); }
i w main daje wyswietl2(&liczby, &tmp); i program wywali się po wyświetleniu:
w funkcji tmp i wartości z tab[0], zadziała dobrze jeśli zrzutuje tab[0] i tab[1] na (dlugaWymierna*) ale funkcja wyswietl2 ma radzic sobie z roznymi innymie strukturami wiec nie moge sobie na to pozwolic!
Przepraszam... Trochę jednak się zagalopowałem z poprzednim komentarzem. Fakt sama funkcja nic Ci nie da. Ale już przekazanie do funkcji wywołującej rozmiaru struktury, da już możliwość przesuwania się po pamięci. Ja to widzę mniej więcej tak:#include <stdio.h> #include <stdlib.h> typedef struct { int a; int b; } pair; void do_something(void* tab, int size, void (*fun)(void*)) { int i; for(i=0; i<10; i++) fun(tab+size*i); } void show_pair(void* _pair) { printf("%d = %d\n", ((pair*)_pair)->a, ((pair*)_pair)->b ); } int main(int argc, char** argv) { pair p[10]; int i; for(i=0; i<10; i++) { p[i].a=i; p[i].b=i*i; } do_something((void*)p, sizeof(pair), show_pair); return EXIT_SUCCESS; }