how to fix 'Access violation reading location' in this code - c++

run this code i got some error like this
' Exception thrown at 0x778D7FCB (ntdll.dll) in Project1.exe: 0xC0000005: Access violation reading location 0x00000014.'
This error occurs in this line
~UnivStudnet() {
delete[]major; // error
}
#include <iostream>
#include <cstring>
using namespace std;
class Person {
private:
char * name;
public:
Person(const char * myname) {
name = new char[strlen(myname) + 1];
strcpy_s(name, strlen(name), myname);
}
~Person() {
delete[]name;
}
void WhatYourName() const {
cout << "My name is " << name << endl;
}
};
class UnivStudnet : public Person {
private:
char * major;
public:
UnivStudnet(const char * myname, const char * const mymajor) :Person(myname) {
major = new char[strlen(mymajor) + 1];
strcpy_s(major, strlen(major), mymajor);
}
~UnivStudnet() {
delete[]major;
}
void WhoAreYou() const {
WhatYourName();
cout << "My major is " << major << endl;
}
};
int main(void) {
UnivStudnet st1("kim", "Mathenatics");
st1.WhoAreYou();
UnivStudnet st2("hong", "Physiscs");
st2.WhoAreYou();
return 0;
}
How do I fix this error?

There are bugs on the two strcpy_s lines.
strcpy_s(name, strlen(name), myname);
should be
strcpy_s(name, strlen(myname)+1, myname);
and likewise
strcpy_s(major, strlen(major), mymajor);
should be
strcpy_s(major, strlen(mymajor)+1, mymajor);
Calling strlen on the newly-allocated char arrays name and major which have indeterminate values, causes undefined behavior which is the cause of your crash.

