c++ "push_back" and "pop_back" for array passed by pointer - c++

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;

Related

How do I measure the length of an int array in C++?

My goal is to print all elements of an array of integers regardless of its length. I would like to print it in Python list format, but then I got this error.
Here is my code
int measure(int n[])
{
int num=0;
while (n[num]) { num++; }
return num;
}
void show(int n[])
{
int a = measure(n);
for (int i=0; i<a; i++) {
if (i==0) { printf("[%d,",n[i]); }
else if (i==a-1) { printf(" %d]",n[i]); }
else { printf(" %d,",n[i]); }
}
}
int main(void)
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
show(arr);
}
It is supposed to print this: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
but I got this instead: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1935094528, -1664206169]
then I replace show() with this:
int i=0;
while (n[i]) {
if (i==0) { printf("[%d,",n[i]); i++; }
else if (n[i+1] == NULL) { printf(" %d]",n[i]); break; }
else { printf(" %d,",n[i]); i++; }
}
and then I got these:
main.cpp:23:28: warning: NULL used in arithmetic [-Wpointer-arith]
23 | else if (n[i+1] == NULL) { printf(" %d]",n[i]); break; }
| ^~~~
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -680101376, -1228044632]
Why does this happen?
How do I measure the length of an int array in C++?
You can use std::size to get the size of an array with known size:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
std::cout << std::size(arr);
Why does this happen?
Because the continue condition for your loop is "while the element is not 0". There are no elements with the value 0, so the loop doesn't end before exceeding the end of the array, at which point your overflow the array and the behaviour of the program becomes undefined.
The parameter n of the functions measure and show is not an array of known size. Since n isn't an array of known size, you cannot use std::size to get its size. In fact, although it looks like an array of unspecified size, n is adjusted to be a pointer to element of such array. There is no general way to measure the size of an array given a pointer to its element.
In cases where you want to pass array of any size into a function, and also need to know the size of the array within the function, a good solution is to use a span parameter:
void show(std::span<int> n)
There simply is no "measuring" the length of arrays in C++. You have to know up front, and pass that info to any functions or methods you pass the array to. You can also use a specific "tag" value (as you have implicitly done here) but if you do that, you have to set the tag yourself, and that means you have to know the array length to set the tag. And you must be very sure that the tag does not equal any valid data value in your array.A different approach would be to use std::vector instead of an array. That data type gives you all the functionality of an array but also provides variable length arrays and the ability to inquire the current length.

How to iterate over a pointer to an array (int*) when size is not known?

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).

Passing an array into a function c++

