Passing pointers of vectors with structures C++ - c++

I've declared the following function in C++
void setCellInfo (CELL_MESH* target, int Global_ID, int node0,vector<NODE_MESH *>* NodeStore, vector<CELL_MESH *>* CellStore) {
CellStore->push_back(target); //No Errors
target->Global_ID = Global_ID; //No Errors
if (node0 != 0) {
target->node[0] = NodeStore[vector<NODE_MESH *>::size_type(node0)]->ID; //ERROR 1
target->node_pointers[0] = NodeStore[vector<NODE_MESH *>::size_type(node0)]; //ERROR 2
}
}
ERROR1: Gives me a "No member named 'ID' in 'std::vector<NODE_MESH *>'" for the target->node[] attributions although its the entities from the pointers within the vector that have this ID member. Since I'm trying to get a specific entity in the vector using NodeStore[value], I would think it would work.
ERROR2: Gives me "Assigning to 'NODE_MESH *' from incompatible type 'vector<NODE_MESH *>'" for all the target->node_pointers attributions. This seems to be the same problem but with pointers directly (without the ID member).
the NodeStore and CellStore vectors a defined as follows outside the function
vector<NODE_MESH*> NodeStore;
vector<CELL_MESH*> CellStore;
I then try to use the function like this, with 'i' being the int Global_ID and 'nodes_x*y+x' being some integer.
CELL_MESH *newCell = new CELL_MESH;
setCellInfo (&newCell, i, nodes_x*y+x, &NodeStore, &CellStore);
I've tried many different alterations to pointers but can't get it work. Would you know how to ?
Here's a simplified complete version:
#include <vector>
using namespace std;
typedef struct NODE_MESH{
int ID;
}NODE_MESH;
typedef struct CELL_MESH{
int Global_ID;
NODE_MESH* node_pointers[4];
int node[4];
}CELL_MESH;
vector<NODE_MESH*> NodeStore;
vector<CELL_MESH*> CellStore;
double nodes_y = 5;
double nodes_x = 4;
int cells_y = 4;
int cells_x = 3;
void setCellInfo (CELL_MESH* target, int Global_ID, int node0,vector<NODE_MESH *>* NodeStore, vector<CELL_MESH *>* CellStore) {
CellStore->push_back(target); //No Errors
target->Global_ID = Global_ID; //No Errors
if (node0 != 0) {
target->node[0] = NodeStore[vector<NODE_MESH *>::size_type(node0)]->ID; //ERROR 1
target->node_pointers[0] = NodeStore[vector<NODE_MESH *>::size_type(node0)]; //ERROR 2
}
}
int main() {
int i = 0;
for (double y = 0; y < nodes_y; y++) {
for (double x = 0; x < nodes_x; x++) {
NODE_MESH *newNode = new NODE_MESH;
NodeStore.push_back(newNode);
newNode -> ID = i;
i++;
}
}
i = 0;
for (int y = 0; y < cells_y; y++) { //nodes_y since horizontal faces are aligned with nodes horizontaly (same y)
for (int x = 0; x < cells_x; x++) { //x coordinate for horizontal faces is in-between nodes so 0.5 with count for faces
CELL_MESH *newCell = new CELL_MESH;
setCellInfo (newCell, i, nodes_x*y+x, &NodeStore, &CellStore);
i++;
}
}
return 0;
}

Given a variable T* t, the syntax t[x] is equivalent to *(t+x), which is the cause of this confusion. Concretely, NodeStore[vector<NODE_MESH *>::size_type(node0)] is of type vector<NODE_MESH *>& instead of an element of the NodeStore as you expected.
Change your code to take variables by reference instead:
void setCellInfo (CELL_MESH* target, int Global_ID, int node0,vector<NODE_MESH *>& NodeStore, vector<CELL_MESH *>& CellStore) {
CellStore->push_back(target); //No Errors
target->Global_ID = Global_ID; //No Errors
if (node0 != 0) {
target->node[0] = NodeStore[node0]->ID;
target->node_pointers[0] = NodeStore[node0];
}
}
The call is then simply
setCellInfo (&newCell, i, nodes_x*y+x, NodeStore, CellStore);
Alternatively, you will need to dereference the pointer before indexing:
(*NodeStore)[node0]->ID

