This question already has answers here:
How do I declare a 2d array in C++ using new?
(29 answers)
Closed 1 year ago.
So I have a Node struct
struct Node
{
int x = 0;
};
I make 20 Node*s. My understanding is that Node** is a pointer to the start of an array that holds pointers to Nodes.
constexpr int mazeSize = 20;
Node** testMaze = new Node * [mazeSize];
After this, I started getting warnings and errors when I tried to do anything with it. Examples:
testMaze[0]->position.x == 0; //->Using uninitialized memory `*testMaze` and
What I understood from this error: *testMaze is dereferencing the array of pointers, which means it's referring to the first Node object in that array. If this is the case than how would I initialize it? If I simply created the Node* as so:
Node* node = new Node;
node->x = 0;
Than it works fine and there is no need to initialize it, so why not with the way I am doing it? I also don't understand how to initialize a struct.
Another examlpe:
testMaze[0]->x == testMaze[1]->x //->Runtime error: Access violation reading error
testMaze[0]->x = 0; //->Runtime error: Access violation writing error
How can I fix these problems? Thanks.
Problems:
constexpr int mazeSize = 20;
Node** testMaze = new Node *[mazeSize]; //this makes 20 pointers, but the pointers dont point to anything
testMaze[0]->position.x == 0; //undefined, as testMaze's pointers do not point to anything
This works because you make a new node, not a new pointer to a pointer to a node.
Node * node = new Node;
node->x = 0;
As for this:
testMaze[0]->x == testMaze[1]->x; //This is an undefined pointer, it doesn't point to anything, and you are trying to access it, so UNDEFINED behavior
testMaze[0]->x = 0; //This is a undefined pointer, it doesn't point to anything, and you are trying to access it, so UNDEFINED behavior
}
I would just do this:
Node** Make(int size) {
Node** temp = new Node * [size];
Node* pool = new Node[size];
for (int i = 0; i < size; ++i) {
temp[i] = &pool[i];
}
}
This makes your array of pointers, makes your pointers point to actual pointers which point to actual values.
Also, don't forget to delete[] your Node**s and Node*s, or you'll have a memory leak!
Always remember that pointer types are separate, concrete types with their own type and size. A pointer to T T* basically boils down to a small chunk of memory that is used to store an address to another memory area, which (hopefully) contains an instance of some type T.
With
Node** testMaze = new Node * [mazeSize];
you are allocating an array of maxSize pointer sized elements of type Node* and sizeof(Node*) (which on modern platforms is usually 4 or 8 bytes, depending if your executable is meant to run in 32 bit or 64 bit mode).
These newly created pointers are not initialized, and thus point to invalid addresses, unless you also zero initialize the array:
Node** testMaze = new Node * [mazeSize] {};
assert (testMaze[0] == nullptr); // holds true
In order to get an maxSize instances of Node, you have to, well, create maxSize instances of Node:
Node** testMaze = new Node* [mazeSize];
for (std::ptrdiff_t i {}; i < maxSize; ++i) {
testMaze[i] = new Node { /* insert parameters here */ };
}
Given that you are using constexpr, I infer the revision of C++ you are targeting is C++11 or newer. In this case, you should be aware that operator new and operator new[] are almost always the wrong choice when writing modern C++, given that they only returns pointers whose ownership and lifetime you then have to manage by hand.
You most definitely should start using STL containers, such as std::vector and std::array, which are easier to use and can avoid you a great deal of unnecessary pain. If you insist on using new, at least give a look to std::unique_ptr, which wraps a pointer or C array and automatically calls delete or delete[] as soon as it goes out of scope.
Related
I have a Node class, and when I created an array of Node pointer(Node*) and passed it through the method, I had a different length of the array as the parameter.
Node* hands[4];
Deal(deck,hands,4,"one-at-a-time",13);
void Deal(Node* &deck, Node* hands[], int people, std::string type, int count){
Node*& temp = deck;
for (int i = 0; i < count; ++i) {
for (int j = 0; j < people; ++j) {
append(hands[j], CopyDeck(temp));
temp = temp->after;
}
}
}
When I use Clion debugger to see the value of variables, I found that hands that I create has values of
hands[0] = 0x746365667265700e
hands[1] = NULL
hands[2] = NULL
hands[3] = 0x00007fc44b402430
And when it is passed through the method, in method the hands is
*hands=0x746365667265700e
hands[1]=NULL
hands[2]=NULL
hands[3]=0x00007fc44b402430
hands[4]=0x00007fc44b402570
What does the "*hands" stand for? And why the initial value in hands are not NULL? Actually the minimal example I can have is something like:
class Node{};
void test(Node* list[]){}
int main(int argc, char* argv[]){
Node * temp[4];
test(temp);
}
But it works. And I have already written the same code in other files and works as I thought.
The deck is a simply doubly-linked list of Node. Node has an attribute "after" point to the next Node. My debugger told me before
Node* &temp = deck;
the parameter "hands" already becomes a 5 elements array.
I think I found a possible reason but I can't understand the relationship between. There are two test methods in my main function. The first one is called "SortingTest" and the second one is "DealingTest". When I comment the first test method out, my DealingTest works properly, but after I uncomment it, the DealingTest doesn't work. After SortingTest ends there is no attribute or anything left in the main method. Can anyone explain it to me? Thank you all. Or maybe my clear method is wrong so it not frees the memory correctly?
void DeleteAllCards(Node* root){
Node *current, *next;
current = root;
while (current != nullptr){
next = current->after;
delete current;
current = next;
}
}
The array you created is a C-Style array, which is a fixed size array with 4 elements. In your case, the element type is Node pointer.
C-Arrays do not initialize with default values, unlike many other popular languages. Therefore, the pointer values you are seeing in hands are either a pointer to a Node * or derived type or a garbage memory address with some exceptions to this rule (see below for the edge cases defined by the Standard. For the ones that do say NULL, their memory address is at ox0000...
Update Edit To reflect a comment made by #AlgirdasPreidZius -
For C and C++, there is a standard rule where a standard C-Array shall be populated with default values upon initialization. C++ standard section 6.8.3.2.2 ([basic.start.static]): "If constant initialization is not performed, a variable with static storage duration or thread storage duration is zero-initialized."
As to why your array has those values in them from the function provided, we need more context. A reproducible example is always the best.
Your for loop, judging by the passed in parameters, is an N^2 time complexity loop with 4*4 iterations. The C-Array Node * was also passed in by reference, so when you assign Node *& to deck, the memory address marking the start of the array changes to the location of the deck array. So, it will have the values that the deck C-Array of Node *'s contains, assuming copy is a 1 : 1 copy, deep or shallow
So I currently have a simple struct (linkedlist) that I will be using in a HashMap:
struct Node {
std::string key, value;
Node* head;
}
I'm currently trying to dynamically allocate an array with pointers to each struct. This is what I have right now ...
Node* nodes = new Node[100]
I understand this allocates an array of 100 nodes into memory (which I will have to delete later on); however, upon iteration to try to transverse these nodes (which I an implementing as a linked list)...
for (int x = 0; x < 100; x++) {
Node current = nodes[x]; // Problem is I wanted an array to node pointers. This is not a pointer.
while (current != nullptr) { // this isn't even legal since current is not a pointer.
// DO STUFF HERE
current = current.next; // This is not a pointer access to a method. I'm looking to access next with current->next;
}
}
Hopefully I was clear enough. Can someone how to allocate a dynamic array of pointers to structs? So far I'm able to dynamically allocate an array of structs, just not an array of pointers to structs.
There are two approaches. Either you allocate an array of structures and introduce one more pointer that will point to the element in the array that will play the role of the head.
For example
Node *head = nodes;
(in this case head points to nodes[0])
After the list will not be needed you have to delete it using operator
delete [] nodes;
Or you can indeed to allocate an array of pointers to the structure like this
Node **nodes = new Node *[100];
But in this case each element of the array in turn should be a pointer to a dynamically allocated object;
And to delete the list you at first have to delete each object pointed to by elements of the array for example in a loop
for ( int i = 0; i < 100; i++ ) delete nodes[i];
and then to delete the array itself
delete [] nodes;
It is a good idea to initialize each element of the array with zeroes when the array is allocated for example
Node **nodes = new Node *[100]();
I suggested you this structure:
class myList {
struct Node {
string value;
Node* next;
}
/*Public methods .. Add/Set/Get/Next/isEmpty.. etc ... */
Node* head, *tail;
};
in main:
myList* lis = new myList[number];
then you have number of lists! and do all work in class by method's and operators, like if you want the next node just call lis[0].getNext();
if you want to skip current node dolis[0].Next(); ... etc ..
this how to work, what you try to do is looks like C program!
None of my code uses dynamic memory, but I do have a vector of pointers to a struct called Node, and in my code, I do lose references to those Nodes at one point. The struct looks like this:
struct Node {
int value;
Node* next;
};
I also have a for loop that tries to find the smallest value in my vector of Node pointers by taking the smallest Node off as I go. Here, lists is the vector of Node pointers, and add is the previous smallest value.
for (int i = 1; i < int(lists.size()); ++i) {
if (lists[i]->value <= add) {
add = lists[i]->value;
lists[i] = lists[i]->next;
break;
}
}
I thought I couldn't leak memory if I was just in the stack though...
If the Node referenced in the lists array is dynamically allocated, you should free all of them manually. Otherwise there will be memory leak. You can find more details on https://en.wikipedia.org/wiki/Memory_leak
I am trying to perform certain operations through linked lists on vectors.
We have been given a struct type vector
typedef struct{
int *array; // a pointer to vector's storage
int size; // the current number of elements in the vector
int cap; // the current capacity of the vector;
int init_cap; // the initial capacity the vector was initialised with.
} vector;
Now, I want to make a function that takes in a pointer to the vector struct, and initialises it with the given capacity. All the fields are to be initialised. I want to do this using linked list.
Here is my code
#include <iostream>
using namespace std;
typedef struct node {
int *array; // a pointer to the vector's storage
int size; // the current number of elements in the vector
int cap; // the current capacity of the vector
int init_cap; // the initial capacity the vector was initialised with
node *next;
} vector;
node *head = NULL;
Can I make nodes from a vector struct, like I have attempted in the code written above?
void vector_init(vector *v, int capacity){
//initialising the vector with the given capacity
v->size = capacity;
v->cap = capacity;
v->init_cap = capacity;
//linked list with nodes created and values initialised
node *temp, temp2;
temp = head;
temp = new node;
temp->size = capacity;
temp->cap = capacity;
temp->init_cap = capacity;
temp->next = temp2
temp2 = new node;
temp2->size = capacity;
temp2->cap = capacity;
temp2->init_cap = capacity;
temp2->next = NULL;
}
Have I made the linked list, and initialised the values correctly? If we do not create temporary points temp and temp2, and just use v->size etc to initialise the fields, would that make it a linked list?
You have many problems with your code.
Don't use the name vector - there is a structure called std::vector and it is easy to get confused.
If you want to initialize the values of the structure, don't create an external, separate function for that - it's not c++'ish. Create a struct constructor initializing all the values instead.
You don't initialize the array variable anywhere in your code. You should allocate space for it depending on the capacity given in the constructor.
Don't use the name 'array' for the variable. There is a structure called std::array in C++, and it might be confusing.
Your implementaion makes very little sense to me. You have a linked list of arrays right now; if you would like to functionally replace an array of ints with a linked list of ints, each node should contain one int value.
If, for some reason, you would want to stick to this implementation, you also need some kind of update function that would automatically update size and cap variables while adding or removing elements from array. Otherwise you are sure to end up forgetting about it and you're gonna have mess in your structure. Make this function a part of the structure - it shouldn't be an external function.
That typedef struct node doesn't make sense even after changing the word vector to something else - you don't use it anyway in your code.
You are using the same name for two different structures; vector is at first defined as having 4 fields, and in the next lines as having 5 fields.
Technically yes, this is a linked list, but your vector_init() function does not work as it should. Apart from what I've written above:
You should avoid making functions depend on the global variable, in this case head. It could be passed as a parameter.
These two lines:
temp = head;
temp = new node;
don't make sense. The first one makes the variable temp point to head; the second one tells temp to start pointing to the new variable as you're using operator new, which allocates space and return a pointer to the newly created variable. As a result, you don't operate on the variable head, when you do further operations, but on another variable that will be lost after the temp pointer gets invalidated.
You don't need temp and temp2 variables at all. They only bloat the code.
These two lines:
temp->next = temp2;
temp2 = new node;
should switch places since now you assign a pointer that hasn't been yet initialised.
After writing all this stuff I've realised that the function is incorrect in general. For some reason, you first work on the parameter v, and then do something unrelated to it.
Also, your instructor is just not right saying that you can solve all types of problems with the use of linked lists. It may solve some problems in certain situations, or create new problems, depending on the context.
I don't want to be rude, but there seems to be something fundamentally wrong with the concept of the task you have been given itself. I guess someone really hasn't thought it through.
I know * defines a pointer... does ** define a pointer to a pointer?
If so, why?
Is a pointer to a pointer some times known as a reference? Just need clarification for the following very simple hash.
Generally pointers are used to pass the location of larger structures when passng the entire contents would be too costly.
I've seen pointers to pointers used in the quantlib project to create "handles" as each "observer" holds a pointer to a "term structure" pointer that might change at run-time, hence the pointer held the location of another pointer.
However I see no correlation here?
class hash_entry
{
private:
int key;
int value;
public:
hash_entry(int key, int value)
{
this->key = key;
this->value = value;
}
int getKey()
{
return key;
}
int getValue()
{
return value;
}
};
class hash_map
{
private:
hash_entry **table;
static const int TABLE_SIZE = 128;
public:
hash_map()
{
table = new hash_entry*[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++)
table[i] = NULL;
}
int get(int key)
{
int hash = (key % TABLE_SIZE);
while (table[hash] != NULL && table[hash]->getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] == NULL)
return -1;
else
return table[hash]->getValue();
}
void put(int key, int value)
{
int hash = (key % TABLE_SIZE);
while (table[hash] != NULL && table[hash]->getKey() != key)
hash = (hash + 1) % TABLE_SIZE;
if (table[hash] != NULL)
delete table[hash];
table[hash] = new hash_entry(key, value);
}
~hash_map()
{
for (int i = 0; i < TABLE_SIZE; i++)
if (table[i] != NULL)
delete table[i];
delete[] table;
}
};
Yes, ** defines a pointer to a pointer (because the spec says so). No, I can't quite imagine anybody calling that a reference.
As to why they're using it in this case, they're writing (very C-like) code to dynamically allocate an array of pointers to X. This code:
hash_entry **table;
[ ... ]
hash_map() {
table = new hash_entry*[TABLE_SIZE];
Is roughly equivalent to:
std::vector<hash_entry *> table(TABLE_SIZE);
(though for the moment, I haven't split it up as you'd need to for a class member).
Yes, ** is a pointer to a pointer, but no, that's not the same as a reference. In this context, it's being used to create a dynamically-allocated two-dimensional array of hash_entry.
By the way, are you sure this code compiles? I see some things that appear to be syntax errors.
You are correct that ** refers to a pointer to a pointer (though incorrect that this is a reference - references are denoted with the ampersand - int & foo, for example).
In this case, it is being used not in the way you have described (as "handles"), but as an array of pointers to hash_entrys
The line:
table = new hash_entry*[TABLE_SIZE];
means "allocate a block of memory to hold hash_entry pointers, of size TABLE_SIZE * sizeof(hash_entry*). From there, the array is initialized to NULL, after which you can fill each entry in the array with a pointer as needed.
Yes, ** represents a pointer to a pointer.
One reason to add that extra level of indirection is so that you can move the thing ultimately pointed to around in physical memory without the code pointing to that something needing to be directly informed of the new address.
If a memory manager wants to move something in memory (for example, to reduce holes in a heap), it can allocate new memory, move the object, and update the address pointed to by the pointer-pointer to point to that new address.
Specifically in this case, if you have more hash entries than TABLE_SIZE, the code could reallocate hash_entry with a larger block of memory and update table with the new address of hash_entry. The rest of the code can be ignorant to the re-allocation.
I know * defines a pointer...does ** define a pointer to a pointer?
Yes.
If so why?
I'll assume you mean here why would someone use one, not how the types work (see any c reference for that). There are a few places I've seen and used them:
Dynamic array of pointers. (This is what we have here)
Dynamic 2-d arrays. (This is actually a subset of 1, a dynamic array where each element points to another dynamic array)
"Returning" a pointer via pointer passed as arg (*arg = ptr_to_return). See, e.g. getline()
Is a pointer to a pointer some times known as a reference? Just need clarification for the following very simple hash.
No, a reference is essentially passing by reference but letting the compiler keep track of the pointer for you.
Generally pointers are used to pass the location of larger structures when passng the entire contents would be too costly.
Yes, but not exclusively. Consider a method that changes a member of a struct. You need it to change YOUR copy of the struct, not the local copy it would have if you passed by value.
In your example here, hash_entry **table; is being used as a (dynamically sized) array of pointers to hash_entrys. It could, perhaps more clearly, be declared hash_entry *table[];