使用指针时访问冲突写入位置

时间:2014-05-24 05:27:27

标签: c++

我正在尝试编写一个程序,允许用户将数据输入到文本文件中以组织类分配。用户可以显示分配列表,在文件中输入分配,以及搜索到期的特定课程作业。我遇到一个问题,我遇到访问冲突写入位置错误,我不完全确定如何解决它。我已经查看了之前发布的讨论,但无法弄清楚我在代码中出错的地方。 这是taskList.cpp。 头文件taskList.h在它之后发布。 我正在使用VS2013。

当我调试时,错误发布在

下面的taskList.cpp文件的第55行

list = new Task [capacity];

#include "taskList.h"
#include "mytools.h"

TaskList::TaskList()
{
capacity = CAP;
list = new Task[capacity];
size = 0;
}
TaskList::TaskList(char filename[])
{


capacity = CAP;
list = new Task[capacity];
size = 0;
//load from file.
ifstream inData;
Task aTask;
char tempName[MAXCHAR];
char tempDescription[MAXCHAR];
char tempDate[MAXCHAR];

inData.open("task.txt");
if (!inData){
    cout << "cannot open file";
    exit(0);
}
inData.getline(tempName, MAXCHAR, ';');
while (!inData.eof())
{
    inData.getline(tempDescription, MAXCHAR, '\n');
    inData.getline(tempDate, MAXCHAR, '\n');

    aTask.setName(tempName);
    aTask.setDescription(tempDescription);
    aTask.setDate(tempDate);
    addTask(aTask);

    inData.getline(tempName, MAXCHAR, ';');
}

inData.close();

;
TaskList::~TaskList()
{
if (list)
{
    delete [] list;
    list = NULL;
}
}
//Adds a video item to the list
void TaskList::addTask(Task aTask)
{
list[size++] = aTask;
}

//displays the list of videos
void TaskList::showList()
{
int i = 0;
for (i = 0; i < size; i++)
{
    list[i].printTask();
}
}

void TaskList::searchList()
{
char searchName[MAXCHAR];
char tempName[MAXCHAR];
int i;
bool found = false;

cout << "Enter the name of the course to search for: ";
cin.getline(searchName, MAXCHAR);

for (i = 0; i < size; i++)
{
    list[i].getName(tempName);
    if (strstr(searchName, tempName) != NULL)
    {
        list[i].printTask();
        found = true;
    }
}
if (found == false)
    cout << "No search results." << endl;
}
void TaskList::writeData()
{
ofstream outData;
outData.open("task.txt");
if (!outData)
{
    cout << "cannot open file";
    exit(0);
}
for (int i = 0; i < size; i++)
    list[i].printToFile(outData);

outData.close();
}
//expand array function
void TaskList::expand()
{
char tempName[MAXCHAR];
char tempDescription[MAXCHAR];
char tempDate[MAXCHAR];

capacity += GROWTH;
Task *temp = new Task[capacity];
//copy from old array to new array
for (int i = 0; i < size; i++)
{
    list[i].getName(tempName);
    list[i].getDescription(tempDescription);
    list[i].getDate(tempDate);

    temp[i].setName(tempName);
    temp[i].setDescription(tempDescription);
    temp[i].setDate(tempDate);
}
//delete old array
delete [] list;
list = NULL;
//point ptr to temp
list = temp;
//set temp to NULL
temp = NULL;
}

头文件(taskList.h)

#include <iostream>
#include <fstream>

using namespace std;

const int CAP = 2;
const int GROWTH = 2;

//define class VideoList for array of Videos and its size.
class TaskList
{
private:
Task *list;
int size;
int capacity;
void expand();
public:
//constructors
TaskList();
TaskList(char filename[]);
//destructor
~TaskList();
//database functions
void addTask(Task aTask);
void showList();
void searchList();
void writeData();
};

#endif

为了确保一切都清楚,因为有3个头文件,4个源文件和一个文本文件,我包含task.h头文件和task.cpp源文件。

这是task.h:

#ifndef TASK_H
#define TASK_H
#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <fstream>
#include <iomanip>
#include <string.h>

using namespace std;
const int MAXCHAR = 101;


class Task
{
private:
char *name;
char *description;
char *date;
public:
//defult constructor
Task();
//constructor with parameters
Task(char newName[], char newDescription[], char newDate[]);
//copy constructor
Task(const Task &otherTask);
//Accessor funct
void getName(char returnName[]);
void getDescription(char returnDescription[]);
void getDate(char returnDate[]);
//mutator function
void setName(char newName[]);
void setDescription(char newDescription[]);
void setDate(char newDate[]);
//print function to print a video
void printTask();
void printToFile(ofstream &outFile);

const Task& operator= (const Task& anItem);
};


#endif

这是task.cpp文件,不确定是否有必要但是为了清楚起见我添加它:

#include "task.h"
#include <iostream>
using namespace std;


//defult constructor
Task::Task()
{
strcpy(name, "no course name");
strcpy(description, "no task description");
strcpy(date, "no due date");
}

//constructor with parameters
Task::Task(char newName[], char newDescription[], char newDate[])
{
name = new char[strlen(newName) + 1];
description = new char[strlen(newDescription) + 1];
date = new char[strlen(newDate) + 1];
strcpy(name, newName);
strcpy(description, newDescription);
strcpy(date, newDate);
}
//copy constructor
Task::Task(const Task &otherTask)
{
//allocate memory and then copy name

this->name = new char[strlen(otherTask.name) + 1];
strcpy(name, otherTask.name);

//allocate memory and then copy description

this->description = new char[strlen(otherTask.description) + 1];
strcpy(description, otherTask.description);

//allocate memory and then copy date

this->date = new char[strlen(otherTask.date) + 1];
strcpy(date, otherTask.date);

}
//Accessor functions
void Task::getName(char returnName[])
{
strcpy(returnName, name);
}
void Task::getDescription(char returnDescription[])
{
strcpy(returnDescription, description);
}
void Task::getDate(char returnDate[])
{
strcpy(returnDate, date);
}

//mutator functions
void Task::setName(char newName[])
{
strcpy(name, newName);
}
void Task::setDescription(char newDescription[])
{
strcpy(description, newDescription);
}
void Task::setDate(char newDate[])
{
strcpy(date, newDate);
}

//prints a video item
void Task::printTask()
{
cout << name << ';' << description << ';' << date << endl;

}

void Task::printToFile(ofstream &outFile)
{
outFile << name << ';' << description << ';' << date << endl;
}

//assignment operator overloaded
const Task& Task::operator= (const Task& aTask)
{
strcpy(this->name, aTask.name);
this->description = aTask.description;
strcpy(this->description, aTask.description);
this->date = aTask.date;
strcpy(this->date, aTask.date);

return *this;
}

3 个答案:

答案 0 :(得分:2)

问题在于:

char *name;

// ...

strcpy(name, "no course name");

第一行创建一个当前不指向任何位置的指针。然后你告诉strcpy将该字符串复制到指针指向的位置,因此它将字符串写入&#34;无处&#34; (实际上:半随机存储器位置)。这会导致您的访问冲突。

要解决此问题,请将代码替换为:

std::string name;

// ...

name = "no course name";

descriptiondate执行相同的操作。请注意,这意味着您不需要复制构造函数或复制赋值运算符或析构函数;因为默认的行为正确。

当然你需要改变你的accssor函数(但是因为调用者不能阻止缓冲区溢出,所以它们设计得很糟糕):

std::string getName() const { return name; }

另外,将Task *list;更改为std::vector<Task> list;并停止使用newdelete。向量正确地为您管理内存。

在不使用指针或手动内存管理或C库函数(如strcpy)的情况下执行此任务是最简单和最简单的。您将代码大小减半(至少),并且不太容易出错。

您可能需要#include <string>#include <vector>

答案 1 :(得分:0)

由于erroe在分配时发生,如果一个数组(list = new Task[capacity])我猜你的问题是在Task类的默认构造函数中。尝试使用这个构造函数一个liitle,我建议分配yor char数组(名称,描述和数据),以填充它们。

某些代码如name = new Char[14];(当然其他两个代码相同)

答案 2 :(得分:0)

您未能遵守五条规则或零规则。

正确的事情(零规则)是用std::vector<Task>来实现TaskList。

看到你的作业要求你使用动态阵列&#34;,也许他们不希望你使用std::vector。这意味着您将无法进行手动内存管理。这意味着您需要正确实现或删除以下功能:

//You have these
TaskList::TaskList();
TaskList::TaskList(char filename[]);
TaskList::~TaskList();

//You are missing these, this is your problem:
TaskList::TaskList(TaskList const &o); //Copy constructor
TaskList &TaskList::operator=(TaskList const &o); //Copy assignment
TaskList::TaskList(TaskList &&o); //Move constructor
TaskList &TaskList::operator=(TaskList &&o); //Move assignment

如果您没有明确提供这些函数,编译器可能会自动生成它们,编译器生成的版本将不正确(对于您在TaskList内手动管理资源的情况),因为它们会这样做成员方式移动或复制,而不是复制或移动底层资源。当您使用这些不正确的编译器生成的版本时,您的代码将有奇怪的行为。

对于Task,您不应该同时管理多个资源。使用std::string或以其他方式编写自己的字符串类,然后使用它来管理Task的字符串成员。如果不这样做,您的代码几乎可以保证不正确(由于缺少异常安全性)。