so I'm having an issue passing an entire array of histograms into a function in C++
the arrays are declared like this
TH1F *h_Energy[2];
h_Energy[0] = new TH1F("h1", "h1", 100, 0, 100);
h_Energy[1] = new TH1F("h2", "h2", 100, 0, 100);
And here is what I'm trying to do in the function:
void overlayhists(TH1 *hists, int numhists) {
int ymax = 0;
for (int i=0; i<numhists; i++) {
if (hist[i].GetMaximum() > ymax) {
ymax = (hist[i].GetMaximum())*1.05;
}
}
}
And I'm passing the function an array like this
overlayhists(*h_Energy, 2);
Where h_Energy is an 1D array with 2 elements. The code will run through the first histogram in the loop but as soon as it starts the second loop and tries to access hist[i].GetMaximum() on the second try it segfaults.
What gives?
This creates an array of pointers to type TH1F
TH1F *h_Energy[2]; //edited after OP changed
If you want to use this, and subsequently pass it as an argument
You must first initialize it, and then create your function prototype to accommodate:
void overlayhists(TH1F **hists, int numhists);
^^
From what you have shown above, you would call it like this: (after your initializations)
h_Energy[0] = new TH1F("h1", "h1", 100, 0, 100);
h_Energy[1] = new TH1F("h2", "h2", 100, 0, 100);
overlayhists(h_Energy, 2);
1. Passing any array to function in c++ to change the content:
Refer to this code snippet:
//calling:
int nArr[5] = {1,2,3,4,5};
Mul(nArr, 5);
Whenever you pass an array to function you actually pass the pointer to first element of the array. This is implicit to C++ and C. If you pass normal value(non array) it will be considered as pass by value though.
// Function Mul() declaration and definition
void MUl(int* nArr, size_t nArrSize){
size_t itr = 0;
for(;itr<nArrSize; itr++)
nArr[i] = 5*nArr;// here we've coded to multiply each element with 5
}
2. Passing any Ptr to function in c++ to change what pointer is pointing to:
Now let us suppose we want to copy nArr (from above code snippet) to another array, say nArrB
The best way for a beginner would be to use reference to the pointer.
You can pass reference to the pointer to your function
//so we had
int nArr[5] = {1,2,3,4,5};
int *nArrB;
Here we don't know the gonnabe size of nArrB.
to copy nArr to nArrB we have to pass nArr, address of pointer to nArrB(or reference to pointer of nArrB or pointer to pointer of nArrB) and size of array.
Here is the implementation.
//Calling
CopyNArr(nArr, &nArrB, 5);
//Function implementation
void CopyNArr(int* nArr, int* & nArrB, size_t nArrSize) {
// dymanically allocating memory size for array. Assuming 4 byte int size
nArrB = new int[nArrSize*4];
size_t itr = 0;
//Copying values
for(;itr<nArrSize; itr++)
nArrB[i] = nArr[i];
}
//After copy nArrB is pointing to first element of 5 element array.
I hope it helped. Write for any further clarification.
You have an array of size 2, but you've created only one element. And that one with a wrong index. Array indexing starts with 0.
The elements should be at h_histogram[0] and h_histogram[1].
I am sorry if this answer is completely irrelevant but
I am tempted to post it. These is an experiment I have
done after seeing your question.
#include<iostream>
using namespace std;
main()
{
int e[2]={0,1};
int *p[2];
int i;
/*
Printing the array e content using one pointer
from an array of pointers. Here I am not using p[2]
at all.
*/
p[1]=e;
cout<<"Elements of e are : \n";
for(i=0;i<2;i++)
{
cout<<*(p[1]+i)<<endl;
/*
In the above line both *((*p)+i) and *(p+i)
won't serve the purpose of printing the array values.
*/
}
/*Printing the array e content using pointer to array*/
cout<<"Elements of e are : \n";
for(i=0;i<2;i++)
{
cout<<*(e+i)<<endl;
}
/*Note that pointer to array is legal but array TO pointer
(don't confuse with array OF pointers) is not.*/
}
Hope this will refresh your understanding.

How to get VC++ to access a pointer as a 2D array

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

FIXED Trying fix broken code on reversing an array

