carrayssortingstructbsearch

Finding an element in an array of structs using bsearch


So I have an array of structures called conj_gms and what I want to find a specific jogo, given its nome.

Structure:

typedef struct jogo
{
    int id;
    char equipas[2][1024];
    int pont[2];
    char nome[MAX_CHARS];
} jogo;

For example i have jogo with

nome: ucl ,
equipas[0]: fcb,
equipas[1]: bvb,
pont[0]: 2,
pont[1]

at the index 1 of conj_jogs, if i search for the string UCL i want the id of the jogo with that name, after using bsearch, which is 1.

So to this i made a function that creates a jogo and atributted them to position in conj_jgs.

The problem is that when i use bsearch i get a segmentation faul

Program:

#include<stdlib.h> 
#include<stdio.h>
#include <string.h>
#define MAX_CHARS 1024

static int id = 0;

typedef struct jogo
{
    int id;
    char equipas[2][1024];
    int pont[2];
    char nome[MAX_CHARS];
} jogo;

jogo make_game(char nome_jg[],char team1[],char team2[],int score1,int score2)
{
    jogo novo_jogo = {0};
    novo_jogo.id = id;
    strcpy(novo_jogo.equipas[0],team1);
    strcpy(novo_jogo.equipas[1],team2);
    strcpy(novo_jogo.nome,nome_jg);
    novo_jogo.pont[0] = score1;
    novo_jogo.pont[1] = score2;
    return novo_jogo;
}

int compare(const void *s, const void *d) {
    return strncmp(s, ((const jogo *)d)->nome, sizeof(((jogo *)0)->nome));
}

int main()
{
    int i; jogo* result;
    jogo conj_gms[MAX_CHARS];
    conj_gms[0] = make_game("DK","fcb","bvb",2,1);
    id++;
    conj_gms[1] = make_game("Elc","barca","rma",1,2);
    id++;
    conj_gms[2] = make_game("Class","fcp","slb",1,3);
    id++;
    conj_gms[3] = make_game("derby","slb","scp",4,1);
    id++;
    result = bsearch("Elc",conj_gms, 4, sizeof(jogo),compare);
    printf("found at index: %d",result->id);
}

Solution

  • For starters the array of structures shall be sorted by the value of the data member nome. Your array of structures is not sorted. Otherwise you have to use a linear search.

    And secondly you have to check the returned pointer of the call of bsearch

    result = bsearch( "Elc", conj_gms, 4, sizeof(jogo),compare);
    if ( result ) printf("found at index: %d",result->id);
    

    As the array is not sorted by the data member nome then the returned pointer is equal to NULL.

    Within the comparison function it is enough to use the function strcmp instead of the function strncmp

    return strcmp(s, ((const jogo *)d)->nome );
    

    If to sort the array

    #include<stdlib.h> 
    #include<stdio.h>
    #include <string.h>
    #define MAX_CHARS 1024
    
    static int id = 0;
    
    typedef struct jogo
    {
        int id;
        char equipas[2][1024];
        int pont[2];
        char nome[MAX_CHARS];
    } jogo;
    
    jogo make_game(char nome_jg[],char team1[],char team2[],int score1,int score2)
    {
        jogo novo_jogo = {0};
        novo_jogo.id = id;
        strcpy(novo_jogo.equipas[0],team1);
        strcpy(novo_jogo.equipas[1],team2);
        strcpy(novo_jogo.nome,nome_jg);
        novo_jogo.pont[0] = score1;
        novo_jogo.pont[1] = score2;
        return novo_jogo;
    }
    
    int cmp(const void *s, const void *d) {
        return strcmp( ((const jogo *)s)->nome, ((const jogo *)d)->nome );
    }
    
    int compare(const void *s, const void *d) {
        return strcmp(s, ((const jogo *)d)->nome );
    }
    
    int main()
    {
        jogo* result;
        jogo conj_gms[MAX_CHARS];
        conj_gms[0] = make_game("DK","fcb","bvb",2,1);
        id++;
        conj_gms[1] = make_game("Elc","barca","rma",1,2);
        id++;
        conj_gms[2] = make_game("Class","fcp","slb",1,3);
        id++;
        conj_gms[3] = make_game("derby","slb","scp",4,1);
        id++;
    
        qsort( conj_gms, 4, sizeof( jogo ), cmp );
        result = bsearch( "Elc", conj_gms, 4, sizeof(jogo),compare);
        if ( result ) printf("found at index: %d",result->id);
    } 
    

    then you will get the expected result

    found at index: 1
    

    If you want to find an element of the array by some prefix then the comparison function can look like

    int compare(const void *s, const void *d) {
        return strncmp(s, ((const jogo *)d)->nome, strlen( s ) );
    }