Final Solution:
void setCellInfo (CELL_MESH* target, int Global_ID, int node0,vector<NODE_MESH *>& NodeStore, vector<CELL_MESH *>& CellStore) {
CellStore.push_back(target);
target->Global_ID = Global_ID;
if (node0 != 0) {
target->node[0] = NodeStore[node0]->ID;
target->node_pointers[0] = NodeStore[node0];
}
}
With this when using it:
CELL_MESH *newCell = new CELL_MESH;
setCellInfo (newCell, i, nodes_x*y+x, NodeStore, CellStore);

Related

C++ exception thrown

I am learning C++ and have lost quite some time trying to solve to understand the reason of the error i am getting.
When i run the code below i am getting an Exception thrown. It happens when the program ends, so i believe it's related to the Edge pointer:
#include <iostream>
#include <vector>
#include <map>
using namespace std;
struct Edge {
int src, dest;
};
class Graph {
public:
int V, E;
Edge *edge = new Edge[E * sizeof(Edge)];
Graph(int Ver, int Edg);
};
Graph::Graph(int Ver, int Edg) {
V = Ver;
E = Edg;
}
Graph* createGraph(int V, int E) {
Graph* graph = new Graph(V,E);
return graph;
}
int find(int* parents, int val) {
if (parents[val] == -1)
return val;
return find(parents, parents[val]);
}
void Union(int *parents, int x, int y) {
parents[x] = y;
}
int isCycle(Graph* graph) {
int* parents = new int[graph->V * sizeof(int)];
memset(parents, -1, graph->V * sizeof(int));
for (int i = 0; i < graph->E; i++) {
int x = find(parents, graph->edge[i].src);
int y = find(parents, graph->edge[i].dest);
if (x == y) {
return 1;
};
Union(parents, x, y);
}
return 0;
}
int main()
{
int V = 9, E = 8;
Graph* graph = createGraph(V, E);
graph->edge[0].src = 0;
graph->edge[0].dest = 1;
graph->edge[6].src = 0;
graph->edge[6].dest = 6;
graph->edge[5].src = 0;
graph->edge[5].dest = 7;
graph->edge[1].src = 1;
graph->edge[1].dest = 2;
graph->edge[2].src = 3;
graph->edge[2].dest = 2;
graph->edge[3].src = 4;
graph->edge[3].dest = 3;
graph->edge[4].src = 4;
graph->edge[4].dest = 5;
graph->edge[7].src = 5;
graph->edge[7].dest = 7;
if (isCycle(graph))
cout << "graph contains cycle";
else
cout << "graph doesn't contain cycle";
return 0;
}
I started learning C++ only few months ago, can somebody help me to understand why I am getting that exception?
Edge *edge = new Edge[E * sizeof(Edge)];
Unless E is initialized, this multiplies an uninitalized variable by sizeof(Edge) (which is also wrong on its face value as well, but we'll get to it later). This is undefined behavior.
Graph::Graph(int Ver, int Edg) {
V = Ver;
E = Edg;
}
This isn't good enough. The default values of class members, if specified, are used to initialize them before the constructor's body starts running.
The proper way to do this is to use the constructor's initialization section:
Graph::Graph(int Ver, int Edg) : V{Ver}, E{Ver}
{
}
This initializes V and E first, so now:
Edge *edge = new Edge[E * sizeof(Edge)];
So here, E is now initialized, fixing this problem. But this is still slightly incorrect. It's clear, based on the rest of the code, that this should really be:
Edge *edge = new Edge[E];
In C++, when you wish to declare an array of, say, 4 integers, all you have to do is declare:
int n[4];
The compiler takes care of multiplying 4 by however many bytes it takes to hold an int. The same thing is true for the new statement. If your goal is to construct an array of #E Edges, that would be, unsurprisingly: new Edge[E]. This same mistake occurs several times in the shown code.

Initialize and declare dynamically multiple variables of random entities in a loop in C++

This is my code:
#include <cstdlib>
#include <ctime>
#include <stdio.h>
#include <vector>
#define ENTITY(A) entity##A
#define ALM(A) alm##A
struct TEntity{
private:
int sumx;
int sumy;
const char * rep;
int m_ix;
int m_iy;
public:
TEntity(int x, int y, int sum_x, int sum_y, const char * txt);
};
TEntity::TEntity(int x, int y, int sum_x, int sum_y, const char * txt) {
m_ix = x;
m_iy = y;
sumx = sum_x;
sumy = sum_y;
rep = txt;
}
class IAlmacenable {
private:
void * element;
public:
IAlmacenable(void * e);
IAlmacenable();
void * getValue();
};
IAlmacenable::IAlmacenable(void *e) {
element = e;
}
IAlmacenable::IAlmacenable() {
element = nullptr;
}
void * IAlmacenable::getValue() {
return element;
}
class TList {
private:
std::vector<IAlmacenable*> elementos;
int position;
public:
TList();
int Size();
int Push(IAlmacenable* psz);
};
TList::TList() {
elementos = std::vector<IAlmacenable*>();
position = 0;
}
int TList::Size() {
return elementos.size();
}
int TList::Push(IAlmacenable* psz) {
int res = 0;
if (elementos.size() >= elementos.max_size()) {
res = -1;
}
else {
elementos.push_back(psz);
}
return res;
}
int main(){
srand(time(NULL));
TList *list = new TList();
//we can put entities in the list and the rest will be filled up to 5
int size = list->Size();
for(int i = size; i<5;i++){
const char c[] = {(rand() % 2 ? 65 + rand() % 25 : 97 + rand() % 25), '\0'};
TEntity ENTITY(i)(rand() % 10, rand() % 10, rand() % 5, rand() % 5, c);
IAlmacenable ALM(i)(&ENTITY(i));
list->Push(&ALM(i));
size++;
}
//do things like printing their value...
delete list;
return 0;
}
I need to create a new variable everytime it run the "TEntity ENTITY(i)" line,
the problem is that it creates the same variable always, I think it is because it creates the variable entityi and therefore it is overwriting on the same variable, besides it seems that the random it generates is always the same number since all entities have the same values ​​in all its parameters. The c variable create a const char * random variable between a-z, A-Z , I don't put the print code because it is unnecessary, so what can I do? Is there any way to dynamically create variables of entities whose values ​​are random?
EDIT
Here is the new code fixed (the macros have been eliminated since they were not necessary and the necessary code has been included to be able to execute it) but there is still the same problem that they are generated with the same parameters (since they are still the same variable):
#include <cstdlib>
#include <ctime>
#include <stdio.h>
#include <vector>
#include <conio.h>
#include <windows.h>
struct TEntity{
private:
int sumx;
int sumy;
const char * rep;
int m_ix;
int m_iy;
public:
TEntity(int x, int y, int sum_x, int sum_y, const char * txt);
void movimiento();
void pinta();
};
TEntity::TEntity(int x, int y, int sum_x, int sum_y, const char * txt) {
m_ix = x;
m_iy = y;
sumx = sum_x;
sumy = sum_y;
rep = txt;
}
void TEntity::movimiento() {
m_ix += sumx;
m_iy += sumy;
}
void TEntity::pinta() {
gotoxy(static_cast<short int>(m_ix), static_cast<short int>(m_iy));
printf("%s", rep);
}
void gotoxy(short int x, short int y)
{
COORD pos = {x, y};
HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(output, pos);
}
void clear()
{
system("cls");
}
class IAlmacenable {
private:
void * element;
public:
IAlmacenable(void * e);
IAlmacenable();
void * getValue();
};
IAlmacenable::IAlmacenable(void *e) {
element = e;
}
IAlmacenable::IAlmacenable() {
element = nullptr;
}
void * IAlmacenable::getValue() {
return element;
}
class TList {
private:
std::vector<IAlmacenable*> elementos;
int position;
public:
TList();
int Size();
int Push(IAlmacenable* psz);
IAlmacenable* First();
IAlmacenable* Next();
};
TList::TList() {
elementos = std::vector<IAlmacenable*>();
position = 0;
}
int TList::Size() {
return elementos.size();
}
int TList::Push(IAlmacenable* psz) {
int res = 0;
if (elementos.size() >= elementos.max_size()) {
res = -1;
}
else {
elementos.push_back(psz);
}
return res;
}
IAlmacenable* TList::First() {
IAlmacenable* res;
if (elementos.empty()) {
res = nullptr;
}
else {
res = elementos.front();
position = 1;
}
return res;
}
IAlmacenable* TList::Next() {
IAlmacenable* res;
if (elementos.empty()) {
res = nullptr;
}
else {
int pos = position;
int size = elementos.size();
if (pos < size) {
res = elementos.at(position);
position++;
}
else {
res = this->First();
}
}
return res;
}
int main(){
srand(time(NULL));
TList *list = new TList();
//we can put entities in the list and the rest will be filled up to 5
int size = list->Size();
for(int i = size; i<5;i++){
const char c[] = {(rand() % 2 ? 65 + rand() % 25 : 97 + rand() % 25), '\0'};
TEntity *entity = new TEntity(rand() % 10, rand() % 10, rand() % 5, rand() % 5, c);
IAlmacenable *alm = new IAlmacenable(entity);
list->Push(alm);
size++;
}
while(true){
clear();
for (int i = 0; i < size; i++) {
reinterpret_cast<TEntity *>(list->Next()->getValue())->pinta();
reinterpret_cast<TEntity *>(list->Next()->getValue())->movimiento();
}
Sleep(2000);
}
delete list;
return 0;
}
There is some confusion here.
Some points:
The macro is not fit-for-purpose, as you already know; you're just creating a variable name entityi each time;
That doesn't matter! The object only exists for the duration of the loop iteration anyway; C++ doesn't let you create multiple objects with the same name at the same time. In fact you can get rid of the entire macro stuff and just call the object entity;
Now that that's out of the way, you're getting repeated results because you're storing a pointer to each iteration of that local variable — on each occasion, that's a dangling pointer to an object that's been destroyed. Don't store dangling pointers!
You can either:
Dynamically allocate the objects that you're adding to the list, or
Store actual objects rather than pointers-to-objects.
Either way, the local-scope name is irrelevant and certainly need not change repeatedly for each loop iteration.

Passing an integer pointer to a constructor and getting runtime memory error

I'm trying to create a vector of a class-name vertex. The value of "n" is not known at compile-time so I'll be using new to create to create the "path" array. But the problem occurs when I create the input array in a function and push it in the vector.
int n;
class vertex {
public:
int *path;
int visited = 0;
vertex(int *y) {
path = new int(n);
for (int i = 0; i < n; i++)
path[i] = y[i];
}
};
void inp(vector<vertex> graph) {
int t1[] = { 0,1,0,0 };
int t2[] = { 0,0,1,0 };
int t3[] = { 0,0,0,1 };
int t4[] = { 0,0,0,0 };
graph.push_back(vertex(t1));
graph.push_back(vertex(t2));
graph.push_back(vertex(t3));
graph.push_back(vertex(t4));
}
int main() {
n=4;
vector<vertex> graph;
inp(graph);
_getch();
}
For simplicity I've created t1 to t4 as static arrays. But still it shows some error at runtime
1:try use: path = new int [n], rather than path = new int(n);
2:if you want to push elements to graph, you should change your function inp to void inp(vector<vertex>& graph)

C/C++, troubles with pointers and functions

I have a little question about understand how pointers and functions work.
I want to see how a function looks like qsort(), but I need to use my own function to swap elements and to compare elements. I am very surprised to know that my function does not swap data...
My code:
//prototypes file: other.h
void Sort(char* pcFirst, int nNumber, int size, void (*Swap)(void*, void*), int (*Compare)(void*, void*) ); //sorts any arrays
void SwapInt(void* p1, void* p2); // swap pointers
int CmpInt(void* p1, void* p2); // compare poineters
//realisation file: other.cpp
#include "other.h"
void Sort(char* pcFirst, int nNumber, int size,
void (*Swap)(void*, void*), int (*Compare)(void*, void*) )
{
int i;
for( i = 1; i < nNumber; i++)
for(int j = nNumber - 1; j >= i; j--)
{
char* pCurrent = pcFirst + j * size;
char* pPrevious = pcFirst + (j - 1) * size;
if( (*Compare)( pPrevious, pCurrent ) > 0 )// if > 0 then Swap
{
(*Swap)( pPrevious, pCurrent );
}
}
}
void SwapInt(void* p1, void* p2)
{
int * ptmp1 = static_cast<int*>(p1);
int * ptmp2 = static_cast<int*>(p2);
int * ptmp = ptmp1;
ptmp1 = ptmp2;
ptmp2 = ptmp;
}
int CmpInt(void* p1, void* p2)
{
int nResult;
int * ptmp1 = static_cast<int*>(p1);
int * ptmp2 = static_cast<int*>(p2);
nResult = (*ptmp1 - *ptmp2);
return nResult;
}
//main file: lab.cpp
#include <tchar.h>
#include <iostream>
#include <cstdio>
#include <cmath>
#include "other.h"
int _tmain()
{
int nAr[] = {33,44,55,22,11}; //array for sort
int nTotal = sizeof(nAr) / sizeof(int); //number of elements
for ( int i = 0; i < nTotal; i++)
{
printf("%d ",nAr[i]); // result of cycle is 33 44 55 22 11
}
Sort(reinterpret_cast<char*>(&nAr[0]), nTotal, sizeof(int), SwapInt, CmpInt);
for ( int i = 0; i < nTotal; i++)
{
printf("%d ",nAr[i]); // result of cycle is 33 44 55 22 11 too =(
}
}
Why does the array not change?
In the debugger I can see that all pointers change, and get correct values, but in main my array is not changed.
pointers point to objects
the code
int * ptmp = ptmp1;
ptmp1 = ptmp2;
ptmp2 = ptmp;
changes some pointer values locally in the function, and that's all.
in order to swap the values of two objects, pass them by reference:
void swap_values_of( int& a, int& b )
{
int const original_a = a;
a = b;
b = original_a;
}
you can also do that, less safely, with pointer arguments, then taking care to swap the values pointed to instead of the pointers themselves.
but except for purposes of learning, use std::swap instead
not asked for, but... if you change the current Microsoft-specific
int _tmain()
to just standard
int main()
then the code will (much more likely) work also in e.g. Linux.
just a tip
You may look at various combinations as these.....
#include<iostream>
#include<stdio.h>
#include<malloc.h>
//Call by Address
void SwapIntAddr(int* ptmp1, int* ptmp2)
{
int ptmp;
ptmp = *ptmp1;
*ptmp1 = *ptmp2;
*ptmp2 = ptmp;
}
//Call by Reference
void SwapIntRef(int& ptmp1, int& ptmp2)
{
int ptmp;
ptmp = ptmp1;
ptmp1 = ptmp2;
ptmp2 = ptmp;
}
//Call by Reference but in pointer level
void SwapPtrRef(int*& ptmp1, int*& ptmp2)
{
int* ptmp;
ptmp = ptmp1;
ptmp1 = ptmp2;
ptmp2 = ptmp;
}
//Call by Address but in Pointer level.
void SwapPtrAddr(int** ptmp1,int** ptmp2)
{
int** ptmp = (int**) malloc(sizeof(int*));
*ptmp = *ptmp1;
*ptmp1 = *ptmp2;
*ptmp2 = *ptmp;
}
int main(){
int a = 3, b= 5;
int* p1 = &a;
int* p2 = &b;
SwapIntAddr(p1,p2);
printf("%d %d\n",*p1,*p2);
SwapIntRef(*p1,*p2);
printf("%d %d\n",*p1,*p2);
SwapPtrRef(p1,p2);
printf("%d %d\n",*p1,*p2);
SwapPtrAddr(&p1,&p2);
printf("%d %d\n",*p1,*p2);
return 0;
}
Your SwapInt function swaps some pointers, not ints. Since all those pointers are local to SwapInt, it has no actual effect. Probably you meant to do something with the ints *ptmp1 and *ptmp2.
What you are actually doing is swapping pointers. What you are trying to do is to swap values, where that pointers point to. At least that comes from your program logic.
So your code could be something like this:
void SwapInt(void* p1, void* p2)
{
int * ptmp1 = static_cast<int*>(p1);
int * ptmp2 = static_cast<int*>(p2);
int ptmp = *ptmp1;
*ptmp1 = *ptmp2;
*ptmp2 = ptmp;
}

Getting Unresolved External error

I have made a class and it compiles with no syntax errors, but I get 6 unresolved external symbols?
THE CLASS:
struct CELL {
private:
static bool haslife;
static int x;
static int y;
public:
static bool has_life()
{
return haslife;
}
static void set_coords(int xcoord, int ycoord)
{
x = xcoord;
y = ycoord;
}
static void get_coords(int &xcoord, int &ycoord)
{
xcoord = x;
ycoord = y;
}
};
class cell_grid {
private:
static int cell_size;
static int cell_count_x;
static int cell_count_y;
CELL **cell;
public:
cell_grid();
cell_grid(unsigned int width,unsigned int height, unsigned int cellsize)
{
//set size based on cellsize
this->cell_size = cellsize;
this->cell_count_x = floor((double)width / this->cell_size);
this->cell_count_y = floor((double)height / this->cell_size);
this->cell = new CELL*[this->cell_count_y];
for(int i = 0; i < this->cell_count_y; i++)
{
cell[i] = new CELL[this->cell_count_x];
}
for(int y = 0; y < this->cell_count_y; ++y)
{
for(int x = 0; x < this->cell_count_x; ++x)
{
int cur_x = x * this->cell_size;
int cur_y = y * this->cell_size;
this->cell[x][y].set_coords(cur_x,cur_y);
}
}
} //end of constructor
static int get_cell_size()
{
return cell_size;
}
static void render(BITMAP *buff)
{
circlefill(buff,70,70,60,makecol(27,37,0));
}
};
MAIN
int main()
{
start_allegro();
cell_grid *grid = new cell_grid(scr_w,scr_h,10);
grid->render(buffer);
//Main Loop
while (!done && !key[KEY_ESC]) //until 'X' pressed or ESC
{
//***** Start Main Code Here *****
while (speed_counter > 0)
{
//render the buffer to the screen
blit(
buffer,
screen,
0,0,0,0,
scr_w,
scr_h);
clear_bitmap(buffer);
speed_counter --;
}
//***** End Main Code Here *****
rest(1); //Normalize cpu usage
}
return 0;
}
END_OF_MAIN()
Thanks
Don't define all of the class variables as static.
When you define a data member as static it means there is only one single instance of it. This doesn't seem to be what you want to do here.
Instead of
private:
static bool haslife;
static int x;
static int y;
write:
private:
bool haslife;
int x;
int y;
Further more, when you define a static member, you need to define it again in the CPP file and initialize it with a value. It doesn't look like you're doing that and that's why you're getting the linker errors.
Also, next time you post something, make sure you actually ask a question rather than just simply stating facts.