Le problème est un "Emplacement d'écriture de violation d'accès 0x00000000" message d'erreur juste après avoir initialisé la variable bk
en NULL
. Je suppose que je devrais réserver de l'espace mémoire à l'avance pour affecter NULL
(quelque chose comme Book bk = new Book();
) mais je n'ai pas été en mesure de comprendre comment le faire en C++ jusqu'à présent.
#ifndef Book_H
#define Book_H
struct _book;
typedef _book* Book;
Book CreateBook(unsigned int pageNum);
#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;
};
Vous affectez bk à NULL, puis essayez d'accéder à un membre de celui-ci. C'est la même chose qu'un pointeur nul en Java, et ce que vous faites déclencherait généralement une NullPointerException (merci dans les commentaires). Si vous souhaitez créer un pointeur vers votre structure, vous devez utiliser l'opérateur new:
bk = new _book;
// ...
return bk;
puis assurez-vous d'appeler supprimer sur le pointeur lorsque vous avez terminé.
Je déconseille cependant d'utiliser des pointeurs ici. Contrairement à d'autres langages, C++ vous permet de créer des objets par valeur. Il permet également des références et des pointeurs, mais n'utilisez des pointeurs que lorsque vous en avez absolument besoin. Si vous voulez simplement créer un objet livre avec un numéro de page donné, vous devez créer un constructeur pendant que vous y êtes:
struct _book {
int pageNum;
_book(int n) : pageNum(n) // Create an object of type _book.
{
}
};
puis vous pouvez l'invoquer comme
_book myBook(5); // myBook.pageNum == 5
Si vous êtes nouveau en C++, veuillez vous procurer un bon livre à ce sujet. Ce n'est pas seulement un langage de bas niveau, et ce n'est pas seulement un langage OOP. C'est un langage de couteau suisse multi-paradigme.
Voici ce dont vous avez besoin:
Book CreateBook( unsigned int pageNum){
Book bk = new _book();
bk->pageNum = pageNum;
return bk;
}
votre bk était nul et vous ne pouvez pas accéder à pageNum lorsque le pointeur est nul.
Et n'oubliez pas d'appeler delete sur bk lorsque vous avez fini de l'utiliser.
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;
};
C'est la solution la plus simple. Les livres sont des valeurs réelles et peuvent être copiés et déplacés, etc.
Si vous avez besoin de l'opacité d'un type abstrait, alors seulement vous devriez vous occuper des pointeurs. Lorsque vous traitez des pointeurs, les cacher derrière un typedef
est une mauvaise idée: les pointeurs signifient la gestion des ressources, il doit donc être évident que vous les utilisez.
La version basée sur le pointeur:
#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;
};
mais, si vous créez des trucs, vous devriez probablement créer des pointeurs intelligents:
#include <memory>
std::shared_ptr<Book> CreateBook( unsigned int pageNum){
std::shared_ptr<Book> bk( new Book );
bk->pageNum = pageNum;
return bk;
};
Pourquoi faites-vous le typedefing? Cela peut être une bonne pratique dans certains cas pour une raison quelconque, je suppose.
Si vous ne le saviez pas, vous pouvez également écrire simplement:
_livre livre;
Maintenant, book est alloué statiquement sur la pile plutôt que dynamiquement dans le tas. Il sera détruit automatiquement lorsque la variable sortira du champ d'application comme int ou double, etc ...
Cela est parfois utile si vous voulez éviter la surcharge ou le travail d'allocation de mémoire pour quelque chose de vraiment simple. C'était bizarre pour moi d'entrer dans Java et de dire,
position vec3 = nouveau Vec3 (0,0, 1,0, 5,0);
au lieu de simplement dire
position vec3 (0,0, 1,0, 5,0);
comme vous le feriez en C++.
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;
}
ou
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;
}
mais si vous ne voulez pas créer une variable à partir du tas, vous pouvez directement créer et retourner de cette façon
bk = _book{any_data_that_you_want_to_insert};
// ...
return bk;
Dans
Book bk;
bk
est un pointeur
Allouez-lui d'abord de la mémoire
Book bk* = new _book();
Et puis
bk->pageNum = pageNum;
N'oubliez pas non plus de libérer la mémoire en utilisant
delete bk;