简体   繁体   English

如何使用结构在 C 中建模图书库系统?

[英]How to model a book-library system in C using structs?

I am trying to learn C and C++ and I am struggling a bit with pointers.我正在尝试学习 C 和 C++,但我在指针方面有点挣扎。 Concretely, I want to model a book-library system using some structs.具体来说,我想使用一些结构来建模一个图书库系统。 A library could have more or less books, but we do not exactly the number.图书馆可以有更多或更少的书籍,但我们不知道确切的数量。 Below, I will post some snippet code:下面,我将发布一些片段代码:

This works but the number of books is known, not desired.这可行,但书籍的数量是已知的,而不是理想的。

// library.h
#ifndef _LIBRARY_
#define _LIBRARY_

#include "book.h"

typedef struct {
    int noBooks;
    book books[10];
}library;

void addBook(book*, library*);

#endif 

// library.c
#include "library.h"

void addBook(book* b, library* l) {
    l->books[l->noBooks] = *b;
    l->noBooks++;
}

// book.h
#ifndef _BOOK_
#define _BOOK_

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

    typedef struct book_ {
        int id;
        char author[15];
        char title[15];
    }book;
    
    void displayInfo(const book*);
    
    #endif

//book.c
#include "book.h"

void displayInfo(const book* b) {
    printf("Id: %d \n Author: %s \n Title: %s\n", b->id, b->author, b->title);
}

//main.cpp
#include<iostream>

extern "C" {
    #include "book.h"
    #include "library.h"
}

int main() {
    std::cout << "Start" << std::endl;

    book b1;
    strcpy_s(b1.author, "Ab");
    b1.id = 1;
    strcpy_s(b1.title, "Ab");

    book b2;
    strcpy_s(b2.author, "Df");
    b1.id = 2;
    strcpy_s(b2.title, "Df");

    library l1;
    l1.noBooks = 0;
    addBook(&b1, &l1);
    addBook(&b2, &l1);

    std::cout << l1.books[0].author << "\n";
    std::cout << l1.books[1].author;
}

How should I modify it in order to add books without to know exactly the number (10 in this case)?我应该如何修改它以添加书籍而不知道确切的数字(在这种情况下为 10)? I tried more cases, for example:我尝试了更多案例,例如:

// library.h
#ifndef _LIBRARY_
#define _LIBRARY_

#include "book.h"

typedef struct {
    int noBooks;
    book* books;
}library;

void addBook(book*, library*);

#endif 

// library.c
#include "library.h"

void addBook(book* b, library* l) {
    l->books[l->noBooks] = *b;
    l->noBooks++;
}

Still, it does not work.尽管如此,它还是行不通。 Could you give me guidance/advice?你能给我指导/建议吗? Thank you for your time!感谢您的时间!

To directly address the concern mentioned in your question, pointers aren't necessary for this program at all.为了直接解决您的问题中提到的问题,该程序根本不需要指针。 At least not pointers that you need to write.至少不是您需要编写的指针。

Given the discussion in the comments about what your code is, I'll chip in an answer that leans more into C++.鉴于评论中关于您的代码是什么的讨论,我将提供一个更倾向于 C++ 的答案。

#include <iostream>
#include <string>
#include <vector>

class Book {
 public:
  Book() = default;
  Book(int id, std::string auth, std::string title)
      : m_id(id), m_author(auth), m_title(title) {}

  friend std::ostream& operator<<(std::ostream& sout, const Book& book) {
    return sout << "ID: " << book.m_id << "\nAuthor: " << book.m_author
                << "\nTitle: " << book.m_title << '\n';
  }

 private:
  int m_id = 0;
  std::string m_author;
  std::string m_title;
};

class Library {
 public:
  void add_book(Book book) { m_books.push_back(book); }
  std::size_t size() const { return m_books.size(); }

  // The better approach would be to provide iterators so that you can access
  // individial books from the library, much like you can with the vector,
  // but that's a whole other level of work.
  void print() const {
    for (auto book : m_books) {
      std::cout << book << '\n';
    }
  }

 private:
  std::vector<Book> m_books;
};

int main() {
  Book b1(1, "Frank Herbert", "Dune");
  Book b2(2, "Frank Herbert", "Dune Messiah");

  Library l1;
  l1.add_book(b1);
  l1.add_book(b2);

  l1.print();
  std::cout << "Number of books in library: " << l1.size() << '\n';
}

Output:输出:

ID: 1
Author: Frank Herbert
Title: Dune

ID: 2
Author: Frank Herbert
Title: Dune Messiah

Number of books in library: 2

