Komparator do porównania struktur.

0

Witam, chce sobei posortować tablice struktur po rożnych polach, na początek po polu nazwa, które jest tablicą charów. Toteż uznałem, że najłatwiej będzie użyć qsort'a i napisać komparatory do różnych pól co też uczyniłem.

int nazwa_compare (struct produkty *a, struct produkty *b)
{
    if(strcmp(*a.nazwa, *b.nazwa)<0) return -1;
    if(strcmp(*a.nazwa, *b.nazwa)<0) return 1;
    return 0
} 

a nstępnie szczęsliwy wklepałem:
qsort(tab, N, sizeof(struct produkty), nazwa_compare);
ale kompilatorowi się to bardzo nie spodobało gdyż raczy mnie błędami:
/usr/lib/gcc/x86_64-linux-gnu/4.9/include/stddef.h|212|error: storage class specified for parameter ‘size_t’|
/usr/lib/gcc/x86_64-linux-gnu/4.9/include/stddef.h|212|error: storage class specified for parameter ‘u_char'|
i tak dalej lecąc po typach.
Moje rozwiązanie musi być w jak najczystszym C, tj. bez bool'i i innych burżuazyjnych wymysłów, z góry dzięki za podpowiedzi :)

0

Ale C ma boole od 17 lat. Co w tym złego?

*a.nazwa ma inne priorytety niż myślisz. to jest równoznaczne *(a.nazwa), chciałeś napisać (*a).nazwa lub a->nazwa

1

Zamiast pisać takie elaboraty napisz sobie tak:

int nazwa_compare (struct produkty *a, struct produkty *b)
{
	return (strcmp(a->nazwa, b->nazwa));
} 

Zdaje się, że strcmp było tak projektowane, żeby dało się je użyć bezpośrednio w takiej sytuacji.

0

Poprawiłem komparator na

 return (strcmp(a->nazwa, b->nazwa)); 

ale nadal sypie takimi samymi błędami przy kompilacji. A co do bool'i, to wydaje mi się, że u mnie w pracowni jest ustawiony standard przed C99.

0

Może błąd jest gdzieś indziej - pokaż resztę kodu.

0

No dobra, to podczas kodowania pamiętaj aby się zabezpieczać przed Y2K.

Pokaż kod i błędy, najważniejszy zawsze jest pierwszy, a nie jakieś ze środka.

0

pierwszy błąd

/usr/lib/gcc/x86_64-linux-gnu/4.9/include/stddef.h: In function ‘nazwa_compare’:
/usr/lib/gcc/x86_64-linux-gnu/4.9/include/stddef.h:212:23: error: storage class specified for parameter ‘size_t’
 typedef __SIZE_TYPE__ size_t; 

kod:

 
int list_sorted(struct produkty tab[N], char pole[99])
{
    puts(pole);
    int ost; /// int ost - zmienna przechowujaca liczbe zapisanych rekordow, zwracanych przez funkcje ostatni_rekord.
    struct produkty temp[N]; ///char temp [1000][99] - tymczasowa tablica struktur do posortowania i wypisania posortowanych wartosci.
    if (strcmp(pole, "nazwa\n")==0)
    {
        qsort(tab, N, sizeof(tab[1]), nazwa_compare);
        list(tab);
    }
}

gdzie list() wypisuje tablice i działa OK.
No i funkcja nazwa_compare()

 
int nazwa_compare (struct produkty *a, struct produkty *b)
{
     return (strcmp(a->nazwa, b->nazwa));
}
0

Jeszcze jedna uwaga - optymalniej jest sortować tablicę wskaźników niż całych struktur, bo to oszczędza dużo kopiowań pamięci - zwłaszcza jak masz strukturę o rozmiarze ochset bajtów, a pointer zajmuje np. 8 (albo 4).

0

plik core.c, wersja mocno robocza

