I'd like to know why the following program gets the error "double free or corruption (fasttop)" when I run the program. I know I can use string instead of character array. But I'd like to use character array with dynamic memory allocation. Could you please let me know how I can fix this problem?
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
class Cube
{
public:
char *str;
Cube(int len)
{
str = new char[len+1];
}
Cube(const Cube &c)
{
str = new char[strlen(c.str) + 1];
strcpy(str, c.str);
}
~Cube()
{
delete [] str;
}
};
int main()
{
vector <Cube> vec;
for (int i = 0; i < 10; i++)
{
char in [] = "hello !!";
Cube c(strlen(in)+1);
strcpy(c.str, in);
vec.push_back(c);
}
int i = 0;
for ( vector<Cube>::iterator it = vec.begin(); it < vec.end(); )
{
cout << it->str << endl;
i++;
if (i % 2 == 0)
it = vec.erase(it);
else
it++;
}
for ( vector<Cube>::iterator it = vec.begin(); it < vec.end(); it++)
{
cout << it->str << endl;
}
return 0;
}
You forgot to define operator= for your class. This is the rule of Big Three (copy ctor, dtor, assignment must all be defined).
n.m. has already given a fine answer, but I found this question interesting so I decided to try to understand it a little better.
It turns out then when you call erase() on the first item of an iterator (which we will call item0), here's what the iterator does: it uses the = operator of your class to do item0 = item1. Then it deletes item1.
If you don't define your own = operator, I think it will simply copy the memory of your object over from item1 to item0, so item0 and item1 will temporarily be pointing to the same string. Then when item1 gets deleted, the string gets freed, leaving item0 in an invalid state because it has a pointer to memory that has been freed.
Here is some simple test code that reproduces and illuminates the problem:
#include <cstring>
#include <vector>
#include <stdio.h>
using namespace std;
class Cube
{
public:
char * str;
Cube(const Cube &c) { set(c.str); }
Cube(const char * s) { set(s); }
~Cube() { clear(); } // is "delete []" necessary? not sure
#if 1 // change to 0 to cause a bug
void operator=(const Cube &c)
{
clear(); // necessary to avoid memory leaks
printf("operator=\n");
set(c.str);
}
#endif
private:
void set(const char * s)
{
str = new char[strlen(s) + 1];
printf("allocated %p for %s\n", str, s);
strcpy(str, s);
}
void clear()
{
if (str)
{
printf("freeing %p: %s\n", str, str);
delete str;
}
}
};
int main(int argc, char ** argv)
{
printf("== CREATING VECTOR ==\n");
vector <Cube> vec;
vec.push_back(Cube("octopus"));
vec.push_back(Cube("squid"));
printf("== BEGINNING ITERATION ==\n");
vector<Cube>::iterator it = vec.begin();
printf("First entry is %p %s\n", it->str, it->str);
it = vec.erase(it);
printf("Second entry is %p %s\n", it->str, it->str); // this prints garbage if Cube has no = operator
return 0;
}
This code produces the following output:
== CREATING VECTOR ==
allocated 00350F98 for octopus
allocated 00350FB8 for octopus
freeing 00350F98: octopus
allocated 00350F98 for squid
allocated 00350FD8 for squid
allocated 00350FE8 for octopus
freeing 00350FB8: octopus
freeing 00350F98: squid
== BEGINNING ITERATION ==
First entry is 00350FE8 octopus
freeing 00350FE8: octopus
operator=
allocated 00350F98 for squid
freeing 00350FD8: squid
Second entry is 00350F98 squid
freeing 00350F98: squid
I compiled and ran this in Windows with MinGW. The command I used was g++ -Wl,--enable-auto-import test.cpp && a.exe.
If it hurts, don't do it:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Cube
{
public:
string str;
Cube(const string& s) : str(s) { }
};
int main()
{
vector <Cube> vec;
for (int i = 0; i < 10; i++)
{
char in [] = "hello !!";
vec.push_back(Cube(in));
}
int i = 0;
for ( vector<Cube>::iterator it = vec.begin(); it < vec.end(); )
{
cout << it->str << endl;
i++;
if (i % 2 == 0)
it = vec.erase(it);
else
it++;
}
for ( vector<Cube>::iterator it = vec.begin(); it < vec.end(); it++)
{
cout << it->str << endl;
}
return 0;
}
Happens to be shorter and correct (not tested).
Related
When I access array elements through unique_ptr, a segfault occurs,Through vs debugging, I found that the type and data of std::unique_ptr<T[]> p is strange,I think it should be an array, but it looks like a string,No matter how many elements I push, the data of p points to "to", and other elements cannot be seen.
code
#include <memory>
#include <string>
#include <assert.h>
#include<vector>
#include<iostream>
#include <stack>
#include <string>
#include <sstream>
template <typename T>
class FixedCapacityStockOfStrings {
public:
FixedCapacityStockOfStrings(const int cap) {
p = std::make_unique<T[]>(cap);
MAX = cap;
}
bool isEmpty() {
return N == 0;
}
size_t const size() { return N; }
void push(T& item){
//assert(N < MAX - 1);
if (N == MAX-1) resize(2 * MAX);
p[N++] = item;
}
T pop() {
assert(N > 0);
T item = p[--N];
p[N] = nullptr;//Segmentation fault is here
if ( N <= MAX / 4) resize(MAX / 2);
return item;
}
size_t max() const { return MAX; }
void clear() {
N = 0;
}
private:
void resize(int max) {
auto t = std::make_unique<T[]>(max);
for (int i = 0; i < N; i++) {
t[i] = p[i];
}
p.reset();
p = std::move(t);
MAX = max;
}
std::unique_ptr<T[]> p;
size_t N,MAX;
};
int main() {
FixedCapacityStockOfStrings<std::string> s(100);
std::string line,item;
while (std::getline(std::cin, line)) {
std::istringstream items(line);
while (items >> item) {
if (item != "-")
s.push(item);
else if (!s.isEmpty()) std::cout << s.pop() << " ";
}
std::cout << "(" << s.size() << " left on stack)" << " max stack : " << s.max() << std::endl;
s.clear();
}
}
Note that p[N] has type std::string& for T = std::string, so what
p[N] = nullptr;
does is call std::string::operator=(const char*) with parameter nullptr. This is not a parameter you're allowed to pass to this assignment operator; it expects a 0-terminated string.
Edit: Improved based on suggestion by #Remy Lebeau
You should go with
p[N] = T{};
instead.
You forgot to initialize N in the constructor, so it is a garbage value and reading it is undefined behavior.
p contains an array of std::string. When you assign p[N] = nullptr, you assign a C string to std::string. C string is a pointer to a null-terminated character array and nullptr is not a valid C string.
In the statement p[N] = nullptr;, you are assigning a nullptr to a std::string, which is Undefined Behavior.
#include<iostream>
#include<string>
#include<sstream>
#include <typeinfo>
#include<cmath>
#include<vector>
#include <algorithm>
using namespace std;
class Mystring {
char *arr;
public:
Mystring(const char pointer[]) {
int i = 0;
while (pointer[i] != '\0') {
i++;
cout << pointer[i] << endl;
}
arr = new char[i];
i = 0;
while (pointer[i] != '\0') {
arr[i] = pointer[i];
i++;
}
}
friend ostream& operator<<(ostream& out, Mystring& str) {
int i = 0;
while (str.arr[i] != '\0') {
out << str.arr[i];
i++;
}
return out;
}
};
int main() {
Mystring string("Hello, world!");
cout << string << endl;
}
I'm trying to create my own string class. The length of "hello world!" is 13, but the length of arr turns out to be 17. It is filled with some strange chars for some reason I don't understand. When I'm trying to cout string it returns this: Hello, world!¤¤¤¤.
You forgot to add '\0' at the end of your arr[].
Moreover, the size or arrshould be increased to incorporate this \0, as noted in #user7860670's answer.
Moreover, using string as a variable name, in addition to using namespace std;, is confusing at least.
#include<iostream>
#include<string>
#include<sstream>
#include <typeinfo>
#include<cmath>
#include<vector>
#include <algorithm>
//using namespace std;
class Mystring {
char *arr;
public:
Mystring(const char pointer[]) {
int i = 0;
while (pointer[i] != '\0') {
i++;
std::cout << pointer[i] << std::endl;
}
arr = new char[i+1];
i = 0;
while (pointer[i] != '\0') {
arr[i] = pointer[i];
i++;
}
arr[i] = '\0';
}
friend std::ostream& operator<<(std::ostream& out, const Mystring& str) {
int i = 0;
while (str.arr[i] != '\0') {
out << str.arr[i];
i++;
}
return out;
}
};
int main() {
Mystring mstring("Hello, world!");
std::cout << mstring << std::endl;
}
Buffer size required to hold "Hello, world!" (including terminating null) is 14 while you only allocate space for 13 chars and completely omit terminating null. So during iteration inside of operator<< buffer index will go out of bounds which is Undefined Behavior.
You should allocate one extra byte and make sure that buffer ends with terminating null
arr = new char[i + 1];
i = 0;
while (pointer[i] != '\0')
{
arr[i] = pointer[i];
++i;
}
arr[i] = '\0';
So I am with some XML files and I want to make a function that reads an XML file and returns an array that includes things like parameters and their values. So far, I am able to read the correct values. My problem occurs when I make a const char* read() function and include the code that is in the bottom, and return const char*. It has to be const char* because the return value from parsing the XML file is a const char*. How do I make a fuction that returns an array that I am able to read in a different function?
I tried using pointers from an example I read, but it gives me: cannot convert 'const char*[3][2] to int* in assignement.
How do I use these pointers to arrays properly without gtting a type error?
#include <QCoreApplication>
#include <iostream>
#include <stdio.h>
#include <tinyxml.h>
#include <sstream>
using namespace std;
int main (void)
{
const char* ptr;
ptr = read();
cout<<ptr[0][0]<<endl;
return 1;
}
const char* read()
{
//READING XML FILE
const char* pFilename = "Profile.xml";
TiXmlDocument doc (pFilename);
if(!doc.LoadFile()) return 1;
const char *xmlread [3][2] = {0};
TiXmlElement *pRoot, *pParm;
int i = 0;
pRoot = doc.FirstChildElement("PRO");
if (pRoot) //parsing
{
pParm = pRoot->FirstChildElement("Parameter");
while (pParm)
{
xmlread[i][0] = pParm->Attribute("name");
xmlread[i][1] = pParm->Attribute("value");
pParm = pParm->NextSiblingElement("Parameter");
cout<<xmlread[i][0]<<endl;
cout<<xmlread[i][1]<<endl;
i++;
}
}
return xmlread;
}
You are writing a program in C++, not C, so you really should not be using raw pointers at all! Just because the XML library returns values as const char* does not mean you have to do the same. Especially since you are trying to return pointers owned by an XML document that is destroyed when your function exits, thus invalidating any pointers you store in the array.
If you absolutely need to return an array of strings using raw pointers (which you don't in C++!), it would look something more like this instead:
#include <QCoreApplication>
#include <iostream>
#include <tinyxml.h>
#include <stdio.h>
using namespace std;
char* myStrDup(const char *s)
{
//return strdup(s);
int len = strlen(s);
char *ptr = new char[len+1];
memcpy(ptr, s, len);
ptr[len] = '\0';
return ptr;
}
char*** read(int *count)
{
*count = 0;
//READING XML FILE
TiXmlDocument doc ("Profile.xml");
if (!doc.LoadFile())
return NULL;
TiXmlElement *pRoot = doc.FirstChildElement("PRO");
if (pRoot) //parsing
{
TiXmlElement *pParm = pRoot->FirstChildElement("Parameter");
while (pParm)
{
++(*count);
pParm = pParm->NextSiblingElement("Parameter");
}
}
char ***xmlread;
int i = 0;
try
{
xmlread = new char**[*count];
try
{
pRoot = doc.FirstChildElement("PRO");
if (pRoot) //parsing
{
pParm = pRoot->FirstChildElement("Parameter");
while (pParm)
{
xmlread[i] = new char*[2];
try
{
xmlread[i][0] = NULL;
xmlread[i][1] = NULL;
try
{
xmlread[i][0] = myStrDup(pParm->Attribute("name"));
xmlread[i][1] = myStrDup(pParm->Attribute("value"));
}
catch (...)
{
delete[] xmlread[i][0];
delete[] xmlread[i][1];
throw;
}
}
catch (...)
{
delete[] xmlread[i];
throw;
}
++i;
pParm = pParm->NextSiblingElement("Parameter");
}
}
}
catch (...)
{
for (int j = 0; j < i; ++j)
{
delete[] xmlread[j][0];
delete[] xmlread[j][1];
delete[] xmlread[j];
}
delete[] xmlread;
throw;
}
}
catch (...)
{
return NULL;
}
return xmlread;
}
int main()
{
int count;
char*** ptr = read(&count);
if (ptr)
{
for(int i = 0; i < count; ++)
{
cout << ptr[i][0] << endl;
cout << ptr[i][1] << endl;
}
for(int i = 0; i < count; ++)
{
delete[] ptr[i][0];
delete[] ptr[i][1];
delete[] ptr[i];
}
delete[] ptr;
}
return 0;
}
Not so nice, is it? You could make it slightly nicer by returning an array whose elements are a struct type to hold the string pointers:
#include <QCoreApplication>
#include <iostream>
#include <tinyxml.h>
#include <stdio.h>
using namespace std;
struct NameValue
{
char *name;
char *value;
NameValue() : name(NULL), value(NULL) {}
~NameValue() { delete[] name; delete[] value; }
};
char* myStrDup(const char *s)
{
//return strdup(s);
int len = strlen(s);
char *ptr = new char[len+1];
memcpy(ptr, s, len);
ptr[len] = '\0';
return ptr;
}
NameValue* read(int *count)
{
*count = 0;
//READING XML FILE
TiXmlDocument doc ("Profile.xml");
if (!doc.LoadFile())
return NULL;
TiXmlElement *pRoot = doc.FirstChildElement("PRO");
if (pRoot) //parsing
{
TiXmlElement *pParm = pRoot->FirstChildElement("Parameter");
while (pParm)
{
++(*count);
pParm = pParm->NextSiblingElement("Parameter");
}
}
NameValue *xmlread;
int i = 0;
try
{
xmlread = new NameValue[*count];
try
{
pRoot = doc.FirstChildElement("PRO");
if (pRoot) //parsing
{
pParm = pRoot->FirstChildElement("Parameter");
while (pParm)
{
xmlread[i].name = myStrDup(pParm->Attribute("name"));
xmlread[i].value = myStrDup(pParm->Attribute("value"));
++i;
pParm = pParm->NextSiblingElement("Parameter");
}
}
}
catch (...)
{
delete[] xmlread;
throw;
}
}
catch (...)
{
return NULL;
}
return xmlread;
}
int main()
{
int count;
NameValue* ptr = read(&count);
if (ptr)
{
for (int i = 0; i < count; ++i)
{
cout << ptr[i].name << endl;
cout << ptr[i].value << endl;
}
delete[] ptr;
}
return 0;
}
However, in C++, the best option is to have your function return a std::vector instead, where the struct type holds std::string members for the strings. Let the C++ standard library handle all of the memory management for you:
#include <QCoreApplication>
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include <tinyxml.h>
using namespace std;
struct NameValue
{
string name;
string value;
};
vector<NameValue> read()
{
vector<NameValue> xmlread;
//READING XML FILE
TiXmlDocument doc ("Profile.xml");
if (doc.LoadFile())
{
TiXmlElement *pRoot = doc.FirstChildElement("PRO");
if (pRoot) //parsing
{
TiXmlElement *pParm = pRoot->FirstChildElement("Parameter");
while (pParm)
{
NameValue elem;
elem.name = pParm->Attribute("name");
elem.value = pParm->Attribute("value");
xmlread.push_back(elem);
pParm = pParm->NextSiblingElement("Parameter");
}
}
}
return xmlread;
}
int main()
{
try
{
vector<NameValue> elems = read();
for (vector<NameValue>::size_type i = 0; i < elems.size(); ++i)
{
cout << elems[i].name << endl;
cout << elems[i].value << endl;
}
/* or:
for (vector<NameValue>::iterator iter = elems.begin(); iter != elems.end(); ++iter)
{
cout << iter->name << endl;
cout << iter->value << endl;
}
*/
/* or:
for (auto &elem : elems)
{
cout << elem.name << endl;
cout << elem.value << endl;
}
*/
}
catch (const exception &e)
{
cerr << e.what() << endl;
}
return 0;
}
const char* ptr;
...
cout<<ptr[0][0]<<endl;
This cannot possibly work. If ptr is pointer to a(n array of) character, then ptr[0] is a character object (specifically, the first character of the pointed array of characters). Further applying [0] on that character is ill-formed since there is no subscript operator for arguments char and int.
TiXmlDocument doc (pFilename);
...
xmlread[i][0] = pParm->Attribute("name");
...
return xmlread;
You've declared doc as an automatic variable. Automatic variables are destroyed automatically at the end of the scope where they are declared. Attribute member function returns pointers to memory owned by the document. The destructor of TiXmlDocument will destroy the owned memory, and the pointers in the array xmlread will be dangling after the function has returned. The behaviour of accessing memory pointed by a dangling pointer is undefined.
The xmlread array itself is also an automatic variable, and is destroyed at the end of read as well. It is not possible to return an array out of a function, and returning a pointer to an array would simply result in a dangling pointer.
Finally there is the problem that the return type is "pointer to char", while you're attempting to return an array of arrays of pointers to char. That is simply ill-formed.
You can return containers from a function such as std::vector. You can structure the "rows" of your 2d array into a readable form using a class that contains instances of std::string. Remy has shown you how to do this in practice in another answer.
Is there a way to use pointers correctly instead of having to change my array and add struct types?
Well, if you can change where you keep the array, then a minimal fix to your code is to put the array into main, and pass a reference to it into read, so that read can fill it. You must also do the same for TiXmlDocument.
I am trying to create a dynamic string array in c++. When trying to display the contents of my dynamic string array to the console I receive this error:
Exception thrown at 0x0FD670B6 (msvcp140d.dll) in Assignment4.exe: 0xC0000005: Access violation reading location 0xDDDDDDDD.
Here is my code:
DynamicStringArray.h
#pragma once
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
class DynamicStringArray
{
public:
DynamicStringArray();
DynamicStringArray(DynamicStringArray &array);
~DynamicStringArray();
int getSize();
void displayContents();
void addEntry(const string &addElement);
string getEntry(int index);
int deleteEntry(const string &deleteElement);
private:
string *dynamicArray;
int size;
};
DynamicStringArray.cpp
#include "stdafx.h"
#include "DynamicStringArray.h"
#include <string>
#include <iostream>
using namespace std;
DynamicStringArray::DynamicStringArray()
{
dynamicArray = NULL;
size = 0;
}
DynamicStringArray::DynamicStringArray(DynamicStringArray &array)
{
if (dynamicArray != NULL)
{
size = 0;
delete [] dynamicArray;
dynamicArray = NULL;
}
size = array.getSize();
dynamicArray = new string[size];
for (int i = 0; i < size; i++)
dynamicArray[i] = array.dynamicArray[i];
}
DynamicStringArray::~DynamicStringArray()
{
cout << "In destructor." << endl;
delete [] dynamicArray;
dynamicArray = NULL;
}
int DynamicStringArray::getSize()
{
return size;
}
void DynamicStringArray::displayContents()
{
if (size != 0)
for (int i = 0; i < size; i++)
cout << "Item-" << i << ": " << dynamicArray[i] << endl;
else
cout << "Array is empty." << endl;
}
void DynamicStringArray::addEntry(const string &addElement)
{
string *temp = new string[size + 1];
for (int i = 0; i < size; i++)
temp[i] = dynamicArray[i];
temp[size] = addElement;
size++;
delete [] dynamicArray;
dynamicArray = temp;
delete[] temp;
}
string DynamicStringArray::getEntry(int index)
{
if ((index >= 0) && (index < size))
{
return dynamicArray[index];
}
return NULL;
}
int DynamicStringArray::deleteEntry(const string &deleteElement)
{
if(size == 0)
{
return false;
}
for (int i = 0; i < size; i++)
{
if (dynamicArray[i] == deleteElement)
{
string *temp = new string[size - 1];
for (int x = 0; x < size - 1; ++x)
{
if (x < i)
temp[x] = dynamicArray[x];
else
temp[x] = dynamicArray[x + 1];
}
delete[] dynamicArray;
dynamicArray = temp;
delete[] temp;
--size;
return true;
}
}
return false;
}
main:
int main()
{
DynamicStringArray dsArray1;
cout << "dsArray1.displayContents():" << endl;
dsArray1.displayContents(); // Should indicate array is empty
cout << "Display dsArray1.getSize()= " << dsArray1.getSize() << endl;
dsArray1.addEntry("Entry-A");
dsArray1.displayContents();
dsArray1.addEntry("Entry-B");
dsArray1.displayContents();
dsArray1.addEntry("Entry-C");
dsArray1.displayContents();
return 0;
}
Can anyone tell me what I am doing wrong. How can i fix this problem?
Please note that all of this is already available by utilizing
std::vector<std::string>. The std::vector class is the dynamic array class that C++ provides, and there is little to no reason to make home-made versions of what is available to you.
Having said this, one glaring issue is that your copy constructor is incorrect. The dynamicArray is uninitialized, but you use it here:
if (dynamicArray != NULL)
There is no guarantee what value dynamicArray has. The fix is to remove this entire block of code in the copy constructor:
if (dynamicArray != NULL)
{
size = 0;
delete [] dynamicArray;
dynamicArray = NULL;
}
Since the copy constructor constructs a brand new object, there is no reason to "pretest" for a NULL pointer and thus do unnecessary work. Remember that the object did not exist, so there is nothing preliminary to do.
The second issue is that you're issuing a delete [] temp; call in the addEntry and deleteEntry functions. Remove these lines, as you are deallocating the memory that you've just assigned to dynamicArray.
The third issue is that you're missing the user-defined assignment operator. The assignment operator has the following signature, and you need to provide the implementation:
DynamicStringArray& operator=(const DynamicStringArray& );
Without this function, assigning a DynamicStringArray to another DynamicStringArray will cause memory leaks and double deallocation of memory when both objects go out of scope.
One implementation can use the copy / swap idiom:
#include <algorithm>
//...
DynamicStringArray& DynamicStringArray::operator=(const DynamicStringArray& rhs)
{
DynamicStringArray temp(rhs);
std::swap(temp.dynamicArray, dynamicArray);
std::swap(temp.size, size);
return *this;
}
Another issue is this:
string DynamicStringArray::getEntry(int index)
{
if ((index >= 0) && (index < size))
{
return dynamicArray[index];
}
return NULL; // <-- Undefined behavior if this is done
}
It is undefined behavior to assign a std::string object with NULL. Either return an empty string, or throw an exception if the index is out of bounds.
In conclusion, I highly recommend that you read up on the Rule of 3 when it comes to designing classes that must implement correct copy semantics.
So I'm trying to create a 2 dimensional array of pointers to a object of type Piece. The problem is when i try assign a pointer to a piece to the array i get a segmentation fault. I realized I needed to initialize to array to sometime before I can start allocating but I can't get it right.
Here is the header file of Map which contains a 2-d array of pointers.
#ifndef MAP_H
#define MAP_H
#include <iostream>
#include <vector>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <string>
#include <cstring>
#include "Player.h"
#include "Sprite.h"
#include "Piece.h"
#include "Messages.h"
#include "PieceType.h"
using namespace std;
class Map
{
private:
Piece*** pieces;
int startingX;
int startingY;
int width;
int height;
string mapName;
public:
Map(string);
~Map();
void printMap() const;
Piece* pieceType(char);
void setSprite(Piece*);
void firstMove();
void resetMap(string);
bool moveUp(int, int);
bool moveDown(int, int);
bool moveLeft(int, int);
bool moveRight(int, int);
int getHeight();
int getWidth();
};
#endif
The array I'm talking about is pieces.
I try to allocate this in the constructor of Map.
Map::Map(string name)
{
ifstream map;
string line;
string dimention;
mapName = name;
map.open(name.c_str());
if (map.good())
{
getline (map, line);
int i = 0;
while(line[i] != 'X')
{
dimention[i] = line[i];
i++;
}
stringstream convert(dimention);
convert >> width;
int temp = i;
dimention = "";
i = 1;
while(line[(i + temp)] != '\0')
{
dimention[i] = line[(i + temp)];
i++;
}
stringstream convertTwo(dimention);
convertTwo >> height;
for (int i = 0; i < height; i++)
{
if (!(map.eof()))
{
getline (map, line);
}
else
{
cout << "Error with file" << endl;
break;
}
for (int j = 0; j < width; j++)
{
pieces[i][j] = pieceType(line[j]); //This is where I'm getting the segmentation fault
cout << "assigned" << endl;
if ((pieces[i][j])->getType() == WAYPOINT)
{
if (pieces[i][j]->getWaypointType() == 0)
{
startingX = j;
startingY = i;
}
}
else
{
(pieces[i][j])->setXCordinate(j);
(pieces[i][j])->setYCordinate(i);
}
}
}
}
}
Where name is a string that holds the name of the file that has the information for loading a particular map.
Also the function pieceType is as follows:
Piece* Map::pieceType(char type)
{
Piece* temp;
if (type == '.')
{
return NULL;
}
if (type == 'S')
{
temp = new Waypoint(0);
return temp;
}
if (type == 'E')
{
temp = new Waypoint(1);
return temp;
}
}
Waypoint is a derived class of Piece.
The problem is indeed that you have to initialize that array. Like this:
pieces=new Piece**[height];
for(int i=0;i<height;i++){
pieces[i]=new Piece*[width];
}
Write that just after you get width and height, and before you start using pieces.
But something you should know: for each new, there should be a corresponding delete, or else that memory will never be freed, and you will get a memory leak. To free that memory, add this in your destructor:
for(int i=0;i<height;i++){
for (int j = 0; j < width; j++){
delete pieces[i][j];
}
delete[] pieces[i];
}
delete[] pieces;
This assumes that every pieces[i][j] contains either an object allocated with new or NULL, and it works with both. Looking at your code, that seems to be your case. However, it would not work if one of them is not assigned (not your case).
Use std::vector<std::vector<Pieces>>instead of (trying to, because it does not work) reinventing the wheel. Its safe, easy, and avoids getting manual-memory-management headaches.