Compiler Error, Linked list: error: base operand of ‘->’ has non-pointer type ‘IntNodeType’ - c++

Below I have some basic code and I am learning about linked lists. This function passes an array and created a linked list from it. However, when I try to compile it I get an error about a non-pointer type. Can anyone tell me what I am doing wrong? Thanks
struct IntNodeType {
int value;
IntNodeType * next;
IntNodeType (int v=0, IntNodeType * p=NULL):value(v),next(p)
{
}
};
IntNodeType * InitList (int a[], int size)
{
IntNodeType *p;
p = new IntNodeType[size];
int i = 0;
while ( i < size )
{
p[i]->value = a[i];
if ( i == size - 1)
{
p[i] -> next = NULL;
break;
}
else
p[i] -> next = p[i+1];
i++;
}
return p;
}

To correctly compile your code, InitList's body should be:
// ..
IntNodeType *p;
p = new IntNodeType[size];
int i = 0;
while ( i < size )
{
p[i].value = a[i]; // here
if ( i == size - 1)
{
p[i].next = nullptr; // here + nullptr
break;
}
else
p[i].next = &(p[i+1]); //here
i++;
}
return p;
Notice the usage of the period operator instead of the -> operator.
Although p is an array type (can be decayed into a pointer), its contents aren't pointers. p contains size many IntNodeTypes.
For the last noted line you need to pass it a reference to the non-pointer p[i+1]
It's also worth noting you should use nullptr over NULL.

Related

C++ memory leak, where?