So I got this code sample that needs fixing. From what I can gather it takes an array, reverses it and then counts all the elements within it. Here is the code.
//-------------------------------------------------------------------
void ReverseTheArray( const short *pArrayStart, const int nArrayByteLength )
{
const short *pArrayEnd = (pArrayStart + nArrayByteLength);
while(pArrayStart != pArrayEnd)
{
short tmp = *pArrayStart;
*pArrayStart = *pArrayEnd;
*pArrayEnd = tmp;
pArrayStart++;
pArrayEnd--;
}
}
//-------------------------------------------------------------------
int CountTheArrayContents( const short *pArrayStart, int nNumEntries )
{
assert(nNumEntries-- > 0);
int nCount = 0;
for(unsigned uArrayIndex = nNumEntries; uArrayIndex >= 0; uArrayIndex--)
{
nCount += pArrayStart[uArrayIndex];
}
return nCount;
}
const short g_nSomeNumbers[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
};
//-------------------------------------------------------------------
int main()
{
short *pDataArray = new short[10];
memcpy(pDataArray, g_nSomeNumbers, sizeof(g_nSomeNumbers));
ReverseTheArray(pDataArray, 10*sizeof(short));
int nCount = CountTheArrayContents(pDataArray, 10);
printf("Sum total is %0.02f\n", nCount);
return 0;
}
I have ideas of what the problems are but can't seem to figure out a simple solution to the problem, one that doesn't require rewriting the entire code. If anyone can read this and see how the errors can be fixed it would be much appreciated.
I'm going to mention some things that I think are causing problems.
All the parameters and the pArrayEnd variable in the ReversTheArray() function are all const but are trying to be changed within the while loop, which is throwing an error. Should the const's be removed? Is there a reason const's would be used for this?
If the const's are remove a runtime error happens when trying to run the for loop in the CountTheArrayContents() function expressing an unhandled exception and saying "Access violation reading location 0x003DFFFE". Drawing a complete blank on that one.
Again any help on the code would be very much appreciated and I couldn't thank you guys enough.
PS. This is a challenge to create a reverse and accumulate function so I'm looking for a fix for the code and not a removal of the two functions. Thank you
PSS. Thanks to everyone who answered. I'm glad I did this (this being the first problem that I've posted about myself) and you've all been a huge help. I've got to say I've learnt alot.
Adding the actual length in bytes will add too many because pointer arithmetic is defined in terms of units of the size of the type pointed to. That is, pArrayEnd becomes &pDataArray[10 * sizeof(short)] instead of &pDataArray[10]. You don't need to multiply by sizeof(short) when calling the reversal function. Alternatively, you can divide nArrayByteLength by sizeof(short) when calculating the initial value of pArrayEnd.
The second issue is the fact that you only have 10 elements (0..9) allocated, meaning &pDataArray[10] would be one element beyond the array. The reversal function then tries to assign data to this unallocated area of memory, which can cause problems. The function should initialize pArrayEnd as shown, but immediately after, it should decrement pArrayEnd by 1. This way you won't be assigning to memory that might not belong to you. Beware of pArrayStart == pArrayEnd before you decrement pArrayEnd. An alternative test would be to ensure nArrayByteLength != 0.
Another problem is if the array has an even number of elements, and you try to do a reversal. If it does have an even number (like 10), pArrayStart will point to pDataArray[4], pArrayEnd will point to pDataArray[5], and after the data is assigned, pArrayStart++ will make pArrayStart point to pDataArray[5] and pArrayEnd-- point to pDataArray[4]. Then (6,3), (7,2), (8,1), (9,0), ... In other words, pArrayStart will never be equal to pArrayEnd in such a case. Instead, you should ensure that pArrayStart < pArrayEnd.
Hope this helps!
Also, any reason for not using std:: reverse? Just wondering.
Edit
The accumulation function can be rewritten as the following, which will avoid the issue with the assert macro while doing the same thing:
int CountTheArrayContents( const short *pArrayStart, int nNumEntries )
{
int count = 0;
assert(nNumEntries);
while (nNumEntries--)
count += pArrayStart[nNumEntries];
return count;
}
Hopefully count doesn't overflow.
If all you're trying to do is reverse the contents of the array and accumulate the result, std::reverse and std::accumulate will do the trick (per the suggestion by #chris). Here's an example, which maintains the dynamically allocated short*. A better solution would use std::vector or std::array.
#include <algorithm>
#include <numeric>
#include <stdio.h>
#include <memory.h>
const short g_nSomeNumbers[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
};
int main()
{
short *pDataArray = new short[10];
memcpy(pDataArray, g_nSomeNumbers, sizeof(g_nSomeNumbers));
std::reverse(pDataArray, pDataArray+10);
int nCount = std::accumulate(pDataArray, pDataArray+10, 0);
for( size_t i=0; i<10; ++i )
printf("%d ", pDataArray[i]);
printf("\n");
printf("Sum total is %d\n", nCount);
delete [] pDataArray;
return 0;
}
This prints
9 8 7 6 5 4 3 2 1 0
Sum total is 45