web-dev-qa-db-ja.com

C ++:アクセス違反の書き込み場所

使用:MSVS2012

コード

elemalg.h

#include <vector>
#include <string>
#include <fstream>

class ElemAlg
{
private:
std::string difficultlyLevel, question, answerToRead;
std::vector<std::string> questions, answers;

std::vector<std::string> GetQuiz(int);
};

elemalg.cpp

#include "elemalg.h"

std::vector<std::string> ElemAlg::GetQuiz(int difficulty)
{
if (difficulty == 1) { difficultyLevel = "algE"; }
if (difficulty == 2) { difficultyLevel = "algM"; }  
if (difficulty == 3) { difficultyLevel = "algH"; }
if (difficulty == 4) { difficultyLevel = "algVH"; }

std::ifstream fin(difficultyLevel + ".txt");
while (std::getline(fin, question)) { questions.Push_back(question); }
fin.close();

std::ifstream fin2(difficultyLevel + "Answers.txt");
while (std::getline(fin2, answerToRead))    { answers.Push_back(answerToRead); }
fin2.close();

return questions;
}

MathTutor.cpp

#includes etc
ElemAlg *ea;
ea->GetQuiz(1);

GetQuizには必ず1から4までの整数が渡されます。これは、メソッドが呼び出される前に検証されます

difficultyLevelは、ヘッダーファイルで定義された文字列です。

コンパイラは、最初のif関数に到達するとすぐに、未処理の例外とアクセス違反の書き込み場所をスローします。

同じ問題をテストするためだけにif関数を削除し、difficultyLevelをalgEとして定義すると、.

difficultyLevelを完全に削除し、ファイルを"algE.txt"および"algEAnswers"として開くと、同じ問題が発生しますが、コードがwhileループに到達すると、別のメモリロケーションで発生します。

7
user3001499

あなたの問題はここにあります:

ElemAlg *ea;
ea->GetQuiz(1);

ElemAlgのインスタンスを作成していないので、初期化されていないポインターでメンバー関数を呼び出しています。

呼び出すメンバー関数は仮想ではないため、コンパイラーはランタイム検索を行う必要がありません。これがGetQuizへの呼び出しの理由です。ただし、thisポインターはガベージになります(eaが初期化されていないため)。そのため、メンバー変数(difficultyLevelなど)にアクセスした瞬間に、未定義の動作が発生します。あなたの場合、未定義の動作はアクセス違反につながります。

初期化ea

ElemAlg *ea=new ElemAlg;
ea->GetQuiz(1)

または、ヒープに割り当てる必要がない場合は、次のようにします。

ElemAlg ea;
ea.GetQuiz(1)
18
Sean