#include "core.h"
#include <stdio.h>
int nazwa_compare (struct produkty *a, struct produkty *b)
{
    //if(strcmp(a->nazwa, b->nazwa)<0) return -1;
    //if(strcmp(a->nazwa, b->nazwa)>0) return 1;
    //return 0;
     return (strcmp(a->nazwa, b->nazwa));
}
/**
    * @brief funkcja wypisujaca rekordy posortowane po zadanym parametrze.
    *
    *
*/
int list_sorted(struct produkty tab[N], char pole[99])
{
    puts(pole);
    structure produkty *temp;
    int ost; /// int ost - zmienna przechowujaca liczbe zapisanych rekordow, zwracanych przez funkcje ostatni_rekord.
    struct produkty temp[N]; ///char temp [1000][99] - tymczasowa tablica struktur do posortowania i wypisania posortowanych wartosci.
    ost = ostatni_rekord(tab);
    printf("ostatni rekord %d \n", ost);
    int i, j;
    if (strcmp(args, "nazwa\n")==0)
    {
        qsort(tab, N, sizeof(tab[1]), nazwa_compare);
        list(tab);
    }
    for (i=0; i<ost; i++) printf("%d\n", klucze[i]);
    /*for (j=0; j<ost; j++)
    {
        int i = klucze[j];*/
         //printf("Nazwa: %s , opis %s, cena %f, lokalizacja %s \n", tab[i].nazwa, tab[i].opis, tab[i].cena, /*tab[i].stan,*/ tab[i].lokalizacja);
    //}

    return 0;

}
/**
    * @brief funkcja znajdujaca ostatni zapisany rekord.
    * @warning funkcja zwraca OSTATNI zapisany rekord tj. rekord ze znacznikiem #last
    * @param tab[N] przyjmuje adres gownej tablicy rekordow.
    * @return numer ostatniego rekordu zawierajacego dane.
*/
int ostatni_rekord( struct produkty tab[N])
{
    int i=0;
    for(i=0;i<N;i++)
    {
       if(strcmp(tab[i].nazwa, "#last")==0) return i;

    }
    return 0;
}
/**
    * @brief funkcja dodajaca okreslona przez uzytkownika ilosc rekordow.
    *
    * @note Podająć stan należy pamietać o tym, że podowany on jest jako liczba .
    * @param tab[N] przyjmuje adres glownej tablicy rekordow.
    * @return zwraca int o wartosci 0 lub kodu bledu.
    */
int add_row(struct produkty tab[N])
{
    /// opis zmiennych lokalnych
    int i; /// i - zmienna starująca pętlą for.
    int k;  /// k - zmianna prsechowujaca podana przez uzytkownika ilosc rekordow do dodania.
    int ost; /// ost - zmienna przechuwujaca ostatni rekord zwrocony przez funkcje ostatni_rekord.
    int t; ///t - tymczasowa zmienna wczytujaca wartośc stanu celem zapisania do ENUMA @sa stan_prod.
    printf("Ile produktow chcesz dodac?\n");
    scanf("%d", &k);
    getchar();
    ost = ostatni_rekord(tab);
    int j;
    for (i=ost; i<k; i++)
    {
        puts("wprowadzanie produktow\n");
        puts("podaj nazwe nowego produktu\n");
        fgets(tab[i].nazwa, 99, stdin);
        printf("podaj opis nowego produktu\n");
        fgets(tab[i].opis, 99, stdin);
        printf("podaj cene nowego produktu\n");
        scanf("%f", tab[i].cena);
        getchar();
        //printf("podaj stan nowego produktu (1 nowy, 2 uzywany) \n");
        //scanf("%d", &t);
        //getchar();
        printf("podaj lokalizacje nowego produktu\n");
        fgets(tab[i].lokalizacja, 99, stdin);
        j=i+1;
        tab[i].nazwa[strcspn(tab[i].nazwa, "\n")] = '\0';
        tab[i].opis[strcspn(tab[i].opis, "\n")] = '\0';
        tab[i].lokalizacja[strcspn(tab[i].lokalizacja, "\n")] = '\0';
        //if (t==1) tab[i].stan=NOWY;
        //if (t==2) tab[i].stan=UZYWANY;
    }
    strcpy(tab[j].nazwa, "#last");
    puts("zakonczono dodawanie produktow");
    return 0;
}
/**
* @brief funkcja listujaca produkty
* @param tab przyjmowany adres glownej tablicy rekordow.
* @return funkcja zwraca 0 lub kod błędu gdy takowy wsytapi.
*/

