Nowe posty

Autor Wątek: wskazniki, takblice, struktury, przekazywanie do funkcji  (Przeczytany 5605 razy)

goscccccccccccc

  • Gość
Mam mały problem. Cześć problemu jest opisana w komentarzach.

#include 


struct Struktura {
   char napis[20];
   float liczby[3];
   float inna_dana_liczbowa;
};

main(){
    struct Struktura *Dane[15]; // chce tablice wskaźników na struktury i myślę, że ją dostaję; funkcja ta działa miło i przyjemnie
    wczytaj_dane(Dane); // to są wskaźniki więc wydaje mi się, że amp (&) jest niepotrzebny
    pozamieniaj_dane(Dane);
}
wczytaj_dane(struct Struktura *Dane) // z gwiazdka bo tu deklaruje czym operuję - funkcja ta działa miło i przyjemnie
{
    int i =0;
    int j= 1;
    FILE *fp;
    fp=fopen("plikk", "r");
    while(j != EOF) {

        j = fscanf(fp ,"%s %f %f %f", Dane[i].napis, &Dane[i].liczby[0], &Dane[i].liczby[1], &Dane[i].liczby[2]);
        printf("Twoj napis to: %s a liczby to %f %f %f\\n", Dane[i].napis, Dane[i].liczby[0], Dane[i].liczby[1], Dane[i].liczby[2]);
        Dane[i].inna_dana_liczbowa = Dane[i].liczby[1] + Dane[i].liczby[2];
        i++;
    }
    return 0;
}
pozamieniaj_dane(struct Struktura *Dane) //tu mi się wykrzacza, albo kompilator sie pluje, że coś nie tak, albo nie daje mi to żadnych danych
{
    struct Struktura *temp; //wskaźnik odpowiedniego typu, chodz zastanawiam się czy nie mógł by być po prostu typu int, ale chyba nie
    if (Dane[1].inna_dana_liczbowa     {
          // chce tutaj zamiany wskaźników w ramach optymalizacji, bo ta nieokrojona wersja programu jest trochę cięższa ;-)
          temp = Dane[0].inna_dana_liczbowa; ///kompilator nic nie wypluwa na ta linię
          Dane[1].inna_dana_liczbowa = Dane[3].inna_dana_liczbowa; // "invalid lvalue in assignment"
          Dane[3].inna_dana_liczbowa = temp; // "invalid lvalue in assignment"
     }
}
Próbuję rożne opcje ampów i gwiazdek, ale nie eksperymentalne podejście zawodzi. Z kolei jak chce jakoś tak bardziej logicznie ;-) to mi by pasowało, żeby przy porównywaniu danych dodać gwiazdki (tam co napisałem, że kompilatorowi nie pasuje) i na moją logikę wszystko powinno być wtedy ok, ale nie jest.

Dzięki za wszelką pomoc.

chmooreck

  • Gość
wskazniki, takblice, struktury, przekazywanie do funkcji
« Odpowiedź #1 dnia: 2008-12-10, 23:18:58 »
1. Utworzyłeś tablicę wskaźników, ale nie masz nigdzie tworzenia struktur (new/malloc). Jeździsz sobie po pamięci. Nie zapomnij potem zwolnić zaalokowanej pamięci.
2. Jeśli chcesz zamienić miejscami wskaźniki (jak już będą poprawne - do zaalokowanego miejsca w pamięci) to powinno to wyglądać tak:
struct Struktura * temp = Dane + 1;
Dane + 1 = Dane + 3;
Dane + 3 = temp;
lub
struct Struktura * temp = &Dane[1];
&Dane[1] = &Dane[3];
&Dane[3] = temp;
Zgadza się ?
Jak się gdzieś walnąłem, to poprawcie - nie chciało mi się tego kompilować ;-)

Edit:
Moim skromnym zdaniem funkcje powinny przyjmować jako parametr tablicę wskaźników do strukturek, a nie wskaźniki do strukturek.
pozamieniaj_dane(struct Struktura *Dane[])
Edit2:
Cytuj
temp = Dane[0].inna_dana_liczbowa; ///kompilator nic nie wypluwa na ta linię
A mi wypluwa... na obie (tą poniżej)
aaa.c:36: error: incompatible types in assignment
aaa.c:38: error: incompatible types in assignment
i ma racje.. bo do wskaźnika próbujesz przypisać float'a i na odwrót...

Daj znać jak pousuwasz błędy ;-)

darkdancer

  • Gość