Your strcpy_s usage is suspect.
major = new char[strlen(mymajor) + 1];
strcpy_s(major, strlen(major), mymajor);
The second parameter to strcpy_s is the allocated size of the buffer specified by the first parameter. (And I just now realized - based on another answer that strlen(major) is undefined before you copy to it!
You are allocating the buffer to be large enough to hold the string, but the subsequent call to strcpy_s is indicating that major isn't big enough to hold the entire string including the null char.
Better:
size_t len = strlen(mymajor) + 1;
major = new char[len];
strcpy_s(major, len, mymajor);
Repeat the above pattern for the base class name parameter as well.

You could go more C++-way:
You need to declare:
virtual ~Person()
destructor in base class and then:
class UnivStudnet : public Person {
private:
std::string major;
public:
UnivStudnet(const char * myname, const char * const mymajor) :Person(myname), major(mymajor) {
}
virtual ~UnivStudnet() {
}
...
This way you will achieve what you need and do not think about memory allocation/deallocation. Remember to #include <string> header.
Same way do it in Person class.

Related

Why pointer to pointer was used in the code?

Why pointer to pointer has been used rather than single pointer in the code? Also do you think the destructor was written wrong if it is how can i make it correct?
pointer to pointer: employee** _arr;
You can see the code below:
#include<iostream>
class employee {
private:
std::string _name;
std::string _surname;
int _year;
double _salary;
static int numberOfEmployees;
public:
employee() {
_name = "not-set";
_surname = "not-set";
_year = 0;
_salary = 0;
numberOfEmployees++;
}
employee(int year, std::string name, std::string surname) {
_name = name;
_surname = surname;
_year = year;
numberOfEmployees++;
calculateSalary();
}
void calculateSalary() {
//salary = 2310 + 2310 * year * 12/100.0
_salary = 2310 + (2310 * (double)_year) * (12 / 100.0);
}
void printInfo() {
std::cout << _name << " " << _surname << " " << _year << " " << " " << _salary << " TL/month" << std::endl;
}
static int getEmployeeCount() {
return numberOfEmployees;
}
};
class employeeList {
private:
int _size;
int _lenght;
employee** _arr;
public:
employeeList() :_size(1), _lenght(0), _arr(NULL) {}
employeeList(int size) :_size(size) {
_arr = new employee * [_size];
_lenght = 0;
}
int listLength() {
return _lenght;
}
employee retrieve_employeeFromIndex(int index) {
if (index >= 0 && index < _size) {
return *_arr[index];
}
}
void addToList(employee* item) {
_lenght++;
if (_lenght <= _size) {
_arr[_lenght - 1] = item;
}
else {
std::cout << "you cannot add another employee!";
}
}
static void printEmployees(employeeList el) {
for (int i = 0; i < el._lenght; i++) {
el._arr[i]->printInfo();
}
}
~employeeList() {
delete[] _arr;
}
};
int employee::numberOfEmployees = 0;
int main() {
employee a;
employee b(5, "John", " Doe");
employee c(3, "Sue", "Doe");
employeeList empList(employee::getEmployeeCount());
empList.addToList(&a);
empList.addToList(&b);
empList.addToList(&c);
employeeList::printEmployees(empList);
std::cout << empList.listLength() << std::endl;
return 0;
}
you can see the output:
Why pointer to pointer has been used rather than single pointer in the code? Also do you think the destructor was written wrong if it is how can i make it correct?
Why pointer to pointer was used in the code?
This is known only by the author who wrote the code. We can make a reasonable guess that their intention may have been to:
Allocate a dynamic array of objects, using a bare pointer to the first element of that array.
Indirectly point to objects stored elsewhere, hence they wanted to use an array of pointers, thus a pointer to first element of the array is a pointer to a pointer.
Their choice 1. to use an owning bare pointer is unnecessary, and there are better choices available which do not require an owning bare pointer. Most commonly, std::vector would be used to create a dynamic array.
Their choice 2. to indirectly point to objects that aren't owned by the class instance is not quite as safe as having the class instance own the objects, but regardless that may have been a reasonable choice depending on the reasons they chose this design. It is impossible to tell whether the choice was good without documentation of what the program is supposed to do. Based on the generic name of the class, I suspect that it wasn't a good choice.
do you think the destructor was written wrong
It can be considered correct. There are other issues with the class though.
The entire employeeList class seems pointless, and can easily be replaced by a std::vector. printEmployees is the only member function that wouldn't be directly provided by a vector. You can use a non-member function for that instead.
Im not expert but u will bumb your topic :P
I think that question is not precised. You mean that pointer to pointer:?
employee** _arr;
Because is pointing a pointer:
_arr = new employee * [_size];
I think that it have sense because array is a pointer? I can be wrong ofcourse coz I just started do educate.
Why do you think destruktor is wrong? It's deleting a pointer.

Segmentation Fault in memcpy operation of a struct

I am adding the header file and cpp file (it has main fucntion).
AuctionPrices.h
#ifndef AuctionPrices_h
#define AuctionPrices_h
/*
*
* class AuctionPrices - maintains Buy Order, Sell Order books
*/
#include <bits/stdc++.h>
#include <map>
//#pragma pack(1)
struct Order
{
char * itemId;
char * auctionId;
int Side;
};
class AuctionPrices
{
public:
virtual int AddNewOrder(char *itemId, char *auctionId, int Side, int Price) = 0;
virtual int DeleteOrder(char *itemId, char *auctionId) = 0;
virtual int Print() = 0;
};
class AuctionPrice_Imp : public AuctionPrices
{
public:
AuctionPrice_Imp();
~AuctionPrice_Imp();
std::map <int, Order, std::greater< int >> BuyMap;
std::map <int, Order, std::less< int >> SellMap;
int AddNewOrder(char *itemId, char *auctionId, int Side, int Price);
int DeleteOrder(char *itemId, char *auctionId);
int Print();
};
#endif
AuctionPrices_Imp.cpp
/**
* Auction Price Class implementation
* Constructor, AddNewOrder, DeleteOrder, Print
*
*/
#include <bits/stdc++.h>
#include <map>
#include "AuctionPrices.h"
using namespace std;
AuctionPrice_Imp::AuctionPrice_Imp()
{
}
AuctionPrice_Imp::~AuctionPrice_Imp()
{
}
int AuctionPrice_Imp::AddNewOrder(char *itemId, char *auctionId, int Side, int Price)
{
Order order;
memcpy(order.itemId, itemId, strlen(itemId)+1);
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
order.Side = Side;
if (Side == 1)
{
BuyMap.insert (std::pair<int,Order>(Price,order));
//buyLevels_.insert( std::pair< OfPrice, Level< OrderEntry > >( price, buyLevel ) );
}
else if (Side == 2)
{
SellMap.insert (std::pair<int,Order>(Price,order));
}
else
{
return 0;
}
return 1;
}
int AuctionPrice_Imp::DeleteOrder(char *itemId, char *auctionId)
{
return 0;
}
int AuctionPrice_Imp::Print()
{
std::map <int,Order,std::greater< int >>::iterator buy_it;
std::map <int,Order,std::less< int >>::iterator sell_it;
// Print Sell Map
for ( sell_it = SellMap.begin();sell_it != SellMap.end(); sell_it++)
{
std::cout << sell_it->first << '\t' << std::endl;
}
// Print Buy Map
for ( buy_it = BuyMap.begin();buy_it != BuyMap.end(); buy_it++)
{
std::cout << buy_it->first << '\t' << std::endl;
}
return 1;
}
int main()
{
AuctionPrice_Imp * auctionPrice_Imp = new AuctionPrice_Imp();
/*
AddNewOrder(“item1”, “auction1”, 1, 100)
AddNewOrder(“item1”, “auction2”, 1, 101)
AddNewOrder(“item2”, “order3”, 1, 99)
AddNewOrder(“item2”, “order4”, 2, 100)
*/
auctionPrice_Imp->AddNewOrder("item1", "auction1", 1, 100);
auctionPrice_Imp->AddNewOrder("item1", "auction2", 1, 101);
auctionPrice_Imp->AddNewOrder("item2", "order3", 1, 99);
auctionPrice_Imp->AddNewOrder("item2", "order4", 2, 100);
auctionPrice_Imp->Print();
}
When I am running the code its giving segmentation fault at the line:
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
Please anyone can help or correct the code.
The functions I am calling are supposed to add the orders to the Maps: BuyMap and SellMap. Once they have added to those map, I am using a print function to print the values.
Order order;
This creates a new Order object. Order does not have a constructor, so none of its class members, itemId, and auctionId, get initialized to point to anything. These pointers are uninitialized, random garbage. Immediately afterwards:
memcpy(order.itemId, itemId, strlen(itemId)+1);
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
Since neither itemId, nor auctionId, point to sufficient memory that are at least strlen(itemId)+1 or strlen(auctionId)+1 in size, respectively, this results in undefined behavior, and your crash.
In C++, before using a pointer, it is your responsibility to make sure that the pointer is valid, and points to the correct object, objects, or sufficiently-sized memory buffers. C++ will not do that for you, you have to do all that work yourself.
But if your intent is to write modern C++ code, it is much simpler just to use C++ classes, like std::strings instead of plain char * pointers. std::strings automatically handle all these low-level details, manage memory properly, without making it your responsibility to do so. You will find a complete description of std::string and many examples of using it in your C++ textbook.
You should use std::string to avoid having to deal with low level issues of pointers and memory allocation. These are the issues that you are getting wrong in your code. Here's your code rewritten to use std::string
struct Order
{
std::string itemId;
std::string auctionId;
int Side;
};
int AuctionPrice_Imp::AddNewOrder(std::string itemId, std::string auctionId, int Side, int Price)
{
Order order;
order.itemId = itemId;
order.auctionId = auctionId;
order.Side = Side;
See how easy that is? The code to use std::string is no different to the code that handles int.

Access violation writing location when using pointers

I'm trying to write a program that allows a user to input data into a text file to organize class assignments. The user can display the list of assignments, enter an assignment into the file, and search for specific course work that is due. I am having a problem where I get an access violation writing location error and I'm not entirely sure how to fix it. I have looked at previous discussions that are posted but can't quite figure out where I am going wrong in my code.
This is taskList.cpp.
The header file taskList.h is posted after it.
I'm using VS2013.
When I debug the error is posted at line 55 in the taskList.cpp file below
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;
}
The header file (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
Just to be sure that everything is made clear because there are 3 header files, 4 source files, and a text file, I am include the task.h header file and task.cpp source file.
Here is 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
Here is the task.cpp file, not sure if this is necessary but I am adding it for clarity:
#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;
}
Here is the problem:
char *name;
// ...
strcpy(name, "no course name");
The first line creates a pointer which currently does not point anywhere. Then you tell strcpy to copy that string to where the pointer is pointing, so it writes the string to "nowhere" (in practice: a semi-random memory location). This causes your access violation.
To fix this, replace the code with:
std::string name;
// ...
name = "no course name";
Do the same for description and date. Note that this means you don't need a copy-constructor or copy-assignment operator or destructor; because the default ones behave correctly.
Of course you will need to change your accssor functions (but they were badly designed anyway since the caller cannot prevent a buffer overflow):
std::string getName() const { return name; }
Also, change Task *list; to std::vector<Task> list; and stop using new and delete. The vector correctly manages memory for you.
It is simplest and easiest to do this task without using pointers or manual memory management or C-library functions such as strcpy. You'll halve your code size (at least) and it will be much less prone to error.
You may need #include <string> and #include <vector>.
Since the erroe happens at allocation if an array (list = new Task[capacity]) i guess your problem is in default constructor of Task class. try playing with this constructor a liitle , i suggest allocating yor char arrays (names , descriptions and data) befor filling them.
somecode like name = new Char[14]; (and of course same for the other two)
You have failed to follow the rule-of-five or the rule-of-zero.
The correct thing (rule-of-zero) would be to implement TaskList in terms of std::vector<Task>.
Seeing as your assignment demands that you use a "dynamic array", perhaps they don't want you to use std::vector. This means that you are stuck with manual memory management. This means that you need to correctly implement or remove the following functions:
//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
If you do not explicitly supply these functions, the compiler may automatically generate them, and the compiler-generated versions will be incorrect (for the situation where you are manually managing resources within TaskList), as they will do member-wise moves or copies, rather than copying or moving the underlying resources. When you then use these incorrect compiler-generated versions, your code will have strange behaviour.
For Task, you shouldn't be managing multiple resources at once. Use std::string, or otherwise write your own string class, and then use it to manage the string members of Task. If you do not, your code is almost guaranteed to be incorrect (due to a lack of exception safety).

const * char in struct in class - segmentation fault

I have this code and it gives me segmentation fault.
struct TRecord {
const char * Id;
const char * Name;
};
class CClass {
CClass ();
~CClass ();
bool Add ( const char * id, const char * name);
TRecord ** m_record;
int m_count;
};
CClass::CClass (void) {
m_count = 0;
m_record = new TRecord * [1000];
}
CClass::~CClass(void) {
for(int i=0;i<m_count;i++){
delete m_record[i];
}
delete [] m_record;
}
bool CClass::Add (const char * id, const char * name) {
m_record[m_count] -> Id = new char[11];
m_record[m_count] -> Name = new char[strlen(name) + 1];
m_record[m_count] -> Id = id;
m_record[m_count] -> Name = name;
m_count++;
return true;
}
If I add for example const char haha[2222]; to struct TRecord, it works. I don't understand why. Can you help me?
P.S. I can't use string.
Add this line as to top of you Add function declaration, It will fix your Segmentation Fault problem.
m_record[m_count] = new TRecord;
But as you can see in answers and comments, your code has many problems. Most important problem is that you have not any good plan for your garbage objects. So your code have memory leakage.
One error is that you are not following the rule of three in your CRegister class. That often causes segfaults.
Another error is that you do not initialise your m_record[i] pointers. So you destructor may call delete[] on garbage values.
A third error is that you apparently dereference the same garbage values in CRegister::Add.

Program Has Unexpectedly Finished

My execution program won't work properly, for whatever reason.
#include <QtCore/QCoreApplication>
#include <tinyxml/tinyxml.h>
#include "classowner.h"
#include "character.h"
int main(int argc, char *argv[])
{
Character * holland = new Character("Holland", HUMAN, MALE);
delete &holland;
std::cout << "Hello, World!" << std::endl;
return 0;
}
All my output states is that the program won't execute properly. The output doesn't display, however when I don't allocate the object, it will. Obviously, it's the object. What am I doing wrong?
Update
It appears the problem may be something more than deleting and allocating memory. Thus, I'm going to post the implementation behind the Character class.
Header:
#include <iostream>
#ifndef CHARACTER_H
#define CHARACTER_H
enum Race {HUMAN, DARK_ELF};
enum Gender {MALE, FEMALE};
class Character
{
public:
Character();
Character(std::string char_name, Race char_race, Gender char_gender);
~Character();
int get_id() { return this->char_id; }
std::string get_name() { return this->name; }
Race get_race() { return this->race; }
Gender get_gender() { return this->gender; }
private:
int char_id;
static int * char_count;
std::string name;
Race race;
Gender gender;
};
#endif // CHARACTER_H
//Source:
#include "character.h"
#include <iostream>
int * Character::char_count = 0;
Character::Character()
{
this->char_id = *char_count;
char_count++;
}
Character::Character(std::string char_name, Race char_race, Gender char_gender)
{
this->char_id = *char_count;
char_count++;
this->name = char_name;
this->race = char_race;
this->gender = char_gender;
}
Character::~Character()
{
}
delete &holland;
should be
delete holland;
Less profanity would be appreciated.
On the other hand, posting a short example that succinctly illustrates the problem is very much appreciated.
First of all, you try to dereference a null pointer:
int * Character::char_count = 0;
Both constructors of class Character do this
this->char_id = *char_count;
and that's an attempt to dereference a null pointer. That code makes no sense to me, I guess you could just use int instead of pointer:
int Character::char_count = 0;
//then
this->char_id = char_count;
Also here:
Character * holland = new Character("Holland", HUMAN, MALE);
you create an object of type class Character. You have to delete that object through a pointer to class Character - the pointer should have type Character*. Instead you try to use delete on a pointer of type Character**and that leads to undefined behavior.
So instead of
delete &holland;
you have to use
delete holland;