I'm having a problem with the code attached below. Essentially it generates a huge memory leak but I can't see where it happens.
What the code does is receiving an array of strings, called prints, containing numbers (nodes) separated by ',' (ordered by desc number of nodes), finding other compatible prints (compatible means that the other string has no overlapping nodes 0 excluded because every print contains it) and when all nodes are covered it calculates a risk function on the basis of a weighted graph. In the end it retains the solution having the lowest risk.
The problem is that leak you see in the picture. I really can't get where it comes from.
Here's the code:
#include "Analyzer.h"
#define INFINITY 999999999
// functions prototypes
bool areFullyCompatible(int *, int, string);
bool contains(int *, int, int);
bool selectionComplete(int , int);
void extractNodes(string , int *, int &, int);
void addNodes(int *, int &, string);
Analyzer::Analyzer(Graph *graph, string *prints, int printsLen) {
this->graph = graph;
this->prints = prints;
this->printsLen = printsLen;
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
this->bestReSize = INFINITY;
this->bestRisk = INFINITY;
this-> actualSize = -1;
}
void Analyzer::getBestResult(int &size) {
for (int i = 0; i < bestReSize; i++)
cout << bestResult[i] << endl;
}
void Analyzer::analyze() {
// the number of selected paths is at most equal to the number of nodes
int maxSize = this->graph->nodesNum;
float totRisk;
int *actualNodes = new int[maxSize];
int nodesNum;
bool newCycle = true;
for (int i = 0; i < printsLen - 1; i++) {
for (int j = i + 1; j < printsLen; j++) {
// initializing the current selection
if (newCycle) {
newCycle = false;
nodesNum = 0;
extractNodes(prints[i], actualNodes, nodesNum, maxSize);
this->actualResult[0] = prints[i];
this->actualSize = 1;
}
// adding just fully compatible prints
if (areFullyCompatible(actualNodes, nodesNum, prints[j])) {
this->actualResult[actualSize] = prints[j];
actualSize++;
addNodes(actualNodes, nodesNum, prints[j]);
}
if (selectionComplete(nodesNum, maxSize)) {
// it means it's no more a possible best solution with the minimum number of paths
if (actualSize > bestReSize) {
break;
}
// calculating the risk associated to the current selection of prints
totRisk = calculateRisk();
// saving the best result
if (actualSize <= bestReSize && totRisk < bestRisk) {
bestReSize = actualSize;
bestRisk = totRisk;
for(int k=0;k<actualSize; k++)
bestResult[k] = actualResult[k];
}
}
}
newCycle = true;
}
}
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
int nodesNum = 0;
for (int i = 0; i < actualSize; i++) {
extractNodes(this->actualResult[i], nodes, nodesNum, maxSize);
// now nodes containt all the nodes from the print but 0, so I add it (it's already counted but misses)
nodes[nodesNum-1] = 0;
// at this point I use the graph to calculate the risk
for (int i = 0; i < nodesNum - 1; i++) {
float add = this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
totRisk += this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
//cout << "connecting " << nodes[i] << " to " << nodes[i + 1] << " with risk " << add << endl;
}
}
delete nodes;
return totRisk;
}
// -------------- HELP FUNCTIONS--------------
bool areFullyCompatible(int *nodes, int nodesNum, string print) {
char *node;
char *dup;
int tmp;
bool flag = false;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL && !flag)
{
tmp = atoi(node);
if (contains(nodes, nodesNum, tmp))
flag = true;
node = strtok(NULL, ",");
}
// flag signals whether an element in the print is already contained. If it is, there's no full compatibility
if (flag)
return false;
delete dup;
delete node;
return true;
}
// adds the new nodes to the list
void addNodes(int *nodes, int &nodesNum, string print) {
char *node;
char *dup;
int tmp;
// in this case I must add the new nodes to the list
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
if (tmp != 0) {
nodes[nodesNum] = tmp;
nodesNum++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
}
// verifies whether a node is already contained in the nodes list
bool contains(int *nodes, int nodesNum, int node) {
for (int i = 0; i < nodesNum; i++)
if (nodes[i] == node)
return true;
return false;
}
// verifies if there are no more nodes to be added to the list (0 excluded)
bool selectionComplete(int nodesNum, int maxSize) {
return nodesNum == (maxSize-1);
}
// extracts nodes from a print add adds them to the nodes list
void extractNodes(string print, int *nodes, int &nodesNum, int maxSize) {
char *node;
char *dup;
int idx = 0;
int tmp;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
// not adding 0 because every prints contains it
if (tmp != 0) {
nodes[idx] = tmp;
idx++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
nodesNum = idx;
}
You have forgotten to delete several things and used the wrong form of delete for arrays where you have remembered, e.g.
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
//...
delete [] nodes; //<------- DO THIS not delete nodes
The simplest solution is to avoid using raw pointers and use smart ones instead. Or a std::vector if you just want to store stuff somewhere to index into.
You have new without corresponding delete
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
These should be deleted somewhere using delete [] ...
You allocate actualNodes in analyze() but you don't release the memory anywhere:
int *actualNodes = new int[maxSize];
In Addition, Analyzer::bestResult and Analyzer::actualResult are allocated in the constructor of Analyzer but not deallocated anywhere.
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
If you must use pointers, I really suggest to use smart pointers, e.g. std::unique_ptr and/or std::shared_ptr when using C++11 or later, or a Boost equivalent when using C++03 or earlier. Otherwise, using containers, e.g. std::vector is preferred.
PS: You're code also has a lot of mismatches in terms of allocation and deallocation. If memory is allocated using alloc/calloc/strdup... it must be freed using free. If memory is allocated using operator new it must be allocated with operator delete. If memory is allocated using operator new[] it must be allocated with operator delete[]. And I guess you certainly should not delete the return value of strtok.

Pointers and pointers to reference

Having a structure
struct Person{
Person( int i):id(i){};
Person * next;
int id;
};
class Test{
public:
void addList( Person *&f , Person *&l , int i){
Person *tmp = new Person(i);
if( f == nullptr ){
f = tmp;
l = tmp;
return;
}
first -> next = tmp;
last = tmp;
}
void addArr( int *arr , int i ){
arr[index++] = i;
}
void print( ){
for( int i = 0; i < index; i ++)
cout << arr[i] << " ";
cout << endl;
}
Person *first = nullptr;
Person *last = nullptr;
int index = 0;
int *arr = new int[10];
};
function addList add node into linked list and addArr adds element into arr.
My question is about pointer and reference pointer.
in
void addList( Person *&f , Person *&l , int i){
Person *tmp = new Person(i);
if( f == nullptr ){
f = tmp;
l = tmp;
return;
}
first -> next = tmp;
last = tmp;
}
I need to pass pointer as reference. Otherwise , the local copy of pointer would be changed not outer. I assume compilator creates something like
Person *temporary = new Person(*f);
But would I not have to pass array by reference?
I am quite confused by this fact.
But would i do not have to pass array by reference?
Not in this case, by passing your Person pointer by reference in the addList function, you are able to alter the pointer itself. That is like saying, "Pointer, use a different address". This is possible, as it was passed by reference.
Whereas in your addArr function, you are not altering the pointer to the array itself. Rather, you are altering the data that is pointed to. "Pointed to data, use a different value". This data arr is pointing to is the same data outside the scope of the function.
So, no, you don't have to pass the array by reference.

passing pointer to function and using realloc

I want to pass a pointer to a function which will call a second function that will use realloc.
The issue is that realloc is returning NULL.
I don't know if the mistake is in the numbers of * in the function call or something else.
Could you please help me ?
The code:
int main(){
// some code.
clause_t* ptr; //clause_t is a structure i declared.
//Some work including the initial allocation of ptr (which is working).
assignLonely(matSAT, ic.nbClause, ic.nbVar, ptr); //the issue is here.
//Some other work
}
void assignLonely(int** matSAT, int nbClause, int nbVar, clause_t* ptr)
{
int i = 0, j = 0;
int cpt = 0;
int indice = -1;
for (i = 0; i < nbClause ; ++i)
{
j = 0;
cpt = 0;
while((j < nbVar) && (cpt < 2))
{
if (matSAT[i][j] != 0)
{
cpt++;
}
else
{
indice = j;
}
if (cpt < 2)
{
deleteClause(indice, &ptr);
}
j++;
}
}
}
void deleteClause(int indiceClause, clause_t** ptr)
{
int i = indiceClause;
int nbElt = sizeof((*ptr))/sizeof((*ptr)[0]);
int tailleElt = sizeof((*ptr)[0]);
while(i+1 < nbElt)
{
(*ptr)[i] = (*ptr)[i+1];
i++;
}
*ptr = (clause_t*)realloc(*ptr, (nbElt-1)*tailleElt);
if (*ptr == NULL)
{
fprintf(stderr, "Erreur reallocation\n");
exit(EXIT_FAILURE);
}
}
You have to declarae function assignLonely similarly to function deleteClause like
void assignLonely(int** matSAT, int nbClause, int nbVar, clause_t** ptr);
if you want that changes of ptr in the function would be stored in the original object in main.
Also take into account that this statement
int nbElt = sizeof((*ptr))/sizeof((*ptr)[0]);
is wrong.
Expression sizeof((*ptr)) will return the size of the pointer. Pointers do not keep information about how many elements in arrays they point to.
So expression
(nbElt-1)
can be equal to zero or even be negative.

A pointer to an array of pointers

I know I should know this, but it's late and my brain just won't put the pieces together.
This is as straight forward as a question can get:
I have a struct item. I want to create a pointer to an array of pointers to that item type.
Eg.
struct item {
int data;
string moreData;
};
I want to have an ArrayPointer that point's to an array. I want that array to contain in each element a pointer to an item.
How do I do this in C++, or more sepcifically where do I need to put how many dereferencing operators? I know how to declare basic (single indirection) pointers and am pretty fluent in their use.
I need information for the following steps if at all possible:
Declaring the ArrayPointer.
Initializing the ArrayPointer with a size s.
Initializing each element of ArrayPointer with new item.
eg:
for(int i = 0; i < s; i++)
ArrayPointer[i] = // a new item
I feel like as soon as someone posts an answer I'm going to facepalm so hard I break my nose.
If I have understood correctly then you need something like this
item **ArrayPointer = new item *[s];
for ( int i = 0; i < s; i++ )
{
ArrayPointer[i] = new item; { i, "More Data" };
}
Or
item **ArrayPointer = new item *[s];
for ( int i = 0; i < s; i++ )
{
ArrayPointer[i] = new item;
ArrayPointer[i]->data = i;
ArrayPointer[i]->moreData = "More Data";
}
To free the allocated memory you can in reverse order
for ( int i = 0; i < s; i++ )
{
delete ArrayPointer[i];
}
delete [] ArrayPointer;
Otherewise if s is a constant then you may simply declare an array of pointers. For example
item * ArrayPointer[s];
for ( int i = 0; i < s; i++ )
{
ArrayPointer[i]->data = i;
ArrayPointer[i]->moreData = "More Data";
}
file.h
struct item {
int data;
string moreData;
};
item ** array;
file.cpp
array = new item*[s];
for(int i = 0; i < s; i++)
{
array[i] = new item;
array[i]->data = 10;
array[i]->moreData = "data";
}
What you want is an array of struct item *, which are pointers to item structs.
An array of such pointers is a struct item **.
#include <string>
#include <cstdlib>
using namespace std;
struct item {
int data;
string moreData;
};
struct item * newItem(int data, string moreData) {
struct item *result = (struct item *) malloc(sizeof(struct item));
result->data = data;
result->moreData = moreData;
return result;
}
struct item ** array; // We don't know the size of the array in advance.
int main() {
int arraySize = 3; // We get this value from somewhere (user input?).
array = (struct item **) malloc(3*sizeof(struct item *));
// Now the array has been allocated. There is space for
// arraySize pointers.
array[0] = newItem(5, "ant"); // Let's make some items. Note that
array[1] = newItem(90, "bear"); // newItem() returns a pointer to
array[2] = newItem(25, "cat"); // an item.
return 0;
}

Array of Linked Lists C++

So I thought I understood how to implement an array of pointers but my compiler says otherwise =(. Any help would be appreciated, I feel like I'm close but am missing something crucial.
1.) I have a struct called node declared:.
struct node {
int num;
node *next;
}
2.) I've declared a pointer to an array of pointers like so:
node **arrayOfPointers;
3.) I've then dynamically created the array of pointers by doing this:
arrayOfPointers = new node*[arraySize];
My understanding is at this point, arrayOfPointers is now pointing to an array of x node type, with x being = to arraySize.
4.) But when I want to access the fifth element in arrayOfPointers to check if its next pointer is null, I'm getting a segmentation fault error. Using this:
if (arrayOfPointers[5]->next == NULL)
{
cout << "I'm null" << endl;
}
Does anyone know why this is happening? I was able to assign a value to num by doing: arrayOfPointers[5]->num = 77;
But I'm confused as to why checking the pointer in the struct is causing an error. Also, while we're at it, what would be the proper protoype for passing in arrayOfPointers into a function? Is it still (node **arrayOfPointers) or is it some other thing like (node * &arrayOfPointers)?
Thanks in advance for any tips or pointers (haha) you may have!
Full code (Updated):
/*
* Functions related to separate chain hashing
*/
struct chainNode
{
int value;
chainNode *next;
};
chainNode* CreateNewChainNode (int keyValue)
{
chainNode *newNode;
newNode = new (nothrow) chainNode;
newNode->value = keyValue;
newNode->next = NULL;
return newNode;
}
void InitDynamicArrayList (int tableSize, chainNode **chainListArray)
{
// create dynamic array of pointers
chainListArray = new (nothrow) chainNode*[tableSize];
// allocate each pointer in array
for (int i=0; i < tableSize; i++)
{
chainListArray[i]= CreateNewChainNode(0);
}
return;
}
bool SeparateChainInsert (int keyValue, int hashAddress, chainNode **chainListArray)
{
bool isInserted = false;
chainNode *newNode;
newNode = CreateNewChainNode(keyValue); // create new node
// if memory allocation did not fail, insert new node into hash table
if (newNode != NULL)
{
//if array cell at hash address is empty
if (chainListArray[hashAddress]->next == NULL)
{
// insert new node to front of list, keeping next pointer still set to NULL
chainListArray[hashAddress]->next = newNode;
}
else //else cell is pointing to a list of nodes already
{
// new node's next pointer will point to former front of linked list
newNode->next = chainListArray[hashAddress]->next;
// insert new node to front of list
chainListArray[hashAddress]->next = newNode;
}
isInserted = true;
cout << keyValue << " inserted into chainListArray at index " << hashAddress << endl;
}
return isInserted;
}
/*
* Functions to fill array with random numbers for hashing
*/
void FillNumArray (int randomArray[])
{
int i = 0; // counter for for loop
int randomNum = 0; // randomly generated number
for (i = 0; i < ARRAY_SIZE; i++) // do this for entire array
{
randomNum = GenerateRandomNum(); // get a random number
while(!IsUniqueNum(randomNum, randomArray)) // loops until random number is unique
{
randomNum = GenerateRandomNum();
}
randomArray[i] = randomNum; // insert random number into array
}
return;
}
int GenerateRandomNum ()
{
int num = 0; // randomly generated number
// generate random number between start and end ranges
num = (rand() % END_RANGE) + START_RANGE;
return num;
}
bool IsUniqueNum (int num, int randomArray[])
{
bool isUnique = true; // indicates if number is unique and NOT in array
int index = 0; // array index
//loop until end of array or a zero is found
//(since array elements were initialized to zero)
while ((index < ARRAY_SIZE) && (!randomArray[index] == 0))
{
// if a value in the array matches the num passed in, num is not unique
if (randomArray[index] == num)
{
isUnique = false;
}
index++; // increment index counter
} // end while
return isUnique;
}
/*
*main
*/
int main (int argc, char* argv[])
{
int randomNums[ARRAY_SIZE] = {0}; // initialize array elements to 0
int hashTableSize = 0; // size of hash table to use
chainNode **chainListArray;
bool chainEntry = true; //testing chain hashing
//initialize random seed
srand((unsigned)time(NULL));
FillNumArray(randomNums); // fill randomNums array with random numbers
//test print array
for(int i = 0; i < ARRAY_SIZE; i++)
{
cout << randomNums[i] << endl;
}
//test chain hashing insert
hashTableSize = 19;
int hashAddress = 0;
InitDynamicArrayList(hashTableSize, chainListArray);
//try to hash into hash table
for (int i = 0; i < ARRAY_SIZE; i++)
{
hashAddress = randomNums[i] % hashTableSize;
chainEntry = SeparateChainInsert(randomNums[i], hashAddress, chainListArray);
}
system("pause");
return 0;
}
arrayOfPointers = new node*[arraySize];
That returns a bunch of unallocated pointers. Your top level array is fine, but its elements are still uninitialized pointers, so when you do this:
->next
You invoke undefined behavior. You're dereferencing an uninitialized pointer.
You allocated the array properly, now you need to allocate each pointer, i.e.,
for(int i = 0; i < arraySize; ++i) {
arrayOfPointers[i] = new node;
}
As an aside, I realize that you're learning, but you should realize that you're essentially writing C here. In C++ you have a myriad of wonderful data structures that will handle memory allocation (and, more importantly, deallocation) for you.
Your code is good, but it's about how you declared your InitDynamicArrayList. One way is to use ***chainListArray, or the more C++-like syntax to use references like this:
void InitDynamicArrayList (int tableSize, chainNode **&chainListArray)