I am using a array of pointer's declared within a class to point to another array. When a pointer array element is initialised to a value within main that value is also carried to the array element it is pointing to. The following code show this and it works fine. However if I initialise the pointer within the init class function I get a segfault. Also if I try to access an element from the pointer array not initialised in main I also get a segfault.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
class testclass {
public:
double *Wgt;
double* *LWgt;
void init() {
Wgt = new double[26];
LWgt = new double*[26];
//segfault from here
*LWgt[5] = 22.34543;
}
};
int main() {
testclass *node;
node = new testclass[10];
for (int i = 0; i < 10; i++) {
node[i].init();
}
for (int i = 0; i < 5; i++) { //init_nconn here
node[i].LWgt[23] = &node[i + 5].Wgt[12];
}
node[6].Wgt[12] = 50.6987;
node[8].Wgt[12] = 0.999923;
cout << *node[1].LWgt[23] << *node[3].LWgt[23] << "--\n";
//No segfault
*node[1].LWgt[23] = 33.234;
cout << node[6].Wgt[12] << "---\n";
//No segfault here
cout << *node[1].LWgt[23] << "---\n";
//Segfault from here
cout << *node[3].LWgt[5] << "---\n";
}
Is there a way to initialise the pointer array within a class function without leading to a segfault?
LWgt = new double*[26];
allocates memory for 26 double* but does not allocate memory for the pointers themselves.
The line
*LWgt[5] = 22.34543;
causes undefined behavior since memory hasn't been allocated for any of the elements of LWgt.
In order to be able to use that, you have to allocate memory for LWgt[5] first.
LWgt[5] = new double[<SOME_SIZE>]; // Allocate an array
or
LWgt[5] = new double; // Allocate just one element.
That's because none of the pointers stored inside LWgt actually point to anything valid yet. Remember that a pointer will be initialized by the runtime with some random value that may or may not be a valid address. When you try to stuff a value inside an invalid address you're going to get an error.
You need to initialize the pointers inside LWgt to point to some actual double memory locations before you can assign any values to them:
void init() {
Wgt = new double[26];
LWgt = new double*[26];
for(int i = 0; i < 26; i++)
LWgt[i] = new double;
//segfault from here
*LWgt[5] = 22.34543;
}
As a side note, this kind of initialization is probably best done inside a constructor for your class rather than a special initialization function. The point of constructors is that they always run automatically when the class is instantiated. You don't have to worry about remembering to call an init function right after you create the object.
Lwgt is an array of pointers to double. You'd have to allocate each element in the array or remove the ** in the declaration.
Related
I know, I could use std::vector or something like that, but I want to know where I think wrong. In the example below, only p3 is in my eyes really a pointer to an array of pointers and is used in the way I would expect. Using p1 instead looks kind of wrong to me because it looks like p1 is also an array of pointers like p2 is and not a pointer to an array of pointers, except for the delete thing. So when I try to use p2 as I do use p3:
(*p2)[i] = new Foo(i);
the error is:
ambiguous overload for ‘operator=’ (operand types are ‘Foo’ and ‘Foo*’)
The question is:
Why do I have to use a cast in the line where p3 is allocated?
Is that assignment for p3 correct or does it just work by incident?
#include <iostream>
using namespace std;
class Foo
{
public:
Foo (int key)
: key(key)
{}
int show() const
{
return key;
}
private:
int key;
};
int main (int, char**)
{
int aSize = 10;
using FooP = Foo *;
FooP *p1 = new FooP[aSize];
FooP p2[aSize];
FooP (*p3)[] = (FooP (*)[]) new FooP[aSize];
for (int i=0; i < aSize; i++)
{
p1[i] = new Foo(i);
p2[i] = new Foo(i + aSize);
(*p3)[i] = new Foo(i + aSize * 2);
}
for (int i=0; i < aSize; i++)
{
cout << p1[i]->show() << ", "
<< p2[i]->show() << ", "
<< (*p3)[i]->show()
<< endl;
delete p1[i];
delete p2[i];
delete (*p3)[i];
}
cout << endl;
delete [] p1;
delete [] p3;
return 0;
}
So the explanation is, that the operator "new" in case of an array, always returns a pointer to the first element and not, as I expected, a pointer to the array of pointers.
So the cast I used when assigning the allocated memory to the variable p3 is valid and would not cause any memory corruption, right?
Thanks to #exprosic for the helpful hint in the comments to https://en.cppreference.com/w/cpp/language/new
Quote from there:
The new expression attempts to allocate storage and then attempts to construct and initialize either a single unnamed object, or an unnamed array of objects in the allocated storage. The new-expression returns a prvalue pointer to the constructed object or, if an array of objects was constructed, a pointer to the initial element of the array.
My code pass the compiler, but I have a question about the concept of the pointer.
main.cpp:
int main(int argc, const char * argv[])
{
int inputPuzzle[3][3];
std::cout << "Set the puzzle: " << "\n";
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
std::cin >> inputPuzzle[i][j];
}
}
puzzle puzzle_1 = *new puzzle(inputPuzzle);
puzzle_1.display();
return 0;
}
puzzle.h:
class puzzle
{
public:
puzzle();
puzzle(int [][maxCol]);
~puzzle();
public:
int puzz [maxRow][maxCol];
};
puzzle.cpp:
puzzle::puzzle(int a[][maxCol])
{
for (int i = 0; i < maxRow; i++) {
for (int j = 0; j < maxCol; j++) {
puzz[i][j] = a[i][j];
}
}
}
My question is about the statement :puzzle puzzle_1 = *new puzzle(inputPuzzle);
Why do I have to add "*" in front of the new object in which I want to assign a 2D array ?
You're programming C++, where new returns a pointer. When you use the asterisk it's the dereference operator, and basically turns a pointer into a non-pointer.
Using the dereference operator like that means that you actually lose the pointer created by new, and you can not free that allocated memory with delete which, of course, leads to a memory-leak.
To avoid losing the pointer, you have to declare the variable as a pointer:
puzzle* puzzle_1 = new puzzle(inputPuzzle);
Then you have to use the pointer member selector operator instead when accessing members:
puzzle_1->display();
And, to avoid leaking memory, when you're done with the pointer you must delete it:
delete puzzle_1;
However, in C++ there is seldom any need to use pointers; instead just declare it as a normal variable:
puzzle puzzle_1(inputPuzzle);
puzzle_1.display();
Unrelated to your question, but if maxRow or maxCol is larger than 3, then you will read from outside the memory for the array inputPuzzle. This will lead to undefined behavior.
The most important part here is the new keyword. It returns a pointer to the newly instantiated object. Check the Dynamic memory allocation for more information and to understand when and how to use pointers, and how the new keyword works.
Now, we know that the new keyword returns a pointer, and you want to obtain an object not a pointer, hence you have to dereference your pointer.
Two correct solutions now:
// without pointers
puzzle puzzle_1(inputPuzzle); // initialize the object without going through a copy
puzzle_1.display();
// with pointers
puzzle *puzzle_1 = new puzzle(inputPuzzle);
puzzle_1->display(); //notice that we used -> here as it's a pointer
// do stuffs here
delete puzzle_1; // free the memory
I made a 2D array on the heap of some objects:
Step (1)
Obj **arr = new Obj *[n];
for (int i=0;i<n;i++)
{
arr[i] = new Obj[n];
}
// so this creates 2D arr[n][n]...then when I delete it:
Step (2)
for (int i=0;i<n;i++)
{
delete [] arr[i];
}
delete [] arr;
So I'm still not sure what this delete does. Does it run the destructor of Obj and flag the OS telling it this is now available memory.
Now what I REALLY do not understand is that when I do Step (1) again (after I deleted), I get these objects initialized to weird values, yet this doesn't happen the first time I do it (all zero-initialized). Did I just get lucky the first time?
AFAIK, the following code will NOT give you weird values, no matter how many times you repeat deleting and newing.
#include <iostream>
using namespace std;
class Foo
{
public:
Foo(): val(-2) { cout << "ctor" << endl; }
~Foo() { cout << "dtor: " << val << endl; }
private:
int val;
};
int main()
{
Foo **arr = new Foo *[2];
for (int i = 0; i < 2; ++i)
arr[i] = new Foo[2](); // <- for builtin type, () is required to initialized to zero.
for (int i = 0; i < 2; ++i)
delete [] arr[i];
delete [] arr;
return 0;
}
Relevant post: Operator new initializes memory to zero
As to what happens to pointers after you delete them, please see this post: C - What happens to an array of pointers when the array is freed?
Your example lacks the declaration of Obj.
new[] allocates memory and calls the constructor of each element
If the constructor does not alter memory, you will see some random values - maybe zeros.
delete[] calls the destructor of each element previously allocated with new[] and deallocates the memory, finally.
In a debugging compilation the memory might be filled with some bytes indicating the deallocation.
Doing new[] right after the deallocation might show indicator bytes.
Hello I have made class gabka and a function f1 to which I would like to pass an array of pointers to fill this array with gabka objects but I get weird error. How to correct it?
error:
cannot convert from gabka to int
the code :
#include <iostream>
using namespace std;
const int n = 4;
class gabka {
public:
float woda;
gabka(){
woda = 0;
}
void f1(gabka t[n]){
for(int i = 0; i < n; i++){
t[i] = new gabka();
}
}
};
int main() {
gabka** t = new gabka*[n];
return 0;
};
Your f1 function takes an array of gabka objects, and you are trying to assign a gabka* to each one of them. You need to decide what you want to pass to f1. For example,
void f1(gabka t[n]){
for(int i = 0; i < n; i++){
t[i] = gabka(); // assign default constructed gabkas
}
}
or
void f1(gabka* t[n]){
for(int i = 0; i < n; i++){
t[i] = new gabka();
}
}
In the latter case, bear in mind you have to call delete on all the elements of t.
It isn't clear what you are intending to do with your code, but, as a general rule, in C++ you should avoid raw pointers and manual dynamic allocation. Prefer standard library containers over dynamically allocates arrays or arrays of dynamically allocated objects.
t[i] = new gabka();
t is an array of gabka, not an array of gabka*.
Either change the declaration of t to be an array of gabka*, or fill it with gabka instances.
After writing the code below:
#include <iostream>
using namespace std;
typedef struct Node {
int value;
Node(int index) {
value = index;
}
} Node;
int main() {
Node* arr[10];
for(int i = 0; i < 10; i++) {
arr[i] = &Node(i);
}
for(int i = 0; i < 10; i++)
cout << arr[i]->value << endl;
}
I saw that the code prints only 9's instead of all the numbers from 0 to 9 it was supposed to.
After debugging the code i saw that address of arr[i] for each i are the same, and Node(i) have freed the space for arr[i] only once, and after that the only thing it is value = index without freeing any other space. Why?
This line: arr[i] = &Node(i); is storing a pointer to a temporary object. Node(i) creates a temporary object that can be destructed at the end of the statement, at which point all references to it become invalid meaning the results of any code that dereferences arr[i] will be undefined. The reason in this case you get all 9's is because the compiler is optimizing the code -- since only 1 temporary Node(i) is being created at a time, the compiler is just reusing that memory each time through the loop.
To fix the problem, allocate memory off the heap for each object: arr[i] = new Node(i);. Then when you are done using them you will also need to remember to delete each one:
for (int i=0; i < 10; ++i) {
delete arr[i];
}
If you want to investigate farther, try adding some code to your Node class to see what's happening: for example print out the address of this in your constructor, and/or create a destructor that just prints a message out so you can see it being called.
To create new objects, use new Node(i) otherwise you are creating temporary objects on the stack which is why they are all the same.
Remember to call delete on each object that you get back from new.
&Node(i)
This expression creates a temporary variable and returns its address. The temporary is then destroyed, and the next time the expression is evaluated, another temporary is created in the same place — hence the identical addresses.
You should probably eliminate the use of pointers, and introduce a default value for Node.
#include <iostream>
using namespace std;
typedef struct Node {
int value;
Node(int index) {
value = index;
}
Node() : value( 0 ) {} // allow default construction
} Node;
int main() {
Node arr[10]; // default-construct array values
for(int i = 0; i < 10; i++) {
arr[i] = Node(i);
}
for(int i = 0; i < 10; i++)
cout << arr[i].value << endl;
}
Do not use new Node for each object individually. Always use a container object to manage a group of objects with similar semantics. You might use std::vector here, or std::array if you have it. The overhead introduced by std::vector will be less than that introduced by new.