So, I have this array. It needs to be accessed outside the scope of this function. I have been slapping a pointer to it into a pair which gets put into a deque. But once I'm outside the scope, the local stack is gone, the array is invalid, and I've just got a useless pointer, right?
So I've trying to put this array onto the scope-transcending heap, where it will remain until I delete it at a later time. But I'm having issues getting this working. Right now g++ is coughing up errors about invalid conversion from 'int' to 'int*'.
void randomFunction(int x, int y, int width, int height)
{
int **blah[4] = {x, y, width, height};
std::pair <foobar*, int* > tempPair (foobar1, blah);
randomDeque.push_front(tempPair);
}
I've also tried initializing it like this:
int *blah[4] = new int[4];
...and it says that the array must be initialized with a brace-enclosed initializer.
I'm really not used to working with pointers. What am I doing wrong?
There are two problems. First, indeed, you are confused about pointers/arrays:
int a[4]; // this is an array of 4 integers, a is the name of the array
int *a[4]; // This is an array of 4 *pointers* to int
So your declaration:
int **blah[4];
Define an array of 4 pointers to pointers array. Maybe you are confused by the following fact (I know I was when I learned C). If you declare a variable:
int *a;
This is a declaration of a pointer to an integer. But if you have a variable a which is a pointer, you get the thing it points to (an integer here) by using *a:
*a = 1; // a is a pointer (i.e. an address), *a is the value pointed to by a.
So * in declaration is used to declare pointer, but * in statements is used to deference value.
But your second problem has nothing to do with pointer per-se. It is about ressource-management (memory being one, but file, locks being others). Anything allocated on the stack does not exist anymore when it is out of scope. In pure C, you only really have one solution: allocating on the heap with malloc, and making sure to free afterwards. So you would do something like:
// foo is a struct
foo *init_foo()
{
foo* tmp;
tmp = malloc(sizeof(*tmp));
// initialize tmp
return tmp;
}
And then, you will clean it with another function:
foo *a;
a = init_foo();
// do stuff
clean_foo(a);
Example: the FILE* handle and fopen/fclose (in addition to allocating stuff, there are some things related to the OS to handle the file). Another solution is to use alloca, which is not standard C, but is supported by many toolchains.
In C++, you can use smart pointers, which use for example reference counting to do resources management. I am less familiar with C++, and I am sure people will jump in on that part. The idea with reference counting is that it still gives some of the advantages of auto pointers (you don't have to call delete by yourself, which is extremely error-prone for non trivial projects), but without being purely scope-based. One reference counting-based smart pointer is shared_ptr in boost.
The whole concept looks strange to me. If you declare array on the stack, it will not exist outside the scope of your function. If you allocate it using 'new' - make sure you 'delete' it sometime, otherwise it's memory leak!
The correct code with 'new' is:
int *blah = new int[4];
...
// don't forget to:
delete [] blah;
I'm not sure if I got right what you want to do, but in case you want to return a reference to an int array which will be valid after randomFunction returns, a good way to do it is with Boost:
#include <boost/shared_ptr.hpp>
#include <vector>
boost::shared_ptr<std::vector<int> > randomFunction(int x, int y, int width, int height)
{
boost::shared_ptr<std::vector<int> > blahPtr(new std::vector<int>(4));
(*blahPtr)[0] = x;
(*blahPtr)[1] = y;
(*blahPtr)[2] = width;
(*blahPtr)[3] = height;
return blahPtr;
}
You don't have to remember about deleteing blahPtr -- when all copies of it go out of scope, Boost will delete your std::vector object automatically, and C++ standard library will delete the underlying array.
It looks like you want a 4x4 array, in which case you should create it like so (untested code from the top of my head):
int **blah = new int* [4];
for(int i = 0; i < 4; ++i)
{
*blah[i] = new int[4];
}
Alternatively you can create a 1D array and treat it like a 2D array:
int *blah = new int[16];
#define ELEM(x,y) w*4+h
blah[ELEM(1,1)] = 123;
Related
I have a method which fills the array with integers:
void fill(int* a[], int dim1, int dim2)
{
int intinArray = 0;
for(int i=0;i<dim1;i++)
{
for(int j=0;j<dim2;j++)
{
cin >> intinArray;
a[i][j] = intinArray;
}
}
}
If I declare array in method main() like this:
int** tab;
fill(tab,3,3);
It crashes when I put the first integer in cin. Why? If there's a problem with this line:
a[i][j] = intinArray;
how should I change it?
The fundamental thing wrong with your code is that you declared pointers, but nowhere do you initialize the pointers to point somewhere. You treat the pointer as if it is a regular old 2 dimensional array of integer. So if it's as easy as that, why use pointers?
Given that this is a fundamental in pointer usage and you plainly aren't doing that, the solution is to review working code that uses pointer.
int main()
{
int *p; // uninitialized -- points to who-knows-where
*p = 10; // this is undefined behavior and may crash
}
Take that code and understand why it also may crash. That pointer points to "we don't know", and then you're assigning 10 to a location that is unknown to you, me, and everyone else reading this answer. See the problem? To fix it, you have to initialize the pointer to point somewhere valid, then you can dereference it and assign to it without error.
int main()
{
int *p; // uninitialized -- points to who-knows-where
int x = 20;
p = &x; // this is now ok, since p points to x
*p = 20; // now x changes to 20
}
Your problem is in this code
int** tab; // <- this one
fill(tab,3,3);
You declared a pointer, and are using it under the assumption that it is pointing to allocated memory. (I guess a source of confusion is that with C++ objects this isn't really the case)
A pointer is a pointer - it points to a location in memory. There's no guarantee that the value it points to is valid unless you explicitly make sure it is yourself.
Read PaulMcKenzie's answer for more about pointers.
Try
int tab[x][y] = {{0}};
fill(tab,3,3);
where x and y define your 2D array's width and height. You're going to have to handle bounds checking for your application.
Note that changing {{0}} to a non zero number will not initialize everything to that number.
I am a bit confused. There are two ways to return an array from a method. The first suggests the following:
typedef int arrT[10];
arrT *func(int i);
However, how do I capture the return which is an int (*)[]?
Another way is through a reference or pointer:
int (*func(int i)[10];
or
int (&func(int i)[10];
The return types are either int (*)[] or int (&)[].
The trouble I am having is how I can assign a variable to accept the point and I continue to get errors such as:
can't convert int* to int (*)[]
Any idea what I am doing wrong or what is lacking in my knowledge?
If you want to return an array by value, put it in a structure.
The Standard committee already did that, and thus you can use std::array<int,10>.
std::array<int,10> func(int i);
std::array<int,10> x = func(77);
This makes it very straightforward to return by reference also:
std::array<int,10>& func2(int i);
std::array<int,10>& y = func2(5);
First, the information you give is incorrect.
You write,
“There are two ways to return an array from a method”
and then you give as examples of the ways
typedef int arrT[10];
arrT *func(int i);
and
int (*func(int i))[10];
(I’ve added the missing right parenthesis), where you say that this latter way, in contrast to the first, is an example of
“through a reference or pointer”
Well, these two declarations mean exactly the same, to wit:
typedef int A[10];
A* fp1( int i ) { return 0; }
int (*fp2( int i ))[10] { return 0; }
int main()
{
int (*p1)[10] = fp1( 100 );
int (*p2)[10] = fp2( 200 );
}
In both cases a pointer to the array is returned, and this pointer is typed as "pointer to array". Dereferencing that pointer yields the array itself, which decays to a pointer to itself again, but now typed as "pointer to item". It’s a pointer to the first item of the array. At the machine code level these two pointers are, in practice, exactly the same. Coming from a Pascal background that confused me for a long time, but the upshot is, since it’s generally impractical to carry the array size along in the type (which precludes dealing with arrays of different runtime sizes), most array handling code deals with the pointer-to-first-item instead of the pointer-to-the-whole-array.
I.e., normally such a low level C language like function would be declared as just
int* func()
return a pointer to the first item of an array of size established at run time.
Now, if you want to return an array by value then you have two choices:
Returning a fixed size array by value: put it in a struct.
The standard already provides a templated class that does this, std::array.
Returning a variable size array by value: use a class that deals with copying.
The standard already provides a templated class that does this, std::vector.
For example,
#include <vector>
using namespace std;
vector<int> foo() { return vector<int>( 10 ); }
int main()
{
vector<int> const v = foo();
// ...
}
This is the most general. Using std::array is more of an optimization for special cases. As a beginner, keep in mind Donald Knuth’s advice: “Premature optimization is the root of all evil.” I.e., just use std::vector unless there is a really really good reason to use std::array.
using arrT10 = int[10]; // Or you can use typedef if you want
arrT10 * func(int i)
{
arrT10 a10;
return &a10;
// int a[10];
// return a; // ERROR: can't convert int* to int (*)[]
}
This will give you a warning because func returns an address of a local variable so we should NEVER code like this but I'm sure this code can help you.
I'am wondering if built-in types in objects created on heap with new will be initialized to zero? Is it mandated by the standard or is it compiler specific?
Given the following code:
#include <iostream>
using namespace std;
struct test
{
int _tab[1024];
};
int main()
{
test *p(new test);
for (int i = 0; i < 1024; i++)
{
cout << p->_tab[i] << endl;
}
delete p;
return 0;
}
When run, it prints all zeros.
You can choose whether you want default-initialisation, which leaves fundamental types (and POD types in general) uninitialised, or value-initialisation, which zero-initialises fundamental (and POD) types.
int * garbage = new int[10]; // No initialisation
int * zero = new int[10](); // Initialised to zero.
This is defined by the standard.
No, if you do something like this:
int *p = new int;
or
char *p = new char[20]; // array of 20 bytes
or
struct Point { int x; int y; };
Point *p = new Point;
then the memory pointed to by p will have indeterminate/uninitialized values.
However, if you do something like this:
std::string *pstring = new std::string();
Then you can be assured that the string will have been initialized as an empty string, but that is because of how class constructors work, not because of any guarantees about heap allocation.
It's not mandated by the standard. The memory for the primitive type members may contain any value that was last left in memory.
Some compilers I guess may choose to initialize the bytes. Many do in debug builds of code. They assign some known byte sequence to give you a hint when debugging that the memory wasn't initialized by your program code.
Using calloc will return bytes initialized to 0, but that's not standard-specific. calloc as been around since C along with malloc. However, you will pay a run-time overhead for using calloc.
The advice given previously about using the std::string is quite sound, because after all, you're using the std, and getting the benefits of class construction/destruction behaviour. In other words, the less you have to worry about, like initialization of data, the less that can go wrong.
I have an array of pointers that point to arrays of ints.
I have made a hard coded array of ints (check 'array' below) and I want to insert it into the array of pointers (check 'bar' below), as far as I can tell, it is still an array of pointers that point to arrays of ints.
It compiles fine; no warnings.
It runs fine; and closes fine;
Until at least, I introduce the currently commented out delete statement in the destructor.
I imagine my compiler would make a better destructor at this point, but I'm interested as to what I'm doing wrong. The terminal window just throws out a gigantic memory map; and googling and searching SO didn't help much.
class foo {
public:
int **bar;
int aSize;
//CONSTRUCTOR
foo(int aSize) {
this->aSize = aSize;
bar = new int*[aSize];
for (int i=0;i<aSize;i++) {
bar[i] = new int[aSize + i];
for (int j=0;j<(aSize + i);j++) {
bar[i][j] = 0;
}
}
}
void myfunc(int *pointer) {
bar[0] = pointer;
}
~foo() {
for (int i=0;i<aSize;i++) {
//delete[] bar[i];
}
delete[] bar;
}
};
int main() {
foo *obj = new foo(5);
int array[] = {1,2,3,4};
obj->myfunc(array);
delete obj;
return 0;
};
I know I've probably done something tragic; I just don't know what it is yet.
There is a reason why I am not using STL or other templates, it is simply because I'm interested in learning this.
Maximum criticism appreciated.
The myfunc function takes in a pointer, and then sets bar[0] to that memory address. In your example code, you pass it the address of array, which is an automatic (stack) variable. The destructor then attempts to delete[] bar[0], which points to a stack variable. This is completely undefined behavior, and the reason your program is crashing. You can't delete[] a stack array. You can only delete[] an array which was allocated using new[].
Also, the myfunc function is always going to leak memory, because bar[0] points to a heap-allocated array. When you set bar to a different memory address without first delete[]ing the previous address, you are leaking memory.
The problem is calling myfunc. In that function, you are replacing a pointer (bar[0]) that your class thinks it owns. Your obj destructor will then consequently try to run delete[] on your array[] in main, which probably causes your crash and leaves your original bar[0] dangling.
If I have a typedef of a struct
typedef struct
{
char SmType;
char SRes;
float SParm;
float EParm;
WORD Count;
char Flags;
char unused;
GPOINT2 Nodes[];
} GPATH2;
and it contains an uninitialized array, how can I create an instance of this type so that is will hold, say, 4 values in Nodes[]?
Edit: This belongs to an API for a program written in Assembler. I guess as long as the underlying data in memory is the same, an answer changing the struct definition would work, but not if the underlying memory is different. The Assembly Language application is not using this definition .... but .... a C program using it can create GPATH2 elements that the Assembly Language application can "read".
Can I ever resize Nodes[] once I have created an instance of GPATH2?
Note: I would have placed this with a straight C tag, but there is only a C++ tag.
You could use a bastard mix of C and C++ if you really want to:
#include <new>
#include <cstdlib>
#include "definition_of_GPATH2.h"
using namespace std;
int main(void)
{
int i;
/* Allocate raw memory buffer */
void * raw_buffer = calloc(1, sizeof(GPATH2) + 4 * sizeof(GPOINT2));
/* Initialize struct with placement-new */
GPATH2 * path = new (raw_buffer) GPATH2;
path->Count = 4;
for ( i = 0 ; i < 4 ; i++ )
{
path->Nodes[i].x = rand();
path->Nodes[i].y = rand();
}
/* Resize raw buffer */
raw_buffer = realloc(raw_buffer, sizeof(GPATH2) + 8 * sizeof(GPOINT2));
/* 'path' still points to the old buffer that might have been free'd
* by realloc, so it has to be re-initialized
* realloc copies old memory contents, so I am not certain this would
* work with a proper object that actaully does something in the
* constructor
*/
path = new (raw_buffer) GPATH2;
/* now we can write more elements of array */
path->Count = 5;
path->Nodes[4].x = rand();
path->Nodes[4].y = rand();
/* Because this is allocated with malloc/realloc, free it with free
* rather than delete.
* If 'path' was a proper object rather than a struct, you should
* call the destructor manually first.
*/
free(raw_buffer);
return 0;
}
Granted, it's not idiomatic C++ as others have observed, but if the struct is part of legacy code it might be the most straightforward option.
Correctness of the above sample program has only been checked with valgrind using dummy definitions of the structs, your mileage may vary.
If it is fixed size write:
typedef struct
{
char SmType;
char SRes;
float SParm;
float EParm;
WORD Count;
char Flags;
char unused;
GPOINT2 Nodes[4];
} GPATH2;
if not fixed then change declaration to
GPOINT2* Nodes;
after creation or in constructor do
Nodes = new GPOINT2[size];
if you want to resize it you should use vector<GPOINT2>, because you can't resize array, only create new one. If you decide to do it, don't forget to delete previous one.
also typedef is not needed in c++, you can write
struct GPATH2
{
char SmType;
char SRes;
float SParm;
float EParm;
WORD Count;
char Flags;
char unused;
GPOINT2 Nodes[4];
};
This appears to be a C99 idiom known as the "struct hack". You cannot (in standard C99; some compilers have an extension that allows it) declare a variable with this type, but you can declare pointers to it. You have to allocate objects of this type with malloc, providing extra space for the appropriate number of array elements. If nothing holds a pointer to an array element, you can resize the array with realloc.
Code that needs to be backward compatible with C89 needs to use
GPOINT2 Nodes[1];
as the last member, and take note of this when allocating.
This is very much not idiomatic C++ -- note for instance that you would have to jump through several extra hoops to make new and delete usable -- although I have seen it done. Idiomatic C++ would use vector<GPOINT2> as the last member of the struct.
Arrays of unknown size are not valid as C++ data members. They are valid in C99, and your compiler may be mixing C99 support with C++.
What you can do in C++ is 1) give it a size, 2) use a vector or another container, or 3) ditch both automatic (local variable) and normal dynamic storage in order to control allocation explicitly. The third is particularly cumbersome in C++, especially with non-POD, but possible; example:
struct A {
int const size;
char data[1];
~A() {
// if data was of non-POD type, we'd destruct data[1] to data[size-1] here
}
static auto_ptr<A> create(int size) {
// because new is used, auto_ptr's use of delete is fine
// consider another smart pointer type that allows specifying a deleter
A *p = ::operator new(sizeof(A) + (size - 1) * sizeof(char));
try { // not necessary in our case, but is if A's ctor can throw
new(p) A(size);
}
catch (...) {
::operator delete(p);
throw;
}
return auto_ptr<A>(p);
}
private:
A(int size) : size (size) {
// if data was of non-POD type, we'd construct here, being very careful
// of exception safety
}
A(A const &other); // be careful if you define these,
A& operator=(A const &other); // but it likely makes sense to forbid them
void* operator new(size_t size); // doesn't prevent all erroneous uses,
void* operator new[](size_t size); // but this is a start
};
Note you cannot trust sizeof(A) any where else in the code, and using an array of size 1 guarantees alignment (matters when the type isn't char).
This type of structure is not trivially useable on the stack, you'll have to malloc it. the significant thing to know is that sizeof(GPATH2) doesn't include the trailing array. so to create one, you'd do something like this:
GPATH2 *somePath;
size_t numPoints;
numPoints = 4;
somePath = malloc(sizeof(GPATH2) + numPoints*sizeof(GPOINT2));
I'm guessing GPATH2.Count is the number of elements in the Nodes array, so if it's up to you to initialize that, be sure and set somePath->Count = numPoints; at some point. If I'm mistaken, and the convention used is to null terminate the array, then you would do things just a little different:
somePath = malloc(sizeof(GPATH2) + (numPoints+1)*sizeof(GPOINT2));
somePath->Nodes[numPoints] = Some_Sentinel_Value;
make darn sure you know which convention the library uses.
As other folks have mentioned, realloc() can be used to resize the struct, but it will invalidate old pointers to the struct, so make sure you aren't keeping extra copies of it (like passing it to the library).