Pointer Arithmetic with a pointer to a class array - c++

I'm having issues with this code for a bag ADT. I'm using a a pointer array made of a separate class that stores a string and an int.
ArrayBag::ArrayBag(int length){
list = new ReceiptArray [length];
size = length;
n= 0;
}
int ArrayBag::getCurrentSize(){return n;};
bool ArrayBag::isEmpty() {
if (!(n==0)){
return 1;
cout << "has items"<< endl;
}
else{
cout << "empty" << endl;
return 0;
}
}
bool ArrayBag::add(string item){
if (!(n==size)){
(*list+n.item) = item;
(*list+n.itemnum) = n+1;
it is the pointer arithmetic lines above that are proving difficult
n++;
return 1;
}
else{
cout << "bag full" << endl;
return 0;}
}
bool ArrayBag::remove(string item){
for(int k=0;k<n;k++){
Here too
if ((*list+k.item) == item){
(*list+k.item) = (*list+n.item);
n--;
return true;
}
}
return false;
}
void ArrayBag::clear(){n=0;}
int ArrayBag::getFrequencyOf(string item){
int frequency = 0;
for(int k=0;k<n;k++){
if(*list+k.item == item){
++frequency;}
}
return frequency;
}
bool ArrayBag::contains(string item){
for(int k=0;k<n;k++){
if(*list+k.item == item){
return 1;
}
}
return 0;
}
The errors
error: request for member ‘item’ in ‘((ArrayBag*)this)->ArrayBag::n’, which is of non-class type ‘int’
(*list+n.item) = item;
I'm confused on why this is happening. I thought you could index the pointer array this way. It happens anywhere where I try to add the current size of the array to properly index the array and access the arrays member variables.
Any advice is welcome

You have: (*list+n.item) where list is a pointer to a ReceiptArray (you should probably rename the class from ReceiptArray to Receipt but that's not your issue.)
You have two issues:
1) An order of operation issue. First *list is evaluated which returns an object of type ReceiptArray. But you need to increment your pointer before you dereference it.
2) Next you try to add n.item to this object. But n is an int and doesn't have an item member. Hence the error.
You want: (*(list+n)).item = item;
Or: (list+n)->item = item
Or simply: list[n] = item;

Related

Member variable resetting back to 0

When running through the test the count variable from the class stack1 gets reset back to 0 when using its pop function. Strangely however, during the push loop, the count increases as intended but when pop occurs, the count gets reset back to 0 and subtracts into the negatives from there. Is there something I'm forgetting?
#include <iostream>
using namespace std;
class TheStack
{
public:
TheStack();
void push(int);
int pop();
bool isEmpty();
private:
const int MaxSize = 10;
int arr[10];
int count;
};
TheStack::TheStack()
{
count = 0;
}
void TheStack::push(int userInput)
{
if (count >= MaxSize)
{
cout << "Stack is full." << endl;
}
else
{
arr[count] = userInput;
count+=1;
}
}
int TheStack::pop()
{
if (isEmpty())
{
cout << "Stack is empty." << endl;
}
else
{
int temp = arr[count];
arr[count] = NULL;
count-=1;
return temp;
}
}
bool TheStack::isEmpty()
{
if (count == 0)
{
return true;
}
else
{
return false;
}
}
int main()
{
TheStack stack1;
if (stack1.isEmpty())
{
cout << "isEmpty() works" << endl;
}
stack1.pop();
for (int i = 0; i < 10; i++)
{
stack1.push(i);
}
stack1.push(0);
stack1.pop();
stack1.pop();
stack1.pop();
stack1.pop();
system("pause");
}
When you do push you first save the data into the array and then increment count. This means that in order to properly do pop you need to work in reverse: first decrement count and only then read data from the array.
But in the code you are doing it backwards. When the stack is full, count is at max value (10 in your case), and your arr[count] = NULL; writes beyond the array boundary. This causes undefined behavior and, in particular, destroys your count value. (This is why it suddenly becomes 0.)
Also:
arr[count] = NULL; makes no sense. NULL is supposed to be used in pointer contexts, not in integer contexts. This is not even guaranteed to compile.
What is the point of that anyway? Initially your array contains garbage above the current top of the stack. Why do you suddenly care to clean it up after doing pop?
Not all control paths of pop() return value. This is undefined behavior in itself.
const int MaxSize = 10; in the class definition is a C++11 feature. Since you are already using C++11, you can do the same for count. Just do int count = 0; right inside the class definition and you will not have to write the constructor explicitly.
Although in your implementation MaxSize would make more sense as a static const class member. In that case you'll also be able to declare your array as int arr[MaxSize];.
You must first decrease count and then access arr[count] in int TheStack::pop(). Now you get access above the last pushed element, event out of bound of array if the stack is full.

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.

Messy and wrong char visualization (after passing actual parameters) C++

