Как создать экземпляр структуры на С++?

Проблема заключается в сообщении об ошибке "Ошибка записи о местоположении 0x00000000" сразу после инициализации переменной bk до NULL. Я предполагаю, что я должен заранее зарезервировать пространство памяти, чтобы назначить NULL (что-то вроде Book bk = new Book();), но до сих пор мне не удалось выяснить, как это сделать на С++.

Book.h

#ifndef Book_H
#define Book_H

struct _book;
typedef _book* Book;

Book CreateBook(unsigned int pageNum);

Book.cpp

#include "Book.h"
#include <iostream>

#ifndef Book_CPP
#define Book_CPP

using namespace std;

struct _book
{
    int pageNum;
};

Book CreateBook( unsigned int pageNum){

    Book bk = NULL; 

    bk->pageNum = pageNum;

    return bk;
};

Ответы

Ответ 1

Вы назначаете bk в NULL, а затем пытаетесь получить доступ к его члену. То же, что и нулевой указатель в Java, и то, что вы делаете, обычно вызывает исключение NullPointerException (спасибо из комментариев). Если вы хотите создать указатель на свою структуру, вам нужно использовать оператор new:

bk = new _book;
// ...
return bk;

а затем убедитесь, что вы вызываете delete по указателю, когда закончите с ним.

Я бы посоветовал не использовать указатели здесь. В отличие от других языков, С++ позволяет создавать объекты по значению. Он также позволяет использовать ссылки и указатели, но только использовать указатели, когда вы абсолютно должны. Если вы просто хотите создать объект книги с заданным pageNum, вы должны создать конструктор, пока вы на нем:

struct _book {
    int pageNum;
    _book(int n) : pageNum(n) // Create an object of type _book.
    {
    }
};

а затем вы можете вызвать его как

_book myBook(5); // myBook.pageNum == 5

Если вы новичок в С++, пожалуйста, возьмите себе хорошую книгу. Это не только язык низкого уровня, но и не только язык ООП. Это многопартийный швейцарский армейский ножевой язык.

Ответ 2

Это то, что вам нужно:

Book CreateBook( unsigned int pageNum){

    Book bk = new _book();

    bk->pageNum = pageNum;

    return bk;
}

ваш bk был null, и вы не можете получить доступ к pageNum, когда указатель имеет значение null.

И не забудьте вызвать delete на bk, когда вы закончите использовать его.

Ответ 3

Book.h

#ifndef Book_H
#define Book_H

// why not put the layout here?    
struct Book
{
    int pageNum;
};
Book CreateBook(unsigned int pageNum);

#endif

Book.cpp

#include "Book.h"

// no #define guards
// do not using namespace std;, it is a bad habit

Book CreateBook( unsigned int pageNum){
  Book bk;
  bk.pageNum = pageNum;
  return bk;
};

Это простейшее решение. Книги являются фактическими значениями и могут быть скопированы и перемещены и т.д.

Если вам нужна непрозрачность абстрактного типа, только тогда вы должны иметь дело с указателями. Когда вы имеете дело с указателями, прятать их за typedef - это плохая идея: указатели означают управление ресурсами, поэтому должно быть очевидно, что вы их используете.

Версия на основе указателя:

#ifndef Book_H
#define Book_H

// why not put the layout here?    
struct Book;
Book* CreateBook(unsigned int pageNum);

#endif

* Book.cpp *

#include "Book.h"

// no #define guards
// do not using namespace std;, it is a bad habit

Book* CreateBook( unsigned int pageNum){
  Book* bk = new Book;
  bk->pageNum = pageNum;
  return bk;
};

но если вы создаете материал, вы, вероятно, должны создавать интеллектуальные указатели:

#include <memory>
std::shared_ptr<Book> CreateBook( unsigned int pageNum){
  std::shared_ptr<Book> bk( new Book );
  bk->pageNum = pageNum;
  return bk;
};

Ответ 4

В

Book bk;

bk является указателем

Сначала выделите память для него

Book bk* = new _book();

И затем сделайте

bk->pageNum = pageNum;

Также не забудьте освободить память, используя

delete bk;

Ответ 5

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

Если вы не знали, вы также можете написать:

_book book;

Теперь книга распределяется статически в стеке вместо динамически в куче. Он автоматически уничтожается, когда переменная выходит за пределы области видимости, как int или double, и т.д.

Это полезно иногда, если вы хотите избежать накладных расходов или работы по распределению памяти для чего-то очень простого. Было странно, что я пошел на Java и должен сказать:

vec3 position = new Vec3 (0.0, 1.0, 5.0);

вместо того, чтобы просто сказать

позиция vec3 (0.0, 1.0, 5.0);

как в С++.

Ответ 6

struct Book{
    int pageNum;    
};

Book* createBook(int pageNum){
    Book *result = new Book;
    result->pageNum = pageNum;
    return result;
}

int main(int argc, char** argv){
    Book book;
    book.pageNum = 0;
    return 0;
}

или

struct Book{
    int pageNum;    
    Book(int pageNum_ = 0)
    :pageNum(pageNum_){
    }
};

Book* createBook(int pageNum){
    return new Book(pageNum);
}

int main(int argc, char** argv){
    Book book(0);
    return 0;
}

Ответ 7

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

bk = _book{any_data_that_you_want_to_insert};
// ...
return bk;

Ответ 8

В вашем коде есть несколько ошибок.

  • Вам нужно положить #endif в конец вашего файла заголовка.
  • Вам нужно поместить точку с запятой в конце определений struct, class и union (после закрывающей скобки).
  • Вы не должны использовать указатели вообще в таком простом случае.

Пример:

Book.h

#ifndef BOOK_H
#define BOOK_H

struct Book
{
    int pageNum;
};

Book CreateBook(int pageNum);

#endif

Book.cpp

#include "Book.h"

Book CreateBook(int pageNum)
{
    Book bk;

    bk.pageNum = pageNum;

    return bk;
}

В любом случае вам не нужна функция CreateBook, но я все равно оставил ее.