int list(struct produkty tab[N])
{

    int ost, i;

    ost=ostatni_rekord(tab);
    printf("ostatni rekord %d\n", ost);
    for (i=0; i<ost; i++)
    {
        printf("Nazwa: %s , opis %s, cena %f, lokalizacja %s \n", tab[i].nazwa, tab[i].opis, tab[i].cena, /*tab[i].stan,*/ tab[i].lokalizacja);
    }
    return 0;
}
/**
* @brief funkja do otworzenia bazy danych
* @param param - char z  dodatkwoymi opcjami moze byc pusty wtedy otwiera plik istniejacy lub t gdy tworzy nowy plik bazy.
* @return zwraca 0 lub kod błędu gdy takowy wystąpi.
*/
int otworz_baze(char param, char opcje[99])
{
    char *nazwa=opcje;
    printf("otwieram baze danych z argumentami %c i dodatkowymi opcjami %s\n", param, opcje);
    FILE *fp;
    if (strcmp(opcje, "")==0) {
        nazwa="baza.txt";
    }
    else {
        strcpy(nazwa, opcje);
    }
    if(param=='0' )
    {
        fp = fopen(nazwa, "r+");
        if (fp==NULL) {
            fprintf(stderr,"Blad otwarcia pliku\n");
            return -1;
        }
        else printf("otwarto baze %s\n", nazwa);
    }
    if(param=='t')
    {
     fp = fopen(nazwa, "w");
        if (fp==NULL) {
            fprintf(stderr,"Blad otwarcia pliku\n");
            return -2;
        }
        else printf("otwarto baze %s\n", nazwa);
    return 0;
    }
}

int pomoc()
{
    printf("oto pomoc\n");
    return 0;
}
int komendy(char func, char add, char argument[99],struct produkty tab[N])
{
     if (func=='o')
     {
        int i=otworz_baze(add, argument);
        if (i!=0) printf("blad otwierania bazy danych %d", &i);
     }
     if (func=='h') return pomoc();
     if (func=='a') return add_row(tab);
     if (func=='l' && add!='s') return list(tab);
     if (func=='l' && add=='s') return list_sorted(tab, argument);
    return 0;
}


 

plik core.h, rowniez wersja mocno robocza

#define NL 100
#define NTS 1000
#define N 1000
#ifndef CORE_H_INCLUDED
#define CORE_H_INCLUDED

enum stan_prod
{
    NOWY=1,
    UZYWANY=2,
    NIOKRESLONY=0
};
struct produkty
{
    char nazwa[99];
    char opis[99];
    float cena;
    //enum stan_prod stan;
    char lokalizacja[99];
};
int nazwa_compare (struct produkty *a, struct produkty *b)
int list_sorted(struct produkty * tab, char pole[99]);
int otworz_baze(char param, char opcje[99]);
int komendy(char func, char add, char argument[99], struct produkty tabela[N]);
int list(struct produkty tab[N]);
int ostatni_rekord(struct produkty tab[N]);
int add_row(struct produkty tabl[N]);
int pomoc();
#endif // CORE_H_INCLUDED


 

no i plik main.c również mocno roboczy

 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "core.h"