this is my first post. Below the code of my implementation of a char Stack. Theoretically It should print f,g,h. But when I execute it, I can just see a long list of strange signs in the console. Is a compiler issue or code issue? Thanks.
#include <iostream>
using namespace std;
const int max_L = 10;
class Stack {
protected:
char array[];
int length;
public:
Stack(){length = 0;}
bool push(char c) {
if(length < max_L){
array[length] = c;
length++;
return(true);
}
else return(false);
}
void pop(){
if(length >= 1){
cout << array[length];
length--;
} else return ;
}
bool is_empty(){
return(length == 0);
}
void print(){
for(int i = 0; i < length; i++){
cout << array[i];
}
}
};
int main() {
Stack p1;
p1.push('f');
p1.push('g');
p1.push('h');`
p1.print();
return 0;
}
There are two problems in the code. As πάντα ῥεῖ said, the array has to be created with a size. The other problem is that push and pop aren't quite complementary. push puts the added value at array[length], then increments length. So after a call to push, length is the index of the next entry, i.e., the one that hasn't been put in yet. pop has to look at the previous entry, i.e., the one that was just put in. So the code for pop should decrement length before looking at array[length]. Change
cout << array[length];
length--;
to
length--;
cout << array[length];

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)

getting mergesort to work on linked-list?

Apologies if this is a silly / simple question.. but I'm very lost. I'm having trouble getting this program to run. I've written this program to read in 2 values, the first being a number of elements in a linked list, and the second to be the maximum random value that can be put into each element.
It should then use the merge sort algorithm included to sort and reprint the sorted list.
Ok, so I'm getting errors like:
base operand of `->' has non-pointer type `LIST'
and
request for member `element' in `conductor', which is of non-aggregate type `LIST *'
...(and a few others).
Yes this is for a class.. I've written the program but I'm not sure what I've done wrong here or why I'm getting errors? Any help is appreciated! Thank you
#include <cstdlib>
#include <iostream>
#include <math.h>
#include <sys/time.h>
using namespace std;
typedef struct LIST {
int element;
LIST *next;
};
LIST split(LIST list)
{
LIST pSecondCell;
if (list == NULL)
return NULL;
else if (list.next == NULL)
return NULL;
else {
pSecondCell = list.next;
list.next = pSecondCell.next;
pSecondCell.next = split(pSecondCell->next);
return pSecondCell;
}
}
LIST merge(LIST list1, LIST list2)
{
if (list1 == NULL)
return list2;
else if (list2 == NULL)
return list1;
else if (list1.element <= list2.element) {
list1.next = merge(list1.next, list2);
return list1;
} else {
list2.next = merge(list1, list2.next);
}
}
LIST MergeSort(LIST list)
{
LIST SecondList;
if (list == NULL)
return NULL;
else if (list.next == NULL)
return list;
else {
SecondList = split(list);
return merge(MergeSort(list), MergeSort(SecondList));
}
}
int main(int argCount, char *argVal[])
{
int i, number, max;
struct timeval time1;
struct timeval time2;
//check for correct number of arguments
if (argCount != 3) {
cout << "Incorrect number of arguments" << endl;
return 0;
}
// initialize read in n and max values
number = atoi(argVal[1]);
max = atoi(argVal[2]);
// create list and fill with random numbers
LIST *conductor;
LIST *root = new LIST;
conductor = root;
for (i = 0; i < number; i++) {
conductor.element = rand() % max;
conductor.next = new LIST;
conductor = conductor.next;
}
// time how long it takes to sort array using mergeSort
gettimeofday(&time1, NULL);
mergeSort(root);
gettimeofday(&time2, NULL);
// print name, sorted array, and running time
cout << "Heather Wilson" << endl;
conductor = root;
for (i = 0; i < number - 2; i++) {
cout << conductor.element << ", ";
conductor = conductor.next;
}
double micro1 = time1.tv_sec * 1000000 + time1.tv_usec;
double micro2 = time2.tv_sec * 1000000 + time2.tv_usec;
cout << conductor.element << endl;
cout << "Running time: " << micro2 - micro1 << " microseconds" << endl;
return 0;
}
For base operand of->' has non-pointer type LIST'
Replace the -> with a .. You want to access a member of a local LIST, not a member of a pointed at object.
request for memberelement' in conductor', which is of non-aggregate type LIST *
This is the opposite. Replace the . with a ->. You want to access a member of the pointed at LIST, not a member of the pointer.
For clarification, I didn't read the code. There's too much of it. But those are the usual ways to address those specific errors. parapura seems to have actually read the code.
First: you should never have let the code grow this big with so many errors. You should start small and simple, then build up, testing at every stage, and never add to code that doesn't work.
Here's a stripped-down beginning of your code, with some bugs fixed:
#include <iostream>
using namespace std;
typedef struct LIST{
int element;
LIST *next;
};
int main(){
int i, number, max;
number = 5;
max = 100;
// create list and fill with random numbers
LIST *conductor;
LIST *root = new LIST;
conductor = root;
for(i=0; i<number; i++){
conductor->element = rand() % max;
cout << "element " << i << " is " << conductor->element << endl;
conductor->next = new LIST;
conductor = conductor->next;
}
conductor = root; // Forgot this, didn't you!
for(i=0; i<number-2;i++){
cout << conductor->element << ", ";
conductor = conductor->next;
}
return 0;
}
Take a look at this, verify that it works, make sure you understand the changes I made, then you can take a crack at implementing your split, merge and MergeSort functions and the I/O (one at a time, and testing at every stage, naturally).
I think all the places you are passing
LIST merge ( LIST list1 , LIST list2 )
it should be
LIST* merge ( LIST* list1 , LIST* list2 )