(FUZZING) Get a pointer to data range of dynamic array - c++

EDIT: Clarification:
If I have an array int* a = new int[10], I want to get a pointer to a, but only the values from 0 to 5, without having to allocate another array for those values.
Original post:
I created a small class to fuzz my functions, but the thing is that it is painfully slow. It takes roughly 10-20 seconds to run my function 1000 times.
I decided to improve my code by allocating a very large array at first, then filling it from 0 to a randomly generated number and then just returning a pointer to that range to use in my function instead of allocating memory and deleting it each time.
Below is my code.
I attempt to allocate 1 million bytes at first, then I want to return a range from 0 to whatever size my class generated. Currently I allocate memory once more for returning it, but that's not efficient.
I use Xorshift to generate random numbers, which should be much faster than rand() so I think besides memory allocation it's pretty good, but any suggestions are very much welcome!
Note: if you do not understand part of my code ask me (it's written quickly, so it might be unintelligible at certain parts) ;)
class fuzz {
public:
fuzz() {
this->alloc_init_buff();
}
~fuzz() {
this->dealloc_init_buff();
}
int fill_buff(unsigned int size) {
if (size > this->m_buffsize) { size = this->m_buffsize; }
for (int i = 0; i < size; ++i) {
this->m_buff[i] = this->rand_xor();
}
return size;
}
int fill_buff() {
int size = this->rand_xor(1, this->m_buffsize);
if (size > this->m_buffsize) { size = this->m_buffsize; }
for (int i = 0; i < size; ++i) {
this->m_buff[i] = this->rand_xor();
}
return size;
}
unsigned char*& get_buff(int size) {
unsigned char* temp = new unsigned char[size];
memcpy((void*)temp, (void*)this->m_buff, size);
return temp;
}
private:
struct xr_xorshift_state {
unsigned int a = 123456789, b = 362436069, c = 521288629, d = 88675123;
};
unsigned int xorshift(xr_xorshift_state* state) {
unsigned int res = 0;
res = state->a ^ (state->a << 11);
state->a = state->b; state->b = state->c; state->c = state->d;
state->d = state->d ^ (state->d >> 19) ^ (res ^ (res >> 8));
res &= 0x7fffffff;
return res;
}
unsigned int rand_xor() {
return this->xorshift(&this->m_state);
}
unsigned int rand_xor(unsigned int min, unsigned int max) {
return (min + (this->rand_xor() % (max - min)));
}
void alloc_init_buff() {
this->m_buff = new unsigned char[this->m_buffsize];
}
void dealloc_init_buff() {
delete[] this->m_buff;
}
xr_xorshift_state m_state = { 0 };
unsigned char* m_buff = { 0 };
unsigned int m_buffsize = { 1000000 };
};
int find_newline(const char* text, int size) {
int pos = 0;
while (*text != '\n') {
if (pos == size) { return 0; }
++text; ++pos;
}
return pos;
}
int main() {
fuzz fz = {};
unsigned char* randdata = nullptr;
int lap = 0;
int th = 0;
for (;;) {
if (lap == 1000) {
lap = 0;
++th;
printf("%d thousand laps done!\n", th);
}
try {
int size = fz.fill_buff();
randdata = fz.get_buff(size);
const char* d = (const char*)randdata;
find_newline(d, size);
delete[] randdata;
++lap;
}
catch (...) {
printf("error!\n");
++lap;
}
}
getchar();
return 0;
}

Related

Improving usage of C++ vector access

I am writing currently an importer for Labplot to support BLF files. The importer works fine, but when looking at the performance it is visible that there is a lot of room to improve. It is visible that adding the data to the datacontainer consumes the most of the computational power. I tried already for testing using std::vector, but it has not that big impact.
I am not able to use a static array, because the actual number of messages is unknown (only upper limit is known), because if the dbcParser is not able to parse the message it will be skipped. So at the end of the import I have to resize the array.
Are there any recomandations how to improve the performance of the code?
Definition of v: QVector<const Vector::BLF::ObjectHeaderBase*> v;
bool firstMessageValid = false;
for (const auto ohb : v) {
int id;
std::vector<double> values;
if (ohb->objectType == Vector::BLF::ObjectType::CAN_MESSAGE) {
const auto message = reinterpret_cast<const Vector::BLF::CanMessage*>(ohb);
id = message->id;
m_dbcParser.parseMessage(message->id, message->data, values);
} else if (ohb->objectType == Vector::BLF::ObjectType::CAN_MESSAGE2) {
const auto message = reinterpret_cast<const Vector::BLF::CanMessage2*>(ohb);
id = message->id;
m_dbcParser.parseMessage(message->id, message->data, values);
} else
return 0;
if (values.size() == 0) {
// id is not available in the dbc file, so it is not possible to decode
DEBUG("Unable to decode message: " << id);
continue;
}
uint64_t timestamp;
timeInNS = getTime(ohb, timestamp);
if (convertTimeToSeconds) {
double timestamp_seconds;
if (timeInNS)
timestamp_seconds = (double)timestamp / pow(10, 9); // TimeOneNans
else
timestamp_seconds = (double)timestamp / pow(10, 5); // TimeTenMics
m_DataContainer.setData<double>(0, message_index, timestamp_seconds);
} else
m_DataContainer.setData<qint64>(0, message_index, timestamp);
if (firstMessageValid) {
const auto startIndex = idIndexTable.value(id) + 1; // +1 because of time
for (std::vector<double>::size_type i = 1; i < startIndex; i++) {
const auto prevValue = m_DataContainer.data<double>(i, message_index - 1);
m_DataContainer.setData<double>(i, message_index, prevValue);
}
for (std::vector<double>::size_type i = startIndex; i < startIndex + values.size(); i++) {
m_DataContainer.setData<double>(i, message_index, values.at(i - startIndex));
}
for (std::vector<double>::size_type i = startIndex + values.size(); i < m_DataContainer.size(); i++) {
const auto prevValue = m_DataContainer.data<double>(i, message_index - 1);
m_DataContainer.setData<double>(i, message_index, prevValue);
}
} else {
const auto startIndex = idIndexTable.value(id) + 1; // +1 because of time
for (std::vector<double>::size_type i = 1; i < startIndex; i++) {
m_DataContainer.setData<double>(i, message_index, 0);
}
for (std::vector<double>::size_type i = startIndex; i < startIndex + values.size(); i++) {
m_DataContainer.setData<double>(i, message_index, values.at(i - startIndex));
}
for (std::vector<double>::size_type i = startIndex + values.size(); i < m_DataContainer.size(); i++) {
m_DataContainer.setData<double>(i, message_index, 0);
}
firstMessageValid = true;
}
message_index++;
}
struct DataContainer {
void clear();
template<class T>
void appendVector(QVector<T>* data, AbstractColumn::ColumnMode cm) {
m_dataContainer.push_back(data);
m_columnModes.append(cm);
};
template<class T>
void setData(int indexDataContainer, int indexData, T value) {
auto* v = static_cast<QVector<T>*>(m_dataContainer.at(indexDataContainer));
v->operator[](indexData) = value;
}
template<class T>
T data(int indexDataContainer, int indexData) {
auto* v = static_cast<QVector<T>*>(m_dataContainer.at(indexDataContainer));
return v->at(indexData);
}
int size() const;
const QVector<AbstractColumn::ColumnMode> columnModes() const;
/*!
* \brief dataContainer
* Do not modify outside as long as DataContainer exists!
* \return
*/
std::vector<void*> dataContainer() const;
AbstractColumn::ColumnMode columnMode(int index) const;
const void* datas(int index) const;
bool resize(uint32_t) const;
private:
QVector<AbstractColumn::ColumnMode> m_columnModes;
std::vector<void*> m_dataContainer; // pointers to the actual data containers
};
Edit
Before the loop I resize every vector to the absolute maximum number of messages.
if (convertTimeToSeconds) {
auto* vector = new QVector<double>();
vector->resize(message_counter);
m_DataContainer.appendVector<double>(vector, AbstractColumn::ColumnMode::Double);
} else {
auto* vector = new QVector<qint64>();
vector->resize(message_counter);
m_DataContainer.appendVector<qint64>(vector, AbstractColumn::ColumnMode::BigInt); // BigInt is qint64 and not quint64!
}
for (int i = 0; i < vectorNames.length(); i++) {
auto* vector = new QVector<double>();
vector->resize(message_counter);
m_DataContainer.appendVector(vector, AbstractColumn::ColumnMode::Double);
}
During parsing I discard messages if I am not able to parse them, therefore message_index <= message_counter. So when having 100k messages, but I parse only 50k of them, I have to resize the array at the end to not waste memory.
m_DataContainer.resize(message_index);
Edit2
Replacing
auto* v = static_cast<QVector<T>*>(m_dataContainer.at(indexDataContainer));
v->operator[](indexData) = value;
by
static_cast<QVector<T>*>(m_dataContainer.at(indexDataContainer))->operator[](indexData) = value;
and replacing
auto* v = static_cast<QVector<T>*>(m_dataContainer.at(indexDataContainer));
return v->at(indexData);
by
return static_cast<QVector<T>*>(m_dataContainer.at(indexDataContainer))->at(indexData);
brought about 20%. I thought it will be optimized out at -O2 but was not.
With -O2 moving from QVector to std::vector was again an improvement of around 25%

C++ array of unsigned char arrays

I'm trying to understand how to create & handle an array of unsigned char arrays in C++. Such as:
Array[0] = { new array of unsigned chars }
Array[1] = { new array of unsigned chars }
Array[2] = { new array of unsigned chars }
....and so on
I've written the next code but I have the feeling that I'm doing something wrong. The code works correctly, but I don't know if the way I declare the "buffer" and how I delete the cache is the correct way, or if it can produce a memory leak.
#define MAX_BUFFER 10
unsigned char* cache[MAX_BUFFER];
bool cache_full = false;
void AddToCache(unsigned char *buffer, const size_t buffer_size)
{
if (cache_full == true)
{
return;
}
for (int index = 0; index < MAX_BUFFER; index++)
{
if (cache[index] == NULL)
{
cache[index] = new unsigned char[buffer_size];
memcpy(cache[index], buffer, buffer_size);
}
if (index < MAX_BUFFER - 1)
{
cache_full = true;
}
}
}
void ClearCache()
{
for (int index = 0; index < MAX_BUFFER; index++)
{
if (cache[index] != NULL)
{
delete[] cache[index];
cache[index] = NULL;
}
}
cache_full = false;
}
bool IsCacheFull()
{
return cache_full;
}
This works?
memcpy(cache, buffer, buffer_size);
It shouldn't. That's overwriting all the pointers in cache with the contents of buffer. In context, this should probably be:
memcpy(cache[index], buffer, buffer_size);
Also, you'll be setting cache_full to true, repeatedly, every time you add to the cache. Try:
AddToCache(unsigned char *buffer, const size_t buffer_size)
{
for (int index = 0; index < MAX_BUFFER; index++)
{
if (cache[index] == NULL)
{
cache[index] = new unsigned char[buffer_size];
memcpy(cache[index], buffer, buffer_size);
return(index); // in case you want to find it again
}
}
// if we get here, we didn't find an empty space
cache_full = true;
return -1;
}

C++ vector equivalent in C [duplicate]

This question already has answers here:
How to replicate vector in c?
(6 answers)
Closed 2 years ago.
I have a code (C++) that looks like this
vector<int> values[10000];
int i, j;
while (.....) {
scanf("%d%d", &i, &j);
values[i].push_back(j);
values[j].push_back(i);
}
but I want to rewrite this code to C. How can I do this?
I researched the opportunity to make the own stack, but maybe have more lightweight way to rewrite this code, maybe two-dimensional arrays. So far I can not think how this remake, I hope that someone more experienced tell me how to do it :)
Sorry guys, added a more advanced example...
Instead of rolling your own, you may want to try a C container library, e.g. http://code.google.com/p/ccl/
You can use Gena library. It closely resembles stl::vector in pure C89.
You can check it out here:
https://github.com/cher-nov/Gena
Something like this:
#include <stdio.h>
#include <stdlib.h>
typedef struct _darray
{
size_t size;
size_t actual_size;
int *content;
} darray;
void darray_create(darray *d)
{
d->actual_size = d->size = 0;
d->content = NULL;
}
void darray_append(darray *d, int v)
{
if (d->size+1 > d->actual_size)
{
size_t new_size;
if (!d->actual_size)
{
new_size = 1;
}
else
{
new_size = d->actual_size * 2;
}
int *temp = realloc(d->content, sizeof(int) * new_size);
if (!temp)
{
fprintf(stderr, "Failed to extend array (new_size=%zu)\n", new_size);
exit(EXIT_FAILURE);
}
d->actual_size = new_size;
d->content = temp;
}
d->content[d->size] = v;
d->size++;
}
const int* darray_data(darray *d)
{
return d->content;
}
void darray_destroy(darray *d)
{
free(d->content);
d->content = NULL;
d->size = d->actual_size = 0;
}
size_t darray_size(darray *d)
{
return d->size;
}
int main()
{
int i;
darray myarray;
const int *a;
darray_create(&myarray);
for(i = 0; i < 100; i++)
{
darray_append(&myarray, i);
}
a = darray_data(&myarray);
for(i = 0; i < darray_size(&myarray); i++)
{
printf("i=%d, value=%d\n", i, a[i]);
}
darray_destroy(&myarray);
}
You can try something like this:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct vector
{
int len;
int allocated;
int step;
int *data;
};
#define INIT_SIZE 1
void init_vector(struct vector *v)
{
v->len = 0;
v->allocated = 0;
v->step = 2;
v->data = NULL;
}
int append(struct vector *v, int item)
{
if (!v->data)
{
v->data = malloc(INIT_SIZE * sizeof(int));
if (!v->data)
return -1;
v->allocated = INIT_SIZE;
}
else
if (v->len >= v-vallocated)
{
int *tmp = realloc(v->data,
v->allocated * v->step * sizeof(int));
if (!tmp)
return -1;
v->data = tmp;
v->allocated *= v->step;
}
v->data[v->len] = item;
v->len++;
return 0;
}
int delete(struct vector *v, int index)
{
if (index < 0 || index >= v->len)
return -1;
memmove(v->data + index, v->data + index + 1,
(v->len - index - 1) * sizeof(int));
v->len--;
return 0;
}
void print(const struct vector *v)
{
printf("Array:\n");
for (int i = 0; i < v->len; i++)
printf("%d ", v->data[i]);
printf("\n");
}
int main(void)
{
struct vector v;
int rc;
init_vector(&v);
rc = append(&v, 1);
assert(rc == 0);
rc = append(&v, 2);
assert(rc == 0);
rc = append(&v, 3);
assert(rc == 0);
rc = append(&v, 4);
assert(rc == 0);
rc = append(&v, 5);
assert(rc == 0);
print(&v);
rc = delete(&v, 2);
assert(rc == 0);
print(&v);
free(v.data);
return 0;
}
A rough equivalent of a C++ vector would be a resizing C array (to account for more elements than available).
Ergo, the equivalent of an array of vectors would be an array of pointers (an array of arrays wouldn't cut it because of the resizing constraint).
int* values[1000];
You'll need to account for the sizes though, so you could either do that externally or wrap the logic inside a structure.
int sizes[1000];
int noElements[1000];
// all sizes and noElements initially 0
for (int i = 0; i < 10; i++) {
if ( noElements[i] >= sizes[i] )
{
// allocate more memory for values[i];
// copy old contents into the new memory
// update sizes[i]
}
values[i][noElements] = 10;
noElements++;
}
There is no C standard equivalent to the c++ vector, though you could create a struct based off of the vector in c++. The struct would
Resize itself if the array bounds are passed the max size
perform the operations similar to that of a vector
OR
Create a linked list stack struct that simulates that of a c++ vector
I'm affraid you'll have to work with heap memory in 80's fashion in the plain C.
typedef struct tagArrayDesc {
int* arr;
size_t top;
size_t reserved;
} ArrayDesc;
#define EC(NAME, T) size_t ensure_capacity##NAME##(size_t size, \
T** vec, \
size_t reserved) \
{ \
size_t new_reserved; \
new_reserved = reserved; \
if (reserved < size) { \
if (reserved != 0) { \
new_reserved *= 2; \
} else { \
new_reserved = 0x10; \
} \
} \
if (new_reserved < size) { \
new_reserved = (size * 4) / 3; \
} \
if (new_reserved > reserved) { \
*vec = realloc(*vec, sizeof(**vec) * new_reserved); \
memset((*vec) + reserved, 0, sizeof(T) * (new_reserved - reserved)); \
} \
return new_reserved; \
}
EC(_int, int)
EC(_array_desc, ArrayDesc)
int main()
{
ArrayDesc* rows = NULL;
size_t rows_size = 0;
size_t rows_reserved = 0;
while (true) {
int i, j;
scanf("%d%d", &i, &j);
rows_reserved = ensure_capacity_array_desc(i + 1, &rows, rows_reserved);
rows[i].reserved = ensure_capacity_int(j + 1, &rows[i].arr, rows[i].reserved);
rows[i].arr[j] = 42;
}
return 0;
}
You have to work with dynamic memory allocation. It's not hard. Every time when a new item must be inserted just use realloc. Somethink that looks like this:
#include <cstdlib>
typedef struct { } UserType;
int currentSize = 0;
UserType* values;
/// Add new value to values method
void addValue(const UserType& newValue)
{
++currentSize;
values = static_cast<UserType*>(realloc(values, currentSize));
if (values == NULL)
// memory allocation filed, place fix code here
*(values + currentSize) = newValue;
}
Remember, u have to use free for free memory of the values. Also, you may don't free allocated memory if will end work right now.