As you can see, even a basic C++ (not C with std::cout , but idiomatic C++) implementation requires essentially a full re-write.如您所见,即使是基本的 C++(不是带有std::cout的 C,而是惯用的 C++)实现也需要完全重写。 And I noted one area where I really skimped.我注意到一个我真的很吝啬的地方。 Your Library is just wrapping a container, and containers are typically built to be iterated through.您的Library只是包装一个容器,而容器通常是为迭代而构建的。 But the effort of writing an iterator (it would just be wrapping the vector iterator) just didn't make sense for this answer.但是编写迭代器(它只是包装向量迭代器)的努力对于这个答案没有意义。

For a toy program like this, you might be better off skipping the Library class completely and just declaring something like std::vector<Book> library;对于像这样的玩具程序,最好完全跳过Library类,只声明std::vector<Book> library;之类的东西。 in your main() function and taking direct advantage of all the capabilities that std::vector provides.在您的main()函数中,并直接利用std::vector提供的所有功能。

The big takeaways in this snippet that will make the code easier to manage are:此代码段中将使代码更易于管理的重要内容是:

  • Classes.上课。 Bundles your relevant data and functions together.将您的相关数据和功能捆绑在一起。
  • std::vector . std::vector A heap-allocated array that grows when needed and knows its own size.一个堆分配的数组,在需要时增长并且知道自己的大小。
  • std::string . std::string Handles all the messy parts and far less error-prone.处理所有杂乱的部分,并且不易出错。

Also on display is operator overloading .还展示了操作员重载 This allows you use your custom types as if they were native types.这使您可以像使用本机类型一样使用自定义类型。 Much nicer than something like a display() function.display()函数好得多。

While all that C syntax is technically valid C++, philosophically it's completely wrong.虽然所有 C 语法在技术上都是有效的 C++,但从哲学上讲它是完全错误的。 You either want to learn C, or you want to learn C++.您要么想学习 C,要么想学习 C++。 Choose one and stick with it.选择一个并坚持下去。 Blending the two the way you did will just lead to a bad time.以你的方式混合这两者只会导致糟糕的时刻。

If you want to do this in C:如果您想在 C 中执行此操作:

You can try to implement your own resizable library.您可以尝试实现自己的可调整大小的库。

Something like this :像这样的东西:

typedef struct {
    int length;
    int capacity;
    book *books;
} library;

int add_book(library *lib, book *b) {
    // Add a book to the library
    assert(lib != NULL); // Check if library is valid
    assert(b != NULL); // Check if book is valid

    if(lib->length + 1 > lib->capacity) { // We run out of space for new books
        lib->capacity *= 2;
        lib->books = realloc(lib->books, lib->capacity * sizeof(book)); // Check for errors
        lib->books[lib->length] = *b;
        lib->length++;
        printf("Increased library capacity and added book to library\n");
        return 0;
    }
    else {
        lib->books[lib->length] = *b;
        lib->length++;
        printf("Book added to library\n");
        return 0;
    }
}

If you want to do this in C++ (much easier): You can use vector and just append values.如果您想在 C++ 中执行此操作(容易得多):您可以使用向量并仅附加值。

Here is a minimal implementation demonstrating how to dynamically add a book to your library and clean up the resources allocated:这是一个最小的实现,演示了如何动态地将一本书添加到您的图书馆并清理分配的资源:

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

struct book {
    int id;
    char author[15];
    char title[15];
};

struct library {
    unsigned noBooks;
    struct book *books;
};

// check for duplicate id?
struct library *library_add(struct library *l, struct book *b) {
    if(!l) return NULL;
    struct book *books = realloc(l->books, sizeof(struct book) * (l->noBooks + 1));
    if(!books) {
        printf("realloc failed\n");
        return NULL;
    }
    l->books = books;
    l->books[l->noBooks].id = b->id;
    strcpy(l->books[l->noBooks].author, b->author);
    strcpy(l->books[l->noBooks].title, b->title);
    l->noBooks++;
    return l;
}

void library_print(struct library *l) {
    if(!l) return;
    for(unsigned i = 0; i < l->noBooks; i++) {
        printf("id = %d, author = %s, title = %s\n",
            l->books[i].id,
            l->books[i].author,
            l->books[i].title
        );
    }
}

void library_destroy(struct library *l) {
    if(!l) return;
    free(l->books);
}

int main() {
    struct library l = { 0, NULL };
    library_add(&l, &(struct book) { 1, "Ab", "Ab"});
    library_add(&l, &(struct book) { 2, "Df", "Df"});
    library_print(&l);
    library_destroy(&l);
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM