C++ newbie here. This may be stupid but I am getting segmentation fault while assigning value to struct in a class. Any pointers?
#include <iostream>
#include<string>
using namespace std;
struct s { std::string s;};
class A {
public:
A(){}
~A(){}
struct s *ss[10];
};
int main(){
A a;
a.ss[0]->s = "test";
cout<<a.ss[0]->s<<endl;
return 0;
}
The pointer a.ss[0] is not allocated.
You could for example allocate it in the constructor of class A, like this:
A(){ ss[0] = new s; }
I'm not sure what the purpose of your code is.
P.S.: Don't forget to delete the allocated memory once it is not needed anymore. For example:
~A(){ delete ss[0]; }
Alternatively, as LogicStuff pointed out, you can rewrite the array of pointers to a regular array, like this:
struct s ss[10];
struct s *ss[10];
What this line declares is an array of 10 pointers to struct s, not 10 objects of type struct s. Those 10 pointers point nowhere, to make them useful you have to actually allocate memory for and create those object (and clean them up when you're done).
This is where constructors and destructors come in handy:
class A {
public:
A()
{
for(int i = 0; i < 10; ++i)
{
ss[i] = new s;
}
}
~A()
{
for(int i = 0; i < 10; ++i)
{
delete ss[i];
}
}
struct s *ss[10];
};
Now each of those 10 pointers in your array point to valid struct s objects, so you can safely access them:
A a;
a.ss[0]->s = "test";
When you say
/*struct*/ s *ss[10]; // P.S. you don't need "struct" here as in C
the compiler understands that it should reserve space in your class for 10 pointers to objects of type s. It doesn't make sure that those pointers point to anything valid, though.
Actually, the safest thing would be to avoid raw arrays entirely and use a vector. Your life will be much easier.
struct A {
// note no need to declare default ctor and dtor here
std::vector<s> ss{10}; // initialize with 10 default-constructed strings
};
// then in main()
A a;
a.ss[0].s = "test";
s* p = &ss[0]; // if you need a pointer; fine so long as vector doesn't change
Related
class Class
{
public:
Class(array[3][3]) //the constructor
{
this->array = array
}
array[3][3];
};
int main()
{
array[3][3] = {...initialization...};
Class object(array[3][3]);
}
I want to make an object, which uses the 2d array and modifies it. I know that C arrays are just pointers to an address, but I couldn't pass it in the constructor no matter how many *, & or [] I write.
The most clever thing I could think of is making an array of POINTERS in the class, and assigning each pointer, to the address of the original array's element via for loop, but then every time I want to modify, or read from the array in main, I have to write for example *array[2][1] = 3.
Any clever solution?
If I finally got the question correctly, you can use a reference to an array:
struct Class {
Class(int (&array)[3][3]) : array_(array)
{}
void set11(int value) {
array_[1][1] = value;
}
int (&array_)[3][3];
};
int main() {
int array[3][3]{};
Class object(array);
object.set11(99);
std::cout << array[1][1]; // Prints 99
}
If that's not what you want, please clarify your question.
Here's how to declare a pointer in your class that can point to the array in main.
class Class
{
public:
Class(int (*array)[3])
{
this->array = array;
}
int (*array)[3];
};
int main()
{
int array[3][3] = { ... };
Class object(array);
}
I have a simple problem but I need to understand the concept behind it.
How to access data members of a 1st struct by instantiating it as pointer in 2nd struct.
If I make data members of 1st struct as pointer then how to print out there values by accessing them e.g.
struct temp
{
int a =5;
float b = 6.0;
i = &a;
f = &b;
int *i;
float *f;
};
I am working on a complex code so I need to understand the logic behind it as how it works in-terms of memory and logic.
Thanks a lot for your time in advance.
#include <iostream>
using namespace std;
struct temp {
int i=5;
float f=6.0;
};
struct qlt {
temp *d;
};
int sum (qlt *s)
{
int a = s->d->i;
// std::cout<<a;
}
int main() {
qlt x;
//int b = ;
std::cout <<sum(&x);
return 0;
}
qlt x;
This creates a qlt allright, but not the d inside it. So you have a dangling pointer (since it's also left uninitialized).
qlt x;
temp b;
x.d = &b;
this would be a C-style solution. C++ has way better ways to do it.
Forget all sort of pointers at this moment and use STL.
Should be a simple question, I have a struct
struct Foo{
float *bar;
Foo(){
bar = 0;
}
};
and a load function:
bool loadFoo(Foo *data){
float nums[4] = {0,1,2,3};
data->bar = nums;
return true;
};
And I run it like this:
void main(){
char data;
Foo myFoo;
loadFoo(&myFoo);
std::cerr << sizeof(myFoo.bar) << "\n";
std::cerr << myFoo.bar[0] << "\n";
std::cerr << myFoo.bar[1] << "\n";
std::cerr << myFoo.bar[2] << "\n";
std::cerr << myFoo.bar[3];
std::cin >> data;
};
and the output is 4 bytes for the sizeof(myFoo->bar) I thought by passing the struct to the method I could modify data->bar and since bar is, float *bar; I could make it an array since I cant specify that bar is an array because its an 'unknown size' when loaded. (when implemented the program will read in values from a file) This works fine with non pointer variables but its the pointer that I can't seem to understand.
How do I make it so that when I pass the struct I can modify the variable pointer?
any help would be greatly appreciated!
You can do something like you've specified, but the exact implementation you've given will encounter undefined behavior.
bool loadFoo(Foo *data){
// Create an array of 4 floats ON THE STACK.
float nums[4] = {0,1,2,3};
// point data->bar at the above slice of stack.
data->bar = nums;
return true;
// abandon the piece of stack we're pointing at.
}
You might want to look into std::vector as a growable way of storing runtime sizes arrays, or you will need to allocate backing store for the destination floats, e.g.
data->bar = new float[4];
and free it when you are done with it
delete data->bar;
That said; it would seem more elegant to do these operations as members of Foo.
#include <vector>
// #include <algorithm> // (for the std::copy option)
class Foo
{
std::vector<float> m_floats;
public:
Foo() : m_floats() {}
void loadFloats()
{
m_floats = { 0, 1, 2, 3 };
}
// or load them from someplace else
void loadFloats(float* srcFloats, size_t numFloats)
{
m_floats.clear();
m_floats.reserve(numFloats);
// copy by hand:
for (size_t i = 0; i < numFloats; ++i) {
m_floats.push_back(srcFloats[i]);
}
// or just:
// std::copy(srcFloats, srcFloats + numFloats, m_floats);
}
};
You haven't specified the problem but let me guess - it crashes and/or doesn't yield the result you expect. The reason for that is assigning a pointer to a local variable in the line data->bar = nums; Here you link your data->bar to a nums array which is allocated on stack and is freed when you exit loadFoo. The result is a dangling pointer inside your Foo object.
You can solve this in different ways. The most straightforward would be to use a constructor with size parameter - this will solve your unkonwn size issue. You'll need to explicitly allocate memory for the data->bar and copy the data into the allocated space (of course, it will require to free it when not in use anymore). Same effect can be achieved by using your loadFoo func but using internal language features (constructor/destructor) is much cleaner.
Instead of loadFoo you can have constructor
struct Foo{
float *bar;
Foo( int size){
bar = new float[size]; //allocate memory
//... Initialize bar
}
~Foo() { delete bar;}
};
OR using initializer_list
#include <initializer_list>
struct Foo{
float *bar;
Foo( std::initializer_list<float> l){
bar = new float[l.size()]; //allocate memory
std::initializer_list<float> ::iterator it = l.begin();
size_t i=0;
for(;it!=l.end();++it,++i)
bar[i] = *it;
}
~Foo() { delete bar;}
};
Also, make sure you follow rule of three
I would like to create a struct and use it inside an other struct as an array. My problem is that I don't know how big array I would like to allocate, I will only know once I am in a function. I mean I would like to use [] instead of a pre-determined constant, like 10000.
I think if you look at my code it would be self-explanatory. Can you help me how to make this code work? Moreover it would help me a lot if you could tell me what is the name of the topic I am asking about (is it dynamic arrays?) and that where can I find articles/tutorials about this topic.
Here is the code with my broken way of thinking about arrays in structs.
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe keyframes[];
};
int main() {
keyframe_file my_file;
my_file.num_views = 1;
my_file.num_keyframes = 6;
my_file.keyframes = new keyframe[my_file.num_keyframes];
my_file.keyframes[0].a = true;
my_file.keyframes[0].b = 5;
my_file.keyframes[0].c = 9;
return 0;
}
Use a std::vector.
struct keyframe_file {
const int num_views;
const int num_keyframes;
std::vector<keyframe> keyframes;
};
int main() {
keyframe_file frame;
frame.keyframes.resize(...);
}
If it suits your purpose, an STL container (std::vector) is easily one of the best options - the less memory management you have to worry about, the better.
In any case, look at the struct definition Nawaz posted above - that's exactly how it should be. Dynamic arrays in C++ are simply pointers. You have, however, allocated the memory properly in your code, but you haven't freed it (so it's leaking). Since you allocated with new [] you will need to
delete [] my_file.keyframes;
in order to free the memory properly.
Resizing is another issue: with a smart implementation, array resizing can be an amortized O(1) operation which is nice. When you resize, it will always take you O(n) since you need to copy all the elements into a new array of different size, but if you do it half as much, it becomes O(1). That is, double the array each time you need to resize. Here is a very quick example
void resize()
{
if(numOfElementsInArray == sizeOfArray)
{
ArrayType * arr = new ArrayType[sizeOfArray*2]; // Allocate a double size array
for(int i=0;i<sizeOfArray;++i)
currentArray[i] = arr[i];
delete [] currentArray; // Free memory in old array
currentArray = arr; // Set the array to our new one
sizeOfArray *= 2; // Double the size
}
}
NOTE: The example above does not take into account space complexity; that said, if you have 5000 elements, and remove all but 5, this method with not shrink it (which is probably what you will want to do for all practical purposes)
Your code appears to be almost correct, except for two things:
keyframes needs to be a keyframe* rather than a keyframe[]
You forgot to delete the memory you allocated
That is incomplete type. In C++, array must be provided with size, and the size must be known at compile time itself.
You're using new, with which you should be using pointer.
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe *keyframes;
};
But std::vector<keyframe> is still a better choice, as #DeadMG already suggested.
By the way, the first two members are const in the struct, that means, they cannot be assigned value, as you're doing in your code. They must be initialized with values you want them to hold. That implies, now with vector, you've to include a constructor, to initialize the struct, as the struct is no more a POD.
struct keyframe_file {
const int num_views; //const member
const int num_keyframes; //const member
std::vector<keyframe> keyframes;
keyframe_file(int nviews, int nkeyframes)
: num_views(nviews), num_keyframes(nkeyframes), keyframes(nkeyframes){}
};
keyframe_file my_file(1,6); //done!
The suggested "Vector" is they safest way to do it.
But if it is only about making your code work (without resizing and stuff) the following should be working:
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe* keyframes;
};
int main()
{
keyframe_file my_file = {1, 6}; // initialization needed bcause of 'const int'
my_file.keyframes = new keyframe[my_file.num_keyframes];
for (int i = 0; i < my_file.num_keyframes; i++)
{
my_file.keyframes[i].a = true;
my_file.keyframes[i].b = 5 + i;
my_file.keyframes[i].c = 9 - i;
}
return 0;
}
somewhere in your code, when you are done using the array you have to call delete [] my_file.keyframes; as already mentioned.
There's a basic rule when using dynamic arrays in c++, especially when using it inside structs or classes, and it's to delete what you no longer need.
If you want to make your struct dynamic, it's easy, just replace the [] with * and the array will become dynamic, but it's not over yet, there is a lot of work.
You have to construct the array and destory it, and destoroying it is possible and useful noly with destructors, like this:
struct keyframe_file
{
const int num_views;
const int num_keyframes;
keyframe* keyframes;
~keyframe_file() // this is the destructor
{
delete[] keyframes;
}
};
Yet even that code isn't going to work at all, since you are assigning values to constants in variable my_file after creating it, it's illegal in c++, you should then use classes instead.
Using classes with dynamic arrays is very easy and interesting and makes your code very good, you don't have to know too much to do that, just learn what is a constructor, an initializer, destructor, private and public and go on with the following code:
#include <iostream>
using namespace std;
struct keyframe
{
bool a;
int b,c;
};
class keyframe_file
{
public:
keyframe_file(int NV, int NKF):num_keyframes(NKF),num_views(NV)
{
keyframes = new keyframe[num_keyframes];
}
~keyframe_file()
{
delete[] keyframes;
}
private:
const int num_views;
const int num_keyframes;
keyframe* keyframes;
};
int main()
{
keyframe_file my_file(1,6);
return 0;
}
This code works very well, it allows you to assign value to the constants num_views and num_keyframes for one time when creating the object (variable) my_file.
Remember, you are a C++ programmer, be proud of that, and use classes instead of structs and dynamic arrays instead of static ones.
Hope that's useful.
Use pointers and apply to your structure!
int *p;
p = new int;
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe *keyframes;
};
int main() {
keyframe_file my_file;
my_file.num_views = 1;
my_file.num_keyframes = 6;
for (int i = 0; i < my_file.num_keyframes; i++){
my_file.keyframes = new keyframe; //<---
}
my_file.keyframes[0].a = true;
my_file.keyframes[0].b = 5;
my_file.keyframes[0].c = 9;
return 0;
}
If I have:
struct a_struct
{
int an_int;
a_struct(int f) : an_int(f) {}
a_struct() : an_int(0) {}
};
class a_class
{
a_struct * my_structs;
a_class() {...}
};
I can do:
a_class() {my_structs = new a_struct(1)}
//or
a_class() {my_structs = new a_struct [10]}
But I cannot do:
a_class() {my_structs = new a_struct(1) [10]}
//or
a_class() {my_structs = new a_struct() [10]}
Is there any correct syntax to get this to work? Or an easy work around?
If using the STL is an option, you could use std::vector instead of a dynamic array.
I think that this will work:
std::vector<a_struct> my_structs;
my_structs.assign(10, 1);
If not, this should:
my_structs.assign(10, a_struct(1));
You could allocate a raw chunk of memory and use placement new to initialize each struct:
int number_of_structs = 10;
my_structs = (a_struct*)new unsigned char[sizeof(a_struct) * number_of_structs];
// allocate a raw chunk of memory
a_struct* p = m_structs;
for (int i=0; i<number_of_structs; i++)
{
new (p) a_struct(i);
p++;
}
//When done should add code for deallocation to help people
// to understand the full cycle of memory management.
for (auto i=0; i<number_of_structs; ++i) {
my_structs[i].~a_struct();
}
delete[] my_structs;
See also: What uses are there for "placement new"?
You could use an array of pointers to pointers. Then you can create the array that will hold pointers to a_struct(), so you can decide later which constructor to use:
class a_class {
a_struct ** my_structs;
a_class() { my_structs = new a_struct* [10]}
void foo () {
my_structs[0] = new a_struct(1);
my_structs[5] = new a_struct("some string and float constructor", 3.14);
}
};
You can't do it directly on any particular parameterized constructor. However you can do,
a_struct *my_struct[10] = {}; // create an array of pointers
for (int i = 0; i < 10; i++)
my_struct[i] = new a_struct(i); // allocate using non-default constructor
I suggest using a std::vector container instead of going through this process.