C++ pointer "losing" its value

As an exercise (largely an exercise in trying to write something using pointers), I'm writing a cache simulation, specifically of the pseudo least recently used system from the old 486. I'm getting an "Access violation reading location" error on the line:
int min = treeArray[set]->root->findPLRU();
Initially the treeArray seems to be initialised properly (if I pause the program at the start and take a look, it's all as should be), but when the programme breaks and I delve in to examine things the root of the tree in question isn't defined.
I feel it's quite probable that I'm making some sort of very elementary pointer mistake, which is causing the pointer to the node to be "lost" somewhere, but I've no clue what it might be. Is there something in particular I need to do to "hold on" to a pointer value?
#include "stdafx.h"
#include "stdlib.h"
#include <conio.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <io.h>
#include "main.h"
//char fn[80]; // trace filename
int tf; // trace file
trace buf[BUFSZ / sizeof(trace)]; // buffer SIZE
int LRUHits = 0;
int pLRUHits = 0;
int randomHits = 0;
int height;
int cachelinenumber;
//log2 helper function
int log2(int n)
{
int i = 0;
while (n)
{
n = n >> 1;
i++;
}
return i - 1;
}
class CacheLine{
public:
int tag;
int access;
CacheLine();
};
class Cache;
class Node{
public:
bool goRight;
Node* left;
Node* right;
int leftCacheLine;
int rightCacheLine;
Node(int depth) // constructor
{
goRight = false;
if (depth < height - 1)
{
left = new Node(depth + 1);
right = new Node(depth + 1);
leftCacheLine = -1;
rightCacheLine = -1;
}
else
{
leftCacheLine = cachelinenumber;
cachelinenumber++;
rightCacheLine = cachelinenumber;
cachelinenumber++;
}
//printf("Depth: %d, Height: %d, Left: %d, Right: %d\n", depth, height, leftCacheLine, rightCacheLine);
}
~Node()
{
delete left;
delete right;
}
int findPLRU()
{
if (leftCacheLine < 0 || rightCacheLine < 0)
{
if (goRight)
{
goRight = false;
return right->findPLRU();
}
else
{
goRight = true;
return left->findPLRU();
}
}
else
{
if (goRight)
{
goRight = false;
return rightCacheLine;
}
else
{
goRight = true;
return leftCacheLine;
}
}
}
};
class Tree{
public:
Node* root;
Tree()
{
root = new Node(0);
}
~Tree()
{
delete root;
}
};
//cache class
class Cache
{
public:
CacheLine *cache;
int l, k, n, replacementPolicy;
int log2l, log2n;
int access;
Tree** treeArray;
//constructor
Cache(int ll, int kk, int nn, int _replacementPolicy)
{
l = ll;
k = kk;
n = nn;
replacementPolicy = _replacementPolicy;
log2l = log2(l);
log2n = log2(n);
cache = (CacheLine*)malloc(sizeof(CacheLine)*k*n);
for (int i = 0; i < k*n; i++)
{
cache[i].tag = 0x80000000;
cache[i].access = 0;
}
if (replacementPolicy == 1)
{
cachelinenumber = 0;
treeArray = new Tree*[n];
for (int i = 0; i < n; i++)
{
treeArray[i] = new Tree();
}
}
access = -1;
}
//destructor
~Cache()
{
free(cache);
}
//test for hit
void hit(int a)
{
access++;
int set = (a >> log2l) & (n - 1);
int tag = a >> (log2n + log2l);
CacheLine* c = &cache[set*k];
for (int i = 0; i < k; i++)
{
if (c[i].tag == tag)
{
c[i].access = access;
if (replacementPolicy == 0)
LRUHits++;
else if (replacementPolicy == 1)
pLRUHits++;
else if (replacementPolicy == 2)
randomHits++;
break;
}
}
if (replacementPolicy == 0) //LRU
{
int min = 0;
int minv = c[0].access;
for (int i = 1; i < k; i++)
{
if (c[i].access < minv)
{
minv = c[i].access;
min = i;
}
}
c[min].tag = tag;
c[min].access = access;
}
else if(replacementPolicy == 1) // pseudoLRU
{
int min = treeArray[set]->root->findPLRU();
c[min].tag = tag;
c[min].access = access;
}
else // random
{
srand(clock());
int randomNumber = rand()%k;
c[randomNumber].tag = tag;
c[randomNumber].access = access;
}
return;
}
};
void analyse (int l, int k, int n)
{
height = log2(k) + 1;
char fn[] = "ico0.trace";
if ((tf = open(fn, _O_RDONLY | _O_BINARY )) == -1) {
printf("unable to open file %s\n", fn);
exit(0);
}
LRUHits = 0;
pLRUHits = 0;
randomHits = 0;
Cache *cache0 = new Cache(l, k, n, 0); // LRU
Cache *cache1 = new Cache(l, k, n, 1); // pseudoLRU
Cache *cache2 = new Cache(l, k, n, 2); // random
int bytes, word0, a, type, burstcount;
int hits = 0;
int tcount = 0;
while (bytes = read(tf, buf, sizeof(buf)))
{
for (int i = 0; i < bytes / (int) sizeof(trace); i++, tcount++)
{
word0 = buf[i].word0;
a = (word0 & ADDRESSMASK) << 2;
type = (word0 >> TYPESHIFT) & TYPEMASK;
burstcount = ((word0 >> BURSTSHIFT) & BURSTMASK) + 1;
cache0->hit(a);
cache1->hit(a);
cache2->hit(a);
}
}
printf("Hits: %d Total: %d\n", LRUHits, tcount);
printf("Hits: %d Total: %d\n", pLRUHits, tcount);
printf("Hits: %d Total: %d\n\n\n", randomHits, tcount);
delete cache0;
delete cache1;
delete cache2;
}
int _tmain(int argc, _TCHAR* argv[])
{
//analyse(16, 1, 8);
analyse(16, 2, 512);
//analyse(16, 4, 256);
//analyse(16, 8, 128);
//analyse(16, 1024, 1);
_getch();
return 0;
}
Your question hasn't yet been pounced upon, probably because your code still doesn't compile since you've not provided main.h.
And even then it would annoy most folks trying to help you because you make no mention of the ico0.trace file that is required to prevent the code from immediately exiting.
You say int min = treeArray[set]->root->findPLRU(); access violates.
1) the value of set can never exceed the size n of your treeArray since you & n-1 the range of input values.
2) since your ~Tree() destructor is never called there will always be a treeArray[set]->root
3) since you *always create new left & right nodes whenever leftCacheLine = -1 or rightCacheLine = -1 it cannot be due to recursive findPLRUs
So, the pointer to the node is not being "lost" somewhere; it is being stomped on.
Try replacing:
int min = treeArray[set]->root->findPLRU();
c[min].tag = tag;
c[min].access = access;
with:
int min = treeArray[set]->root->findPLRU();
if (min >= k*n)
{
printf("ook\n");
}
else
{
c[min].tag = tag;
c[min].access = access;
}
and I think you will discover what's doing the stomping. ;)

c++ array class problems

Alright, so without going into detail on why I'm writing this class, here it is.
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
aType * Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
aType * Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
aType * Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
It is supposed to be a std::Vector type object, without all the bells and whistles.
Problem is, it doesn't seem to work.
I basically start by going
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
I get an Access Violation Reading Location error and it hits on the line
Array[_Count] = Item
in the Push_back function.
The problem seems to be that it's not treating the Array object as an array in memory.
I've spent time going through the code step by step, and I don't know what else to say, it's not operating right. I don't know how to word it right. I'm just hoping someone will read my code and point out a stupid mistake I've made, because I'm sure that's all it amounts to.
Update
So now I changed 3 initializations of Array in nArray(), nArray(int Count), and Resize(int newSize)
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
This is how my code was before. Anyway, the original problem was the fact that when I try to access a specific element in the array, it just accesses the first element, and it doesn't seem to add elements eather. It doesn't seem to be treating Array as an array.
int Resize(int newSize)
{
.
.
aType * Array = new aType[newSize*2];
At this point, instead of updating the member variable as you intended, you've actually created a local variable called Array whose value is discarded when you exit from Resize(). Change the line to
Array = new aType[newSize*2];
The same thing is happening in your constructors, they also need changing accordingly. Moreover, since the default constructor allocates an array, you should set the size members accordingly. You have too many of these: an array needs to keep track of current element count and maximum capacity, however you appear to have three members. What is the purpose of the third? Redundant information is bad, it makes code difficult to read and without a single point of truth it is easier to make mistakes.
With the code in Resize(), you can do better: the second copy is completely redundant.
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
Also, in
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
you need curly braces around body of the if(), just indentation on its own won't do the trick:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
{
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
You have a number of problems. At a guess, the one causing problems so far is that your default ctor (nArray::nArray()) defines a local variable named Array that it initializes, which leaves nArray::Array uninitialized.
Though you probably haven't seen any symptoms from it (yet), you do have at least one more problem. Names starting with an underscore followed by a capital letter (such as your _Size, _MaxSize, and _Count) are reserved for the implementation -- i.e., you're not allowed to use them.
The logic in your Resize also looks needlessly inefficient (if not outright broken), though given the time maybe it's just my brain not working quite right at this hour of the morning.
Your array is not initialized by the constructors and resize function (working on local vars instead).
And is there a reason you want to store instances of string and not pointers to string (string *) ?
I think the answer after the changes is in moonshadow's reply:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
This code will always return aType(), the last two lines will never be reached.
You might also want to check what happens if you start out with a default-constructed nArray. (Hint: you call Resize(_MaxSize); but what is the value of _MaxSize in this case?
Edit:
This outputs "asdf2" for me as it should be (with the initialization and the braces fixed):
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1) {
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
#include <string>
#include <iostream>
using namespace std;
int main()
{
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
}