Использование функции поиска для массивов различных типов структур в C - PullRequest
0 голосов
/ 28 мая 2020

Я сейчас работаю над своим проектом курса программирования для начинающих, и в нем мне нужно выполнить несколько поисков в массивах структур, например, у меня есть эти две разные структуры:

typedef struct{
  char name[SIZE];
  int number, year, isbn;
}magazine;

typedef struct{
  char title[SIZE];
  char author[SIZE];
  int isbn, year;
}book;

Как видите , как книга, так и журнал имеют isbn как общий элемент, и запросы, сделанные с помощью isbn, могут выполняться для обеих структур данных, мой вопрос в том, как я могу сделать (или использовать glib c) функцию общего назначения, без необходимо сделать это:

book *search_book(book *array, int key){
   //We search a book by its isbn and return the pointer.
}

magazine *search_mag(magazine *array, int key){
  //We search a magazine by its isbn and return the pointer
}

И вместо этого иметь возможность выполнять поиск обеих структур данных в одной функции?

Ответы [ 3 ]

1 голос
/ 28 мая 2020

Другие ответы прекрасны, но только потому, что ваш код находится в C, это не значит, что он не может быть на C ++!

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

#define SIZE 256

struct Base {
    int isbn;
    char name[SIZE];
    int year;
};

struct Book {
    struct Base base; // Inheritance, C style
    int number;
};

struct Magazine {
    struct Base base;  // Inheritance, C style
    char author[SIZE];
};

/* 
You're going to need to cast the arguments and return value.
Also provide the size of the element.
However: the code is generic, casting always works (if `Base` is the first element) , and there is no need for IF or SWITCH statements.
*/
struct Base* search(struct Base* array,int length,size_t size,int key){
    for (int i=0;i<length;++i){
        if (array->isbn == key){
            return array;
        }
        // array[i] won't work, because the size of Base is not the size we need to jump in.
        array = (struct Base*)((uint8_t*)array + size);
    }
    return NULL;
}

int main(int argc,char** argv){

    // Initialize some data
    struct Book books[] = {
        { {123,"Moby Dick",1851},1 },
        { {124,"Oliver Twist",1837},2 }
    };
    struct Magazine magazines[] = {
        {{ 125,"Wired",2020 }, "Some author"},
        {{ 126,"Byte",1990 }, "Some author"}
    };

    // Search for a book and a magazine
    struct Book* book = (struct Book*)search((struct Base*)books,2,sizeof(struct Book),124);
    struct Magazine* magazine = (struct Magazine*)search((struct Base*)magazines,2,sizeof(struct Magazine),126);

    if (book){
        printf("Found book %s, number: %d\n",book->base.name,book->number);
    }
    if (magazine){
        printf("Found magazine %s, author: %s\n",magazine->base.name,magazine->author);
    }
}
0 голосов
/ 28 мая 2020

Вот здесь отлично подходят шаблоны C ++. Однако в чистом C это ад: сначала вам понадобится общий тип для ваших массивов, который, вероятно, будет void*, но это также удалит любую информацию о типе.
Из-за этого ваша функция поиска затем также необходимо знать размер одного элемента и смещение внутри одного элемента в члене isbn.

Здесь в игру вступает арифметика указателя c, и, конечно же, новичок ничего не хочет делать. Если вы хотите использовать go таким образом, взгляните на sizeof и, возможно, на макрос offsetof, который обычно используется в коде C, но я действительно думаю, что это довольно продвинуто.

0 голосов
/ 28 мая 2020

Вы можете подумать об использовании такой структуры и написании функции для проверки типа, а затем либо вызвать одну из специализированных функций, которые знают, как искать книги и журналы.

typedef enum { INVALID, BOOK, MAGAZINE } itemType;

typedef struct {
  union {
  book b;
  magazine m;
  } u;

  itemType type;
} Item;

Вы можете инициализируйте свой массив своими элементами, также задав тип для каждого из них. Последним элементом может быть элемент с типом INVALID для обозначения конца массива, или вы можете передать размер вашей функции поиска.

Функция может выглядеть примерно так:

Item *search(Item *array, int key){
    Item * result = NULL;
    ...
    switch (array[i].type)
    {
       case BOOK: < do book search here using array[i].u.b >
                  if (found) result = array[i];
       break;
       case MAGAZINE: < do magazine search here using array[i].u.m>
                  if (found) result = array[i];
       break;
       default: // handle invalid case here
       break;
    }
    ...
    return result;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...