Sortowanie danych z pliku .dat

0

Mam do napisania, jako część większego prgramu, funkcję sortującą rekordy w pliku .dat. Mój program (który po części był pisany na zajęciach) nie wyrzuca w obecnym stanie błędów, ale też nic nie sortuje. Trzeba go jednak też przeobić, żeby sortował względem dowolnej wartości (imię, nazwisko, wiek, zarobki), która ma być wybrana w menu programu. Próbowałem wpisywać dane do tablicy, ale nic z tego nie wychodziło. Będę wdzięczny za każdą pomoc!

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

struct osoba {
    char imie[15];
    char nazwisko[25];
    int wiek;
    int zarobki;
};

int compar(const void *p1, const void *p2)
{
    struct osoba *os1 = (struct osoba *)p1;
    struct osoba *os2 = (struct osoba *)p2;
    int n = strcmp(os1->nazwisko, os2->imie);
    if(n) return n;
    else return strcmp(os1->imie, os2->nazwisko);
}

void sortuj(void *base, size_t n, size_t size, 
           int (*compar)(const void *, const void *))
{
    int i, j;
    for(i=n-1; i>0; i--)
        for(j=0; j<i; j++)
            if(compar(base + j*size, base + (j+1)*size)>0)
            {
                char temp[size];
                memcpy(temp, base + j*size, size);
                memcpy(base + j*size, base + (j+1)*size, size);
                memcpy(base + (j+1)*size, temp, size);
            }
    return;
}

int main()
{
    struct osoba os[100];

    FILE *fin = fopen("osoby.dat","r+");
    if(!fin)
    {
        printf("Blad otwarcia pliku!");
        exit(-1);
    }
    int n=0;
    while(fscanf(fin,"%s %s %d %d",os[n].imie, os[n].nazwisko, &os[n].wiek, &os[n].zarobki) == 4) n++;
    
    sortuj(os, n, sizeof(char), compar);
    
    int i;
    for(i=0; i<n; i++)
        printf("%s %s %d %d\n",os[i].nazwisko, os[i].imie, os[i].wiek, os[i].zarobki);
    
    fclose(fin);
    return 0;
} 

Wyciąłem tą część do osobnego pliku, bo łatwiej testować tylko to co mnie interesuje.

1
sortuj(os, n, sizeof(char), compar); 

chyba gwałci sposób jaki sobie założyłeś (typowy dla biliotek C). drugi size_t to rozmiar pojedynczej struktury.

Przesuwanie całymi blokami w sortuj prawdodobnie jest maksymalnie wydajne, ale mi nie chce się tej arytmetyki sprawdzać.

I nie zgłaszaj problemów "ale nic z tego nie wychodziło" bo to nic nie znaczy

0

@AnyKtokolwiek: Zmieniłem sizeof(char) na sizeof(os) w wywołaniu, co nagrodziło mnie wypluciem segmentation fault. Czy to znaczy że muszę zaalokować pamięć dla tych danych? Jeśli tak to w jaki sposób?

0
cr00w_ napisał(a):
                memcpy(temp, base + j*size, size);
                memcpy(base + j*size, base + (j+1)*size, size);
                memcpy(base + (j+1)*size, temp, size);

base jest typu void*

Faktycznie błędów nie wyrzuca, ale ostrzeżenia już tak:

test.c:22:18: warning: declaration of 'compar' shadows a global declaration [-Wshadow]
   22 |            int (*compar)(const void *, const void *))
      |            ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.c:12:5: note: shadowed declaration is here
   12 | int compar(const void *p1, const void *p2)
      |     ^~~~~~
test.c:27:31: warning: conversion to 'size_t' {aka 'long long unsigned int'} from 'int' may change the sign of the result [-Wsign-conversion]
   27 |             if(compar(base + j*size, base + (j+1)*size)>0)
      |                               ^
test.c:27:28: warning: pointer of type 'void *' used in arithmetic [-Wpointer-arith]
   27 |             if(compar(base + j*size, base + (j+1)*size)>0)
      |                            ^
test.c:27:50: warning: conversion to 'size_t' {aka 'long long unsigned int'} from 'int' may change the sign of the result [-Wsign-conversion]
   27 |             if(compar(base + j*size, base + (j+1)*size)>0)
      |                                                  ^
test.c:27:43: warning: pointer of type 'void *' used in arithmetic [-Wpointer-arith]
   27 |             if(compar(base + j*size, base + (j+1)*size)>0)
      |                                           ^
test.c:30:38: warning: conversion to 'size_t' {aka 'long long unsigned int'} from 'int' may change the sign of the result [-Wsign-conversion]
   30 |                 memcpy(temp, base + j*size, size);
      |                                      ^
test.c:30:35: warning: pointer of type 'void *' used in arithmetic [-Wpointer-arith]
   30 |                 memcpy(temp, base + j*size, size);
      |                                   ^
test.c:31:32: warning: conversion to 'size_t' {aka 'long long unsigned int'} from 'int' may change the sign of the result [-Wsign-conversion]
   31 |                 memcpy(base + j*size, base + (j+1)*size, size);
      |                                ^
test.c:31:29: warning: pointer of type 'void *' used in arithmetic [-Wpointer-arith]
   31 |                 memcpy(base + j*size, base + (j+1)*size, size);
      |                             ^
test.c:31:51: warning: conversion to 'size_t' {aka 'long long unsigned int'} from 'int' may change the sign of the result [-Wsign-conversion]
   31 |                 memcpy(base + j*size, base + (j+1)*size, size);
      |                                                   ^
test.c:31:44: warning: pointer of type 'void *' used in arithmetic [-Wpointer-arith]
   31 |                 memcpy(base + j*size, base + (j+1)*size, size);
      |                                            ^
test.c:32:36: warning: conversion to 'size_t' {aka 'long long unsigned int'} from 'int' may change the sign of the result [-Wsign-conversion]
   32 |                 memcpy(base + (j+1)*size, temp, size);
      |                                    ^
test.c:32:29: warning: pointer of type 'void *' used in arithmetic [-Wpointer-arith]
   32 |                 memcpy(base + (j+1)*size, temp, size);
      |                             ^
test.c: In function 'main':
test.c:50:16: warning: conversion to 'size_t' {aka 'long long unsigned int'} from 'int' may change the sign of the result [-Wsign-conversion]
   50 |     sortuj(os, n, sizeof(char), compar);
      |                ^
1
    int n = strcmp(os1->nazwisko, os2->imie);
    if(n) return n;
    else return strcmp(os1->imie, os2->nazwisko);

Co to ma być, nazwisko z imieniem porównujesz?

 int i, j;

Doprawdy? Od 21 lat można deklarować wprost w forze

for(j=0; j<i; j++)

Wyszukiwanie i zliczanie par takich samych liczb z tablicy

for(int i=n-1;i>0;--i)
{
        for(int j=0;j<i;++j)
        {
                char *a=((char*)base)+i*size,*b=a+size;
                if(compar(a,b)>0)
                {
                        char temp[size];
                        memcpy(temp,a,size);
                        memcpy(a,b,size);
                        memcpy(b,temp,size);
                }
        }
 }

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