int main()
{
    struct produkty products[N];
    int err=0, kontrolka=69;
    printf("Witaj w elektronicznej ewidencji, wpisz -h aby wyswietlic pomoc\n");
    //add_rekord(products);
    for (;;)
    {
        kontrolka=69;
        char command2, tmp[99], command1, command[99];
        char * argument;
        fgets(tmp, 99, stdin);
        int i, k=0;
        for (i=0; i<strlen(tmp); i++) {
            if (tmp[i]!=' ')
            {
                command[k]=tmp[i];
                k++;
            }
        }
        char * polecenie = strstr(command, "-");
        if (polecenie != NULL)
        {
            command1=*(polecenie+1);
            //printf(" polecenie 1: %c\n", command1);
        }
        else
        {
            printf("nie rozponano polecenia\n");
            continue;
        }
        char * polecenie2 = strstr(polecenie+1, "-");
        if (polecenie2!=NULL)
        {
            command2=*(polecenie2+1);
            //printf("polecenie 2: %c\n", command2);
            argument = polecenie2+2;
        }
        else
        {
            command2='0';
            argument = polecenie+2;
        }
        //printf("argument: %s", argument);
        if (command1=='q') break;
        while (kontrolka!=0)
        {
            kontrolka = komendy(command1, command2, argument, products);
        }
    }
    return 0;
}

co do wskaźnikow to taki jest zamysł, ale ja wolę pisać kod "po kawałkach i chce najpierw nauczyć się sortować w tym języku jaskiniowców z ubiegłego milenium struktury.

1

Na szybko parę bugów.

  1. qsort przyjmuje funkcję compare w postaci int cmp(const void *, const void *). Trzeba zrobić rzutowanie w środku funkcji.
  2. funkcja otworz_baze potrafi skutecznie ominąć litanię ifów i dojść do swojego końca na którym nie ma return. UB.
  3. core.h: przy deklaracji nazwa_compare nie masz na końcu średnika. To pewnie tłumaczyłoby alergię kompilatora.
  4. core.h: #define wewnątrz #ifndef, nie na odwrót
  5. list_sorted ma jedną zmienną tak zadeklarowaną: structure produkty *temp (to i tak jest źle) a potem struct produkty temp[N]. Zdecyduj się na coś.
0
 
int nazwa_compare (const void *a, const void *b)
{
    a=(*produkty) a;
    b=(*produkty) b;
     return (strcmp(a->nazwa, b->nazwa));
}

czy rzutowanie jest ok?

0

Uff, Panie, jednak język dla dinozaurów jest ciut zbyt skomplikowany:

int nazwa_compare(const void *a, const void *b)
{
	return (strcmp(((struct produkty *)a)->nazwa, ((struct produkty *)b)->nazwa));
}
0

Niestety z C walczę dopiero tydzień, tak naprawdę. Trochę fajne, że mogę sam robić fiku miku z pamięcią ale na początek czuję się trochę zagubiony. W ramach dobrego serca prosiłbym jeszcze o wyjaśnienie dlaczego:

 
int nazwa_compare (const void *a, const void *b)
{
    a=(struct produkty*) a;
    b=(struct produkty*) b;
     return (strcmp(a->nazwa, b->nazwa));
}

To nie działa? Kompilator na mnie za to krzyczy w ten sposób:

 
||=== Build: Debug in projekt1 (compiler: GNU GCC Compiler) ===|
/home/wegrzycki/Dokumenty/prm/projekt1/core.c||In function ‘nazwa_compare’:|
/home/wegrzycki/Dokumenty/prm/projekt1/core.c|7|warning: implicit declaration of function ‘strcmp’ [-Wimplicit-function-declaration]|
/home/wegrzycki/Dokumenty/prm/projekt1/core.c|7|warning: dereferencing ‘void *’ pointer|
/home/wegrzycki/Dokumenty/prm/projekt1/core.c|7|error: request for member ‘nazwa’ in something not a structure or union|
/home/wegrzycki/Dokumenty/prm/projekt1/core.c|7|warning: dereferencing ‘void *’ pointer|
/home/wegrzycki/Dokumenty/prm/projekt1/core.c|7|error: request for member ‘nazwa’ in something not a structure or union|

0

Bo tak naprawdę nie robisz rzutowania.

A, no i dodaj sobie #include <string.h> dla świętego spokoju.

1 użytkowników online, w tym zalogowanych: 0, gości: 1