I'm doing a little graphics programming and I have a two dimentional array (that varies in size during program execution) that I store using openGL.
So when I go to access it, all I get is a void pointer back.
To make the logic easier, I want the compiler to pretend that it is, and use it as, a 2D array (because arr[i][j] is more concise and less error prone than ptr[i * y + j]).
This clever method of casting I found works fine in GCC (on the linux machines at uni):
Vertex (&vertices)[tess][tess] = *reinterpret_cast<Vertex (*)[tess][tess]>(
glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY)
);
Which basically casts the block of memory pointer openGL gave me to a tess X tess 2D array, and creates a reference of that type to point at it.
This allows me to access the memory like vertices[i][j].
Vertex is just a typedefed struct containing floats
However, at home on my Windows machine, VS'12 has a hissy fit, complaining that it requires the integers where tess is written to be constant (specifically; error C2057: expected constant expression).
I have no idea why.
Now, I understand that VS doesn't support VLA's, but I am not creating an array here, I'm creating a reference to something that I don't know the size of 'till runtime.
So it shouldn't care if the size changes between function calls, right? Why is this not allowed?
Not to be deterred I tried using std::array
std::array<std::array<Vertex, tess>, tess>& vertices;
And apart from the obvious references must be initialized this test didn't help me because it still complained about expression must have a constant value (specifically; error C2975: '_Size' : invalid template argument for 'std::array', expected compile-time constant expression)
I am at a loss at what to try here, I was so proud of the reinterpret_cast and how simple it made things and was sure I wasn't using a method that was contravening the standard.
I don't want to create a std::vector from the pointer then copy the data from that dynamic array back into the pointer location when I'm finished; that just seems so inefficient when the memory block is already just sitting there!
There's no way to create a vector around a pre-existing block of memory, is there? ..no that sounds silly.
I want to see if this can be done without giving up and just using it as Vertex*; Ideas?
Can someone enlighten me as to why it isn't working in VS?
Is there something I can do to get it working (extensions/updates to VS)?
Does VS'13 add support for this?
I am also getting the error C2087: 'vertices' : missing subscript that I can't explain.
As well as these other errors that seem to show VS desperately wants tess to be constant:
error C2466: cannot allocate an array of constant size 0
error C2540: non-constant expression as array bound
error C2440: 'initializing' : cannot convert from 'Vertex [1][1]' to 'Vertex (&)[][1]'
Well that was fun; I implemented a class to handle exactly what I wanted.
It's not as typesafe as I'd like, but I learned a lot doing it
Much like how I felt implementing should-be-a-part-of-the-specification, syntactic-sugar-esque functionality for javascript before I discovered jQuery.
Basically, instead of being able to do this.
int (&array)[x][y] = *reinterpret_cast<int (*)[x][y]>(pointer);
You will have to do this
MDAI<int, 2> array = MDAI<int, 2>(pointer, x, y);
But other than that it works flawlessly! :D
I initially wrote just a specialised TwoDArray class but found I actually had some 3D arrays too.
So instead of implementing a 3D version (that returned TwoDArray when you drilled down) I made something more generic and can help with arrays of as many dimensions as you'd like.
#include <Windows.h>
#include <iostream>
/*MultiDimensional Array Interpretation
has the compiler use a flat pointer reference as if it were a faceted array
C++11/GCC VLA-supporting equivalent:
int (&array)[x][y] = *reinterpret_cast<int (*)[x][y]>(pointer);
using MDAI, <C++11 and MSVS compatible:
MDAI<int, 2> array = MDAI<int, 2>(pointer, x, y);
*/
template<class Type, unsigned int dimension>
class MDAI {
private:
Type* array;
//+1 to guard against zero-length-array
unsigned int bounds[dimension + 1];
public:
//unfortunately I can't use `unsigned int &(dimensions)[dimension]` to make it safe
//because of how operator[]() tries to construct its return value
/*constructor*/
MDAI(Type* array, unsigned int* bounds)
: array(array)
{
std::copy(bounds, bounds + dimension, this->bounds);
}
/*programmer usable constructor for typing of the dimensions, instead of having to declare an array*/
MDAI(Type* array, ...)
: array(array)
{
va_list arguments;
va_start(arguments, array);
for (int index = 0; index < dimension; ++index)
bounds[index] = va_arg(arguments, unsigned int);
va_end(arguments);
}
/*drills down one level into the multi dimensional array*/
MDAI<Type, dimension - 1> operator[](unsigned index) {
if (dimension < 1) {
std::cerr << "MDAI is not an array.\n";
throw 1;
}
if (index < 0 || index >= bounds[0]) {
std::cerr << "Index out of bounds.\n";
throw 1;
}
//figure out how many addresses to jump
for (unsigned int index2 = 1; index2 < dimension; ++index2)
index *= bounds[index2];
return MDAI<Type, dimension - 1>(array + index, bounds + 1);
}
/*'dereferences' the array to get a reference to the stored value*/
Type& operator*() {
if (dimension > 0) {
std::cerr << "MDAI is an array.\n";
throw 1;
}
return *array;
}
/*allows the compiler to automagically 'convert' the MDAI into whatever the user thinks it is*/
operator Type&() {
return **this;
}
/*makes assignment work automagically too!*/
MDAI<Type, dimension>& MDAI<Type, dimension>::operator=(Type value) {
**this = value;
return *this;
}
};
Testing a three-dimensional array of bounds 2-4-3:
void main(unsigned int argC, char** argV) {
using namespace std;
int array[2][4][3] = {
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
{10, 11, 12}
},
{
{13, 14, 15},
{16, 17, 18},
{19, 20, 21},
{22, 23, 24}
}
};
//cast array to pointer, then interpret
MDAI<int, 3> mdai((int*)array, 2, 4, 3);
//testing correct memory access
cout << 15 << ' ' << mdai[1][0][2] << endl;
//testing modifcations using mdai are in array
mdai[0][2][1] = -1;
cout << array[0][2][1] << ' ' << mdai[0][2][1] << endl;
//testing modifications in array show up in mdai
array[1][3][2] = -23;
cout << -23 << ' ' << mdai[1][3][2] << endl;
//testing automatic type casting
cout << -15.0 << ' ' << mdai[0][0][1] * -7.5 << endl;
}
It's as seamless as it would have been had I left it as an array reference.
For compile-time safety I wanted to have redeclare operator*() as, specifically;
Type& MDAI<Type, 0>::operator*()
so you could only call it on a <X, 0>
But I couldn't figure it out.
Similarly get operator[]() to only appear for dimensions greater than 0
Oh well, runtime checking will have to be good enough
Related
For context, this for a school assignment. I will attach a picture of the whole question, but to summarize the assignment, we have to make a RECURSIVE maze solver that will return the length of the path to solve the maze from start to finish, but we also have to input the path into an array, which is passed to the array by pointer. As far as I know, I cannot find the size of the array by pointer, and cannot figure out how to put the path into the array.
The question:
Function we have to fill:
int runMaze(Maze& theMaze, int path[], int startCell, int endCell){}
I believe I am properly traversing the maze via DFS and returning the right path length, but I am not sure how to properly input/remove values from the path[].
Is there any way I can know the size of the path[] and be able to push_back() and pop_back() its elements?
This is an example of how our functions are called:
bool test1(std::string& error) {
Maze theMaze("maze1.txt");
int path[10];
int pathLength = runMaze(theMaze, path, 0, 17);
int correctLength = 10;
int correct[10] = { 0, 1, 7, 8, 2, 3, 4, 5, 11, 17 };
bool rc = true;
if (!checkPath(path, pathLength, correct, correctLength)) {
rc = false;
if (pathLength != correctLength) {
error = "Error 1a";
error += ": runMaze() returned ";
error += std::to_string(pathLength);
error += ". It should have returned ";
error += std::to_string(correctLength);
}
else {
error = "Error 1b: runMaze() does not create the correct path\n";
error += "To see what is happening load the corresponding\n";
error += "test and test1path.txt file at: \n";
error += "https://seneca-dsa555-f21.github.io/dsa555-f21/\n";
}
}
printPath("test1path.txt", path, pathLength, 3, 6);
return rc;
}
There are a total of 10 tests it must pass.
Your questions:
Is there any way I can know the size of the path[]
No, there is absolutely no way you can determine the size of a raw array being passed to you without some sort of pre-determined terminator, such as \0 for character arrays.
A raw array as a parameter to a function end up just being a pointer to type. So your parameter is really just int* path, there is no size information included with this.
and be able to push_back() and pop_back() its elements?
There is no push_back() or pop_back() for raw arrays.
I am not sure how to properly input/remove values from the path[]
path[0] = 1;
So I'm following a certain tutorial series and trying to use that knowledge to put my own spin on something kindof both similar but also different to the series itself. In one section, to tackle a certain inconvenience which is not important for the scope of my issue, a possible solution was to store certain chunk of data into members of a struct and then call that struct onto a function that later output the data precisely the way we wanted - as an array.
All was well and good, until the function for some reason refused to take in values of the array, claiming there was an overload of information in the array arguments (I will specify the errors later), and that the entity I am returning does not match the function's return type.
Here's my code:
struct TriCoord
{
float Position[3];
int Label[2];
};
std::array<TriCoord, 3> Implement(float x, float y, float z, int j) //2
{
float size = 1.0f;
TriCoord f0;
f0.Position = { x, y, z }; //1
f0.Label = { j, 1 }; //1
TriCoord f1;
f1.Position = { x + 0.5, y + 0.5, z };
f1.Label = { j, 2 };
TriCoord f2;
f2.Position = { x + 0.5, y, z };
f2.Label = { j, 3 };
return { f0, f1, f2 }; //2
};
int main()
{
int X;
float A[3] = Implement(3, 4, 5, 1); //3
std::cout << A[0] << ", " << A[1] << ", " << A[2] << std::endl;
std::cout << "Press Enter key to return" << std::endl;
std::cin >> X;
return 0;
}
I've put comments locating specifically where the errors are.
1) The compiler says that f0 is "not a modifiable lvalue". I see no reason why it shouldn't be. In the array argument at specifically the second element of the array (in this case y), the compiler says that I am adding "too many initializer values". Again, makes no sense. I specified the Position array to have 3 elements and am plugging 3 elements of matching type (float).
These two errors extend to f0.Label, as well as the other TriCoords.
2) The compiler says that the function "returns incomplete type 'std::array'". Furthermore, in the return line, "list-initialization of an object type 'std::array' is not allowed because the type is incomplete".
Technically what I am returning is an std array whose elements are TriCoords and of amount 3, so I don't see the problem once again. I did work around this issue by changing the function's return type to float, but in its stead the return line generates the same error for the second element (in this case f1) as in problem 1.
3) "Initialization with '{...}' expected for aggregate object" I have no idea what this means. I get this error regardless of which return type I specify for my function.
I must emphasise that both me and the series I'm following are using Visual Studios and no such errors popped up in the video I was following. I even copy-pasted the entirety of the video's code line by line and the errors still persisted, leading me to the conclusion that there is something wrong in the way Visual Studios is configured on my end, possibly due to version differences (the video was uploaded this year so it's not running on too old of a version). All my dependencies are correct as well and are present in their respective project-based directories, I have double checked those.
Lastly, the code I used above was a separate testing code I redid on a new project in an attempt to isolate the error. Needless to say, I got the same error in both cases indicating there's nothing inherently wrong with the custom-defined headers and libraries of my original project.
1) You cannot assign into arrays like this once they are initialized.
int arr[3] = {1, 2, 3}; //valid
int arr2[3];
arr2 = {1, 2, 3}; //invalid
In your case, what you could do is instead of: -
TriCoord f0;
f0.Position = { x, y, z };
f0.Label = { j, 1 };
write: -
float tempFloat[3] = { x, y, z };
int tempInt[2] = { j, 1 };
TriCoord f0;
for (int i = 0; i < 3; ++i)
f0.Position[i] = tempFloat[i];
for (int i = 0; i < 2; ++i)
f0.Label[i] = tempInt[i];
2) Solve 1 to solve 2...
3) You are trying to assign std::array<TriCoord, 3> to a float array which is certainly not possible...
At this point, I would strongly advise you to use std::array everywhere.
I was looking through some coding problems and I've come across a problem where the input array is given as "int*" instead of vector.
This made me question how to iterate through this array if we didn't know the size:
vector<int> cellCompete(int* states, int days)
{
// my try:
for (; *states; states++ ) {
cout << *(states) << " ";
}
vector<int> testArray;
return testArray;
}
As you can see i've tried a simple way to iterate over the array, trying to check if the pointer would return nullptr at a point.
Example:
[1, 0, 0, 0, 0, 1, 0, 0] returned "1" as output
[1, 1, 1, 0, 1, 1, 1, 1] returned "1 1 1" as output.
However, this approach worked in the following example:
#include <iostream>
using namespace std;
int main () {
// an array with 5 elements.
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double *p;
p = balance;
for (; *p; p++ ) {
cout << *(p) << endl;
}
return 0;
}
This is the question https://www.geeksforgeeks.org/active-inactive-cells-k-days/ but I cannot share the link for where I've come across the question because it is confidential. In the version that I had to solve, the function input was "int*" instead of other options.
Extras:
On the same website, my approach worked for another question with similar input:
int generalizedGCD(int num, int* arr)
{
// WRITE YOUR CODE HERE
for (; *arr; arr++ ) {
cout << *(arr) << " ";
}
return 1;
}
where the input examples were:
[2, 3, 4, 5, 7] and [2, 4, 6, 8, 10]
Is there a more reliable way to iterate through a pointer to an array when we do not know the size of the array?
None of the sources I've found online give a way to iterate without knowing the size.
I wanted to express that this question did indicate the size of the array but it just made me think if there is a way to iterate without given size.
No, there isn't.
You either need to have some kind of a terminating character, like in null-terminated strings or explicitly provide the size.
Besides your approach does not work and is not safe.
*states will not tell you if your pointer is nullptr. operator* is dereferencing and taking value of the object referenced by the pointer. That is why your cycle stops once it hits a 0 value in your array. If you do not have any zeroes in the array, the cycle will go on until going out of the allocated space for you array, and you will have an unaddressable access resulting in undefined behavior, because you will be accessing memory, which could be used for something else, or even worse could be read-only or outside process's address space, causing a crash.
To take the actual value of the pointer (the address), you need to check states instead of *states, but it will not be nullptr. The value of the variable states is just some number(which is equal to the address of the memory where the array is written).
I don't use C that much and I recently got confused about 2d array initialization problem. I need to debug somebody's code and stuck in the following(her original code):
const int location_num = 10000;
bool **location_matrix;
if (node_locations)
{
location_matrix = (bool **)malloc(location_num*sizeof(bool *));
if (!location_matrix)
{
cout<<"error 1 allocating location_matrix" << endl;
exit;
}
for (i=0; i<location_num; i++)
{
location_matrix[i] = (bool *) malloc(location_num*sizeof(bool ));
if (!location_matrix[i])
{
cout<<"error 2 allocating location_matrix" << endl;
exit;
}
for (j=0; j<location_num; j++)
location_matrix[i][j] = false;
}
}
I thought is was redundant, so I changed it to the following:
location_matrix[location_num][location_num] = { {false} };
However, segmentation fault happens at runtime.
My question is: how does the above code fail? If it looks right, what's the difference between dynamically allocation and static allocation? Is it just because the dimension might not be constant, so we need to do it dynamically?
Also, just for curiosity, how do I malloc 2d array that stores pointers? Thanks.
The change would likely require about 100MB (10,000 * 10,000 * 1) on the stack, so the segmentation fault was likely due to a stack overflow.
Edit I originally stated 400MB in the answer, but #Mooing Duck points out bool will likely be 1 byte. I was thinking the Win32 BOOL (for no real reason at all), which is typedefed to an int.
I actually don't see anything wrong with the code.
The following code doesn't work because location_matrix is not allocated:
location_matrix[location_num][location_num] = { {false} };
GCC will allow the following (as an extension):
bool location_matrix[location_num][location_num] = { {false} };
But it will blow your stack because 10000 x 10000 is too large.
Currently, your code uses dynamic allocation. That's the correct way to do it because the matrix is too large to be done as a static array (and may overrun the stack).
As for your last question, "how to make a 2d array that stores pointers": It can be done almost the same way as your current code. Just change bool to int*.
So a 2D array of NULL int pointers will look like this:
int ***location_matrix;
if (node_locations)
{
location_matrix = (int***)malloc(location_num*sizeof(int**));
if (!location_matrix)
{
cout<<"error 1 allocating location_matrix" << endl;
exit;
}
for (i=0; i<location_num; i++)
{
location_matrix[i] = (int**) malloc(location_num*sizeof(int*));
if (!location_matrix[i])
{
cout<<"error 2 allocating location_matrix" << endl;
exit;
}
for (j=0; j<location_num; j++)
location_matrix[i][j] = NULL;
}
}
The standard library is your friend.
#include <vector>
int
main()
{
int location_num = 1000;
std::vector<std::vector<bool> > location_matrix(location_num, std::vector<bool>(location_num, false));
}
Second, the array is likely too large to fit on the stack, so you'd need to dynamically allocate it -- but you can simplify the code as long as the difference between a 2-dimensional array and an array of pointers won't be an issue (as it would be if you needed to pass the array to a function or use pointer arithmetic with it).
You could use something like this:
bool (*location_matrix)[location_num];
location_matrix = (bool (*)[location_num])calloc( location_num,
location_num * sizeof(bool) );
...which allocates space for the whole two-dimensional array and gives a pointer to an array of bool arrays with location_num elements each.
OK, I am trying to get a sub array from an existing array and I'm just not sure how to do it. In my example I have a very large array, but I want to create an array from the last 5 elements of the array.
An example of what I am talking about would be:
int array1 = {1,2,3,...99,100};
int array2[5] = array1+95;
I know this isn't correct, but I am having some trouble getting it right. I want to get the elements 96 through 100 in array1 and put them into array2 but I don't want to copy the arrays. I just want array2 to start at the 96 element such that array1[96] and array2[0] would be pointing to the same location.
for this:
"such that array1[96] and array2[0] would be pointing to the same location."
you can do:
int *arr2 = arr1 + 96;
assert(arr2[0] == arr1[96] == 97);
A reference hack from a C programmer willing to subvert the type system to get what works:
int (&array2)[5] = (int (&)[5])(*(array1 + 5));
Now array2 will be an array for all intents and purposes, and will be a sub-array of array1, and will even be passable to that famous C++ array_size template function. Though the best way to handle this hackery is to hide it with more hackery!
#define make_sub_array(type, arr, off, len) (type (&)[len])(*(arr + off));
int (&array2)[5] = make_sub_array(int, array1, 5, 5);
Nice. Terrible by some standards, but the end result a) looks pretty neat, b) does exactly what you want, c) is functionally identical to an actual array, and d) will also have the added bonus (or mis-feature) of being an identical reference to the original, so the two change together.
UPDATE: If you prefer, a templated version (sort of):
template <typename T, size_t M>
T (&_make_sub_array(T (&orig)[M], size_t o))[]
{
return (T (&)[])(*(orig + o));
}
#define make_sub_array(type, array, n, o) (type (&)[n])_make_sub_array(array, o)
int (&array2)[5] = make_sub_array(int, array1, 5, 5);
We still have to pass the type. Since one of our arguments must be used as part the cast, we cannot cleanly (IMHO) avoid the macro. We could do this:
template <typename T, size_t M, size_t N>
T (&make_sub_array(T (&orig)[M], size_t o))[N]
{
return (T (&)[N])(*(orig + o));
}
int (&array2)[5] = make_sub_array<int, 15, 5>(array1, 5);
But the goal here is to make the calling code as clean as possible, and that call is a bit hairy. The pure-macro version probably has the least overhead and is probably the cleanest to implement in this case.
You can use boost::iterator_range to represent "slices" of arrays/containers:
#include <iostream>
#include <boost/range.hpp>
int main()
{
int array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// Create a "proxy" of array[5..7]
// The range implements the concept of a random sequence containter
boost::iterator_range<int*> subarray(&array[5], &array[7]+1);
// Output: 3 elements: 5 6 7
std::cout << subarray.size() << " elements: "
<< subarray[0] << " "
<< subarray[1] << " "
<< subarray[2] << "\n";
}
Note that the iterator range "knows" about the size of the sub-array. It will even do bounds checking for you. You cannot get that functionality from a simple pointer.
The usefulness of Boost.Range will become more apparent once you learn about STL containers and iterators.
If you're into linear algebra, Boost.uBlas supports ranges and slices for its matrices and vectors.
For a completely different approach you could do something like.
vector<int> v0(array1 + 95, array1 + 100);
or
vector<int> v1(array1, array1 + 100);
vector<int> v2(v1.begin() + 95, v1.end());
This would make a real copy of the elements of your vector.
In C++ you can use an int pointer as an int array, so getting the array2 to start at item 96 in array1 is easy, but there isn't any way to give array2 a size limit, so you can do this
int array2[] = &array1[96];
or this
int *array2 = &array1[96];
but NOT this
int array2[5] = &array1[96]; // this doesn't work.
On the other hand, C++ doesn't enforce array size limits anyway, so the only real loss is that you can't use sizeof to get the number of elements in array2.
note: &array1[96] is the same thing as array+96
edit: correction - int array[] = &array[96] isn't valid, you can only use [] as a synonym for * when declaring a function parameter list.
so this is allowed
extern int foo(int array2[]);
foo (&array1[96]);
int array1[] = {1,2,3,...99,100};
int *array2 = &array1[96];
int arr[] = { 1, 2, 3, 4, 5};
int arr1[2];
copy(arr + 3, arr + 5, arr1);
for(int i = 0; i < 2; i++)
cout << arr1[i] << endl;
The code is not safe if the boundaries are not handled properly.
You said you don't want to copy the array, but get a pointer to the last five elements. You almost had it:
int array1[] = {1,2,3,...99,100};
int* array2 = &array1[95];