wskazniki, takblice, struktury, przekazywanie do funkcji
« Odpowiedź #2 dnia: 2008-12-11, 19:46:11 »
Cytat: goscccccccccccc
if (Dane[1].inna_dana_liczbowa<Dane[2].inna_dana_liczbowa)
wydaje mi się, że bezsensownie porównuje wskaźniki a chcę wartości, jednak jak dam * na początku to kompilator mi wypluwa, że "invalid type argument of 'unary *'"
Polecam K&R i odpowiedni paragraf o wskaźnikach do struktur. Jeżeli Dane jest tablicą wskaźników do struktur (u Ciebie w obu funkcjach jest wskaźnikiem do struktury) to do poszczególnych pól struktury odwołujemy się korzystając z operatora -> w tym przypadku Dane[1]->inna_dana_liczbowa (to to samo co (*Dane[1]).inna_dana_liczbowa - nawiasy są bardzo istotne, bez nich *Dane[1].inna_dana_liczbowa oznaczałoby, że pole struktury inna_dana_liczbowa jest zmienną wskaźnikową (silniej wiąże operator "."), stąd taka a nie inna treść komunikatu)
Jak już wyżej zostało wspomniane - jeśli nie chcesz zobaczyć nieprzyjemnych segfaultów to dla każdej struktury musisz zaalokować pamięć. Wtedy możesz operować zamianą adresów:
// zamień miejscami elementy i-ty i j-ty w tablicy Dane
void zamien (struct Struktura *Dane[], int i, int j)
{
    struct Struktura *temp = Dane[i];
    Dane[i] = Dane[j];
    Dane[j] = temp;
}

goscccccccccccc

  • Gość
wskazniki, takblice, struktury, przekazywanie do funkcji
« Odpowiedź #3 dnia: 2008-12-11, 23:32:03 »
Na początku przepraszam was za pomyłkę w ostatnich linijkach.
 
temp = Dane[0].inna_dana_liczbowa;
          Dane[1].inna_dana_liczbowa = Dane[3].inna_dana_liczbowa;
          Dane[3].inna_dana_liczbowa = temp;
Oczywiście bez sensu jest bawić się we wskaźniki dla pojedynczych zmiennych chodziło o zamianę całych struktur za pomocą wskaźników.
temp = &Dane[1]; //kompilator nic nie wypluwa na ta linię
&Dane[1] = &Dane[3]; // wciąż"invalid lvalue in assignment"
&Dane[3] = temp; // "invalid lvalue in assignment"
Przekazywanie parametru jako Dane[] wydaje mi się rzeczywiście słuszne, ale nadal mam problem z tymi funkcja pozamieniaj dane.

Ostatecznie utknąłem na czymś takim.
#include 


struct Struktura {
   char napis[20];
   float liczby[3];
   int inna_dana_liczbowa;
};

main(){
    int i;
struct Struktura *Dane[15];
struct Struktura tmp[15];
for(i = 0 ; i < 15 ; i++)
{
Dane[i] = &tmp[i];
}
    wczytaj_dane(Dane);
pozamieniaj_dane(Dane);
}
wczytaj_dane(struct Struktura *Dane[]) // z gwiazdka bo tu deklaruje czym operuję
{
    int i =0;
    int j= 1;
    FILE *fp;
    fp=fopen("plikk", "r");
    while(j != EOF) {

        j = fscanf(fp ,"%s %f %f %f", Dane[i]->napis, &Dane[i]->liczby[0], &Dane[i]->liczby[1], &Dane[i]->liczby[2]);
        printf("Twoj napis to: %s a liczby to %f %f %f\\n", Dane[i]->napis, Dane[i]->liczby[0], Dane[i]->liczby[1], Dane[i]->liczby[2]);
Dane[i]->inna_dana_liczbowa = Dane[i]->liczby[1] + Dane[i]->liczby[2];
        i++;
    }
    return 0;
}
pozamieniaj_dane(struct Struktura *Dane[])
{
    struct Struktura *temp[1];
struct Struktura wartosc_tempa[1];
temp[0] = &wartosc_tempa[0];
    if (Dane[1]->inna_dana_liczbowainna_dana_liczbowa) //wydaje mi się, że bezsensownie porównuje wskaźniki a chcę wartości, jednak jak dam * na początku to kompilator mi wypluwa, że "invalid type argument of 'unary *'"
     {
          // chce tutaj zamiany wskaźników w ramach optymalizacji, bo ta nieokrojona wersja programu jest trochę cięższa ;-)
          temp[0] = &Dane[1]; //assigment from incopatible pointer type
          &Dane[1] = &Dane[3]; // "invalid lvalue in assignment"
          &Dane[3] = temp[0]; // "invalid lvalue in assignment"
     }
}
Dzięki za wszelką pomoc.

chmooreck

  • Gość
wskazniki, takblice, struktury, przekazywanie do funkcji
« Odpowiedź #4 dnia: 2008-12-12, 10:50:28 »
Cytat: goscccccccccccc
pozamieniaj_dane(struct Struktura *Dane[])
{
    struct Struktura *temp[1];
struct Struktura wartosc_tempa[1];
temp[0] = &wartosc_tempa[0];
    if (Dane[1]->inna_dana_liczbowainna_dana_liczbowa) //wydaje mi się, że bezsensownie porównuje wskaźniki a chcę wartości, jednak jak dam * na początku to kompilator mi wypluwa, że "invalid type argument of 'unary *'"
     {
          // chce tutaj zamiany wskaźników w ramach optymalizacji, bo ta nieokrojona wersja programu jest trochę cięższa ;-)
          temp[0] = &Dane[1]; //assigment from incopatible pointer type
          &Dane[1] = &Dane[3]; // "invalid lvalue in assignment"
          &Dane[3] = temp[0]; // "invalid lvalue in assignment"
     }
}
Porównanie, które napisałeś jest odpowiednie. Dane zwraca ci wskaźnik do struktury, do pól której poprawnie odwołujesz się przez ->. Jakbyś na siłę chciał tam wrzucić '*', to musiałoby to wyglądać tak (zresztą pisał już o tym darkdancer):
(*Dane[1]).inna_dana_liczbowa
co jest zapisem zdecydowanie mniej czytelnym i nie polecam ;-)
Skoro już przekazujesz tablicę wskaźników, to wystarczy pozamieniać te wskaźniki... czyli wartość tymczasowa powinna być wskaźnikiem na strukturkę, zamiana dokładnie tak, jak napisał darkdancer.

P.S. K&R oznacza http://www.wnt.com.pl/product.php?action=0&prod_id=481&hot=1
Lektura obowiązkowa.

Edit:
Do iterowania lepiej używać sizeof(), wTwoim przypadku wyglądało by to tak:
    struct Struktura *Dane[15];
    struct Struktura tmp[sizeof(Dane)/sizeof(*Dane)];
    for(i = 0 ; i < sizeof(Dane)/sizeof(*Dane); i++)
{

goscccccccccccc

  • Gość
wskazniki, takblice, struktury, przekazywanie do funkcji
« Odpowiedź #5 dnia: 2008-12-12, 21:36:06 »
oki, to mam teraz już program, który mi się kompiluje i działa. Dowiedziałem się też, że czytałem i mam w domu dość sławną książkę i że ma ona kryptonim K&R ;-) Dzięki wszystkim za pomoc.
Kaka' mi też trochę pomógł. Mam jednak wątpliwości co do tych linijek programu w funkcji pozamieniaj_dane
temp[0] = Dane[1];
Dane[1] = Dane[3];
Dane[3] = temp[0];
Czy ja przypadkiem nie przypisuję/kopiuję danych zamiast wskaźników? Książki książkami mogę się pochwalić posiadaniem i czytaniem K&R oraz Programowaniem Schildta, które tez bym polecił, ale jak by mi ktoś rozjaśnił tak jakoś nie książkowo ;-), to byłoby super.

Na koniec wrzucam cały program dla jasności.
#include 


struct Struktura {
   char napis[20];
   float liczby[3];
   int inna_dana_liczbowa;
};

main(){
    int i;
struct Struktura *Dane[15];
struct Struktura tmp[15];
for(i = 0 ; i < 15 ; i++)
{
Dane[i] = &tmp[i];
}
    wczytaj_dane(Dane);
pozamieniaj_dane(Dane);
}
wczytaj_dane(struct Struktura *Dane[])
{
    int i =0;
    int j= 1;
    FILE *fp;
    fp=fopen("plikk", "r");
    while(j != EOF) {

        j = fscanf(fp ,"%s %f %f %f", Dane[i]->napis, &Dane[i]->liczby[0], &Dane[i]->liczby[1], &Dane[i]->liczby[2]);
        printf("Twoj napis to: %s a liczby to %f %f %f\\n", Dane[i]->napis, Dane[i]->liczby[0], Dane[i]->liczby[1], Dane[i]->liczby[2]);
Dane[i]->inna_dana_liczbowa = Dane[i]->liczby[1] + Dane[i]->liczby[2];
        i++;
    }
    return 0;
}
pozamieniaj_dane(struct Struktura *Dane[])
{
    struct Struktura *temp[1];
struct Struktura wartosc_tempa[1];
temp[0] = &wartosc_tempa[0];
    if (Dane[1]->inna_dana_liczbowainna_dana_liczbowa)
     {
          // chce tutaj zamiany wskaźników w ramach optymalizacji, bo ta nieokrojona wersja programu jest trochę cięższa ;-)
          temp[0] = Dane[1];
          Dane[1] = Dane[3];
          Dane[3] = temp[0];
     }
}

goscccccccccccc

  • Gość
wskazniki, takblice, struktury, przekazywanie do funkcji
« Odpowiedź #6 dnia: 2008-12-12, 22:54:01 »
Dobra, już dostałem informację, że zamieniam tylko wskaźniki. Dzięki wszystkim.