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.
Related
I've been writing an VM/Interpreter combination thingy, I don't know how to exactly describe it.
Everything behaved as it should, now before I have hundreds of lines of code, I wanted to go into Garba Collection, because there were some pointers which somehow got lost, in some way. Not that I didn't delete pointers, I created, but they somehow got lost in the proccess of interpreting/running the code.
So, I wanted to track them. I wrote my own "Memory Manager" in some way, it's just a std::vector, where I collect all pointers in.
To track and allocate pointers, I have following code:
struct MemBlock {
bool free;
void* ptr;
size_t size;
};
std::vector<MemBlock*> mem;
size_t max_size;
size_t mem_size;
int count = 0;
void mem_init(size_t maxSize) {
max_size = size/sizeof(MemBlock*);
}
void* mem_alloc(size_t size) {
for (int i = 0; i < count; i++) {
MemBlock* block = mem[i];
if (block->free) {
mem_size -= block->size;
mem_size += size;
block->free = false;
block->ptr = malloc(size);
block->size = size;
if (block->ptr == nullptr) {
throw std::exception();
}
return block->ptr;
}
}
void* ptr = malloc(sizeof(size));
if (ptr == nullptr) {
throw PointerNullException();
}
MemBlock* block = (MemBlock*) malloc(sizeof(MemBlock));
*block = (MemBlock) {
false,
ptr,
size
};
mem_size += size;
count++;
mem.push_back(block);
return block->ptr;
}
But as soon, as I use mem_alloc() and initialize the object inside of the pointer:
Int* i = (Int*) mem_alloc(sizeof(Int));
*i = (Int) {}; // -- Here
i->value = atoi(advance().c_str());
The GCC AdressSanitizer shows following error:
==5939==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000098 at pc 0x555963d82fc5 bp 0x7fff4ec39070 sp 0x7fff4ec39060
WRITE of size 4 at 0x602000000098 thread T0
If I remove said line, then it just occurs on the nex line. The the pointer does point to a valid memory location, if not it should've had thrown an exception.
I'm sure that I missed something/did something wrong, of course.
But I don't know what. This is how I learned it, or at least what I understood...
Edit:
This would be a minimal reproducible Example:
#include <iostream>
#include <stdlib.h>
#include <vector>
struct Object {
const char* type;
};
template <typename T>
struct Primitive : Object {
T value;
};
struct Int : Primitive<int> {
const char* type = "int";
};
struct MemBlock {
bool free;
void* ptr;
size_t size;
};
std::vector<MemBlock*> mem;
size_t mem_size = 0;
int count = 0;
void* mem_alloc(size_t size) {
for (int i = 0; i < count; i++) {
MemBlock* block = mem[i];
if (block->free) {
mem_size -= block->size;
mem_size += size;
block->free = false;
block->ptr = malloc(size);
block->size = size;
if (block->ptr == nullptr) {
throw std::exception();
}
return block->ptr;
}
}
void* ptr = malloc(sizeof(size));
MemBlock* block = (MemBlock*) malloc(sizeof(MemBlock));
*block = (MemBlock) {
false,
ptr,
size
};
mem_size += size;
count++;
mem.push_back(block);
std::cout << "HI" << std::endl;
return block->ptr;
}
void mem_free(void* ptr) {
for (int i = 0; i < count; i++) {
MemBlock* block = mem[i];
if (block->ptr == ptr) {
free(ptr);
mem_size -= block->size;
block->size = 0;
block->ptr = nullptr;
block->free = true;
}
}
}
int main() {
// Create new Integer-Object
Int* i = (Int*) mem_alloc(sizeof(Int));
std::cout << "[Pointer]: " << i << std::endl;
*i = (Int) {};
i->value = 5;
std::cout << "[Value]: " << i->value << std::endl;
}
Well, thanks to Retired Ninja and Richar Critten, I've got the solution.
In mem_alloc() I've used sizeof(size) to allocate memory to the pointer, which of course is wrong. I guess my head was pretty much off after hours of coding.
But I guess this problem is now solved.
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;
}
I am trying to come up with a generic buffer (or heap container - not sure how to call it) for generic objects. So I could have a large number of them in contiguous memory.
The header I did works, but I was wondering if you guys could help me understand what am I doing wrong if anything, or any gotchas/bugs I am missing here. Or any other re-factoring I could do to make it better.
buffer.h
#ifndef _ENGINE_BUFFER
#define _ENGINE_BUFFER
#include <cstdlib>
#include <cstdio>
#include <typeinfo>
#include <cstring>
// Defining buffer struct:
template <typename T>
struct Buffer {
unsigned int _size;
unsigned int _number_of_objects;
unsigned int _head;
unsigned int _next;
unsigned int * _backlog;
int _backlog_head;
T* _buffer_address;
};
// Creating buffer:
template <typename T>
Buffer<T>* createBuffer(int size) {
Buffer<T>* _buffer = (Buffer<Sprite>*) calloc(1, sizeof(Buffer<T>));
if (_buffer) {
*(_buffer) = Buffer<T>();
_buffer->_size = size;
_buffer->_number_of_objects = 0;
_buffer->_head = 0;
_buffer->_next = 0;
_buffer->_backlog = (unsigned int*) calloc(size, sizeof(int));
_buffer->_backlog_head = -1;
_buffer->_buffer_address = (T*) calloc(size, sizeof(T));
if(_buffer->_buffer_address) {
return _buffer;
}
}
return (Buffer<T>*) nullptr;
}
// Adding object to buffer:
template <typename T>
int addObjectToBuffer(Buffer<T>* _buffer, const T &_obj) {
int _head = 0;
if (_buffer->_backlog_head > -1) {
_buffer->_buffer_address[_buffer->_backlog[_buffer->_backlog_head]] = _obj;
_head = _buffer->_backlog_head;
_buffer->_backlog_head--;
_buffer->_number_of_objects++;
} else {
if ( (int) (_buffer->_number_of_objects + 1) >= _buffer->_size){
T* _new_address = (T*) calloc((_buffer->_number_of_objects + 1) * 2, sizeof(T));
memcpy(_new_address, _buffer->_buffer_address, _buffer->_number_of_objects * sizeof(T));
free(_buffer->_buffer_address);
_buffer->_buffer_address = _new_address;
_buffer->_size = (_buffer->_number_of_objects + 1) * 2;
for (int i = _buffer->_head; i < _buffer->_size; i++){
_buffer->_buffer_address[i] = 0;
}
}
_buffer->_buffer_address[_buffer->_head] = _obj;
_buffer->_number_of_objects++;
_head = _buffer->_head;
_buffer->_head++;
}
return _head;
}
// Getting number of objects in buffer:
template <typename T>
unsigned int bufferGetSize(Buffer<T>* _buffer) {
return (int) _buffer->_number_of_objects;
}
// Getting next object in buffer:
template <typename T>
T* bufferGetNext(Buffer<T>* _buffer) {
if (_buffer->_backlog_head > -1){
for (int i = 0; i <= _buffer->_backlog_head; i++ ) {
if (_buffer->_backlog[i] == _buffer->_next) _buffer->_next++;;
}
}
unsigned int _next = _buffer->_next;
if (_next < _buffer->_head) {
_buffer->_next++;
return &_buffer->_buffer_address[_next];
} else {
_buffer->_next = 0;
bufferGetNext(_buffer);
}
}
// Reset iterator head:
template <typename T>
void bufferResetHead(Buffer<T>* _buffer){
_buffer->_next = 0;
}
// Deleting object from buffer:
template <typename T>
void deleteObjectFromBuffer(Buffer<T>* _buffer, unsigned int _obj_index) {
if (_obj_index >= 0 && _obj_index <= _buffer->_head) {
bool _obj_exists = false;
for (int i = _buffer->_backlog_head; i >= 0; i-- ) {
if (_buffer->_backlog[i] == _obj_index){
_obj_exists = true;
fprintf(stderr, "\n[ Warning: object_deleted_twice | buffer: %#010x | object: %#010x | index: \"%d\" ]\n",
_buffer, &_buffer->_buffer_address[_obj_index], _obj_index);
}
}
if (!_obj_exists) {
_buffer->_backlog_head++;
_buffer->_backlog[_buffer->_backlog_head] = _obj_index;
_buffer->_number_of_objects--;
}
} else {
fprintf(stderr, "\n[ Warning: index_out_of_range | buffer: %#010x | index: \"%d\" ]\n",
_buffer, _obj_index);
}
}
// Deleting buffer:
template <typename T>
void deleteBuffer(Buffer<T>* _buffer) {
free(_buffer->_buffer_address);
free(_buffer);
}
// Print buffer memory:
template <typename T>
void printBufferMemory(Buffer<T>* _buffer, unsigned int _number_of_columns, bool _print_address) {
int _column_count = 0;
printf("\n");
printf("[ Number of objects in buffer: %#02d | Actual buffer size: %#02d ]\n", _buffer->_number_of_objects, _buffer->_size);
for (int i = 1; i < 11 * _number_of_columns; i++) {
printf("=");
}
printf("\n");
for (int i = 0; i < _buffer->_size; i++) {
if (_column_count > _number_of_columns - 1) {
printf("\n");
_column_count = 0;
}
if (_print_address) {
printf("%#010x ", &_buffer->_buffer_address[i]);
} else {
printf("%#010d ", *(&_buffer->_buffer_address[i]));
}
_column_count++;
}
printf("\n");
for (int i = 1; i < 11 * _number_of_columns; i++) {
printf("=");
}
printf("\n");
}
#endif // _ENGINE_BUFFER
sprite.h
#ifndef _SPRITE
#define _SPRITE
struct Sprite {
int value = 0;
Sprite(int n){
value = n;
}
};
#endif // _SPRITE
main.cpp
#include <cstdio>
#include <cstdlib>
#include "sprite.h"
#include "buffer.h"
using namespace std;
int main()
{
int buffer_size = 512;
int object_number = 512;
Buffer<Sprite>* engine_buffer = createBuffer<Sprite>(buffer_size);
for (int i = 0; i < object_number; i++) {
addObjectToBuffer(engine_buffer, Sprite(i + 100));
}
for (int i = 0; i < bufferGetSize(engine_buffer); i++) {
printf("Value of Sprite %d is: %d\n", i + 1, bufferGetNext(engine_buffer)->value);
}
printBufferMemory(engine_buffer, 10, false);
deleteBuffer(engine_buffer);
return(0);
}
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. ;)
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);
}