C++ Iterator range using pointers to an array - c++

Question
I do not want to pass the size of the array as an index parameter.
For my merge_sort, I want to optimize my parameters using the iterator range concept. I can't seem to figure out how to deference the iterator range and access my array. I can deference to access the indices like low and high in recursive_merge_sort, but there does not seem to be an intuitive way to access the array itself. I've been using this great guide on C++ Pointers and Arrays as a starting point.
My Merge Sort C++11 C++17 question brought this concept to light and I like the idea of using iterator ranges to reduce the number of parameters for my sort.
Code
void recursive_merge_sort(int* low, int* high) {
// deference to get starting index "low" and ending index "high"
if(*(low) >= *(high) - 1) { return; }
int mid = *(low) + (*(high) - *(low))/2;
// what's the correct syntax to access my array from the iterator range
// int* d = some how deference low or how to get the data array they iterate on
recursive_merge_sort_v(d + low, d + mid);
recursive_merge_sort_v(d + mid, d + high);
merge(d + low, mid, d + high);
// delete d;
}
void merge_sort(int* data) {
// what's the correct syntax to access my array from the passed in iterator range
// is this event possible? incorrect syntax below
recursive_merge_sort(data + 0, data + std::size(*(data)));
}
int main()
{
int data[] = { 5, 1, 4, 3, 65, 6, 128, 9, 0 };
int num_elements = std::size(data);
std::cout << "unsorted\n";
for(int i=0; i < num_elements; ++i) {
std::cout << data[i] << " ";
}
merge_sort(data);
std::cout << "\nsorted\n";
for(int i=0; i < num_elements; ++i) {
std::cout << data[i] << " ";
}
}
Comment section Solution from the bayou
Remy Lebeau: "When you pass an array by pointer, you lose all information about it. You can't get back to the original array given only a pointer/iterator, as dereferencing will only give you a single element of the array, not the array itself. When passing an array by pointer, you have no choice but to pass the array size as another parameter. Otherwise, pass the array by reference instead, and if you need to support arrays of different sizes then use a template so the compiler can deduce the array size for the reference."

Iterators are modeled to act like pointers. They have the same type of overloaded operators: dereferencing and increment at the very least (some also have decrement, random access, etc.).
The most advanced iterator interface is random access, which functions exactly like a raw pointer (by design).
So all (raw) pointers are basically random access iterators into a C-style (contiguous) array. Look at the following to visualize begin/end iterators for a C-style array:
int vals[] = { 0, 1, 2, 3, 4 };
int *begin = vals;
int *end = vals + 5;
v vals[]
0 1 2 3 4 ...
^ begin ^ end (1 past the end of array)
vals[2] == begin[2]
vals[4] == begin[4]
etc.
So basically, you just treat the begin iterator as the front of the array, and you just don't dereference anywhere before the begin iterator, nor at or past the end iterator, as standard C++ convention dictates the end iterator is 1 past the end of the range.
Here's an example of using pointers like iterators:
void print(int *begin, int *end)
{
// for each element in the range (starting at begin, up to but not including end)
for (; begin != end; ++begin)
{
// print the element
std::cout << *begin << '\n';
}
}
int main()
{
// declare a C-style array
int arr[] = { 10, 5, 2, 6, 20 };
// for the sake of example, print only the middle 3 elements
// begin = arr + 1
// end = arr + 4
print(arr + 1, arr + 4);
return 0;
}

Related

How does the Sort Function work and what its parameter denotes?

#include <bits/stdc++.h>
using namespace std;
int main()
{
int arr[] = { 1, 5, 8, 9, 6, 7, 3, 4, 2, 0 };
int n = sizeof(arr) / sizeof(arr[0]);
sort(arr, arr + n);
cout << "\nArray after sorting using "
"default sort is : \n";
for (int i = 0; i < n; ++i)
cout << arr[i] << " ";
return 0;
}
How the sort function works here? why the sort function just contains array name as 'arr' and not the index? What 'arr + n' doing?
std::sort is a function template, it operates on anything that satisfies RandomAccessIterator, which pointers do (being the archetypical iterator types). The two argument overload compares elements with <.
In an ordinary function call1, the name of an array is automatically converted to a pointer to the first element. This is called array to pointer decay. In particular, function templates will decay arrays to pointers when the type parameters are being determined.
arr + n calculates the pointer n elements into arr, which (in this case) is the special one-past-the-end element, which can be pointed to but not dereferenced. std::sort(first, last) on the half-open range [first, last).
Unless the function takes a reference-to-array parameter

how do i create dynamic array in cpp

I have this function:
void reverse(int* nums, unsigned int size)
This function is supposed to reverse the values in the array it is getting.
Now for reversing I thought to create another array with the size of the array passed in. Assigning this new one from the end of the original array to the start.
But I am a kind of new in C++, So I don't know how to create dynamic array in the size of the parameter of the function.
It's actually not necessary to allocate a new array here. See if you can find a way to solve this problem just by rearranging the existing elements in-place.
Given that this seems like it's an exercise with pointers, you can allocate space by using the new[] operator:
int* auxiliaryArray = new int[size];
You'd then free it by writing
delete[] auxiliaryArray;
However, this isn't the preferred way of doing this in C++. The better route is to use std::vector, which does all its own memory management. That would look like this:
std::vector<int> auxSpace(size);
You can then access elements using the square brackets as you could in a real array. To do this, you'll need to #include <vector> at the top of your program.
In C++, the recommended way to create an array of variable size would be to use an std::vector
#include <vector>
void reverse(int* nums, unsigned int size)
{
std::vector<int> V(size);
...
}
But that approach isn't the best here for performance because it requires additional memory to be allocated of the size of the array, which could be big. It would be better to start from the outside of the array and swap members one by one that are at mirroring positions (so if the size is 5, swap 0 and 4, then swap 1 and 3 and leave 2 alone). This only requires temporary storage of a single int.
You can do it without the need to create another array:
void reverse(int* array, const int size){
for(int i = 0; i < size / 2; i++){
int tmp = array[i];
array[i] = array[size - 1 - i];
array[size - 1 - i] = tmp;
}
}
int main(){
int array[] = {1, 3, 5, 7, 9, 11};
const int size = sizeof(array) / sizeof(array[0]);
reverse(array, size);
for(int i(0); i < size; i++)
std::cout << array[i] << ", ";
}
As you can see above in the loop you only need to swap the first element (element 0) with the n-1 element and the second one with n-1-1 and son on...
Remember arrays are indexed from 0 through n-1.
If you want to allocate new array which is not practical:
int* reverse2(int* array, const int size){
int* tmp = new int[size];
for(int i(size - 1), j(0); j < size; j++, i--)
tmp[j] = array[i];
return tmp;
}
int main(){
int array[] = {1, 3, 5, 7, 9, 11};
for(int i(0); i < size; i++)
std::cout << array[i] << ", ";
std::cout << std::endl;
int* newArray = reverse2(array, size);
for(int i(0) ; i < size; i++)
std::cout << newArray[i] << ", ";
std::cout << std::endl;
delete[] newArray;
return 0;
}
If you want to use a new array you can, but I think is to kill flies with a cannon.
Looks like you are using plain C code and not C++. I say that because of the signature of the function. The signature of the function in a common C++ code could be something like this other:
void reverse(std::vector& items);
You can reverse the current array without a new array, using the current one. You are passing the pointer to the first item of the array, and the content is not constant so that you can modify it. A better signature for the function could be:
void reverse(int* const nums, const unsigned int size);
Looks like a pointer problem. Think about the boundaries to iterate the positions of the array. Would you need to iterate the whole array? Maybe only half array? ;)
As bonus track, what about to exchange the values without an auxiliar variable? (this is true into this case that we are using the fundamental type int... remember the binary arithmetic).
array[pos_head] ^= array[pos_tail];
array[pos_tail] ^= array[pos_head];
array[pos_head] ^= array[pos_tail];

Issue finding size of dynamic int array that contains a zero

We are not allowed to use vectors.
Another noobie with a problem. I am trying to find the index of a dynamic int array that is initialized to a size of 50. We can only use a dynamic int array.
Say for example I’m only entering 10 integers into this array: 1 9 5 3 8 0 8 2 0 6
The rest of the array is NULL. The goal is to keep the integer values that were entered into this array and put them into an output file. So the size of the array of ints I want is 9. But when I do the following:
int index = 0;
while (intArray[index])
{
index++;
}
It tells me that the index is 5 and thus only 5 values get copied into the output file. I know it’s because of the 0 in the array. If there is no 0 in the array, the results come out as expected. How do I bypass this so that the index is correctly reflected as 9 and all the values get copied properly? I appreciate any input!
As pointed out in the comments the best approach here, given that you cannot use std::vector (*sigh*), is to make your own minimal dynamic_array (mimicking a std::vector) which knows its own size at all times.
It's interface could look something like this:
template<typename _Ty>
class dynamic_array {
public:
typedef _Ty value_type;
typedef const _Ty& const_reference;
typedef _Ty& reference;
typedef std::size_t size_type;
//... other necessary typedefs
dynamic_array() : arr(), arr_size(0), allocated_size(0) {}
dynamic_array(size_type n) : arr_size(n), allocated_size(n) { allocate(n); }
~dynamic_array() { delete arr; }
size_type size() const noexcept { return arr_size; }
const_reference operator[](size_type n) const { return arr[n]; }
reference operator[](size_type n) { return arr[n]; }
void push_back(const value_type& _val) {
++arr_size;
// actual implementation of pushing back _val up to you
}
private:
value_type* arr;
size_type arr_size; // number of elements
size_type allocated_size; // actual number of allocated elements in memory
void allocate(size_type n) { arr = new value_type[n]; }
};
Then to iterate through this via indices you would simply do:
dynamic_array<int> darr;
// populate darr
for (int i = 0; i < darr.size(); ++i) {
// do stuff with each element accessing via: darr[i] as before
}
Edit - If you can use std::unique_ptr then use this instead of the raw pointer value_type* arr to avoid any potential memory management headaches.
There is no such thing as NULL for integer value. So there are 3 usual approaches, that used:
Special value, marker of the end. This aproach is used for C-style strings, where '\0' used as end. For integer this approach will not work as 0 is "normal" value. You may use some other special value, like std::numeric_limits<int>::min or std::numeric_limits<int>::max, but this would be not very good approach.
Have another variable, that holds current size of array. Note this is usually different, than for how many elements were allocated. This could be wrapped into a class. This is how std::vector is implemented.
Have another variable, pointer, that points to the pone element after the last one. This could be useful for using in standard algorithms.
Approach 2 and 3 are very close and one can be converted very easy to another. So I would recommend to rewrite your algorithm using start and behind_end iterator:
auto end = myArray + 5; // 5 elements in array
for( auto it = myArray; it != end; ++it ) {
std::cout << *it << endl;
}
this code can be easily templatized and used with standard containers.
You could do something like this only if you are sure that the input data are not negatives:
#include <iostream>
int main()
{
int MyArray[50]; // declare your array
// ..
for (int i = 0; i < 50; i++)
MyArray[i] = -1; // fill with negatives
MyArray[0] = 0; // some data
MyArray[1] = 10; // some data
for (int i = 0; i < 50; i++)
{
if (MyArray[i] >= 0 )
{
std::cout << MyArray[i];
// write to your file
}
}
//..
return 0;
}
boost::static_vector would help here. It is essentually a cross between vector and array: either a stack-allocated vector with fixed capacity or uninitialized array with some facilities to track logical size.
Example of use:
#include "boost/container/static_vector.hpp"
#include <iostream>
namespace cnt = boost::container;
void foo()
{
cnt::static_vector<int, 50> buf = {1, 9, 5, 3, 8, 0, 8, 2, 0, 6,};
std::cout << buf.size();
}
int main()
{
foo();
}

Where is the flaw in my logic that is causing an infinite loop?

I'm trying out "code golf" type problems to prepare for interviews. At the moment I'm trying to do the one where you move the odd elements of an array to the back (without necessarily preserving the order). I've looked over my logic many times and can't think of any case that could cause an infinite loop. However, I'm getting a Timeout when I try to run it. I've commented out my thought process for you to see.
#include <iostream>
void int_swap (int *pi1, int *pi2)
{
int temp = *pi1;
*pi1 = *pi2;
*pi2 = temp;
}
void odds_to_back (int *arr, size_t n)
{
int * end = arr + n; // get pointer to 1 off the end of the array
if (arr == end) return; // handle case of empty array
--end; // move pointer to last element of the array
while (arr != end)
{
if (*arr % 2) // if first pointer is odd
{
if (!(*end % 2)) // if second pointer is even
{
int_swap(arr, end); // swap first and second
++arr; // increment first
}
else // second pointer is odd
{
while ((*end % 2) && arr != end) --end; // move second pointer towards first until second pointer is even or hits the first
}
}
else // if first is even
{
++arr; // increment first
}
}
}
int main ( )
{
int myArray [] = {1, 3, 5, 6, 19, 1, 2, 2};
size_t N = sizeof(myArray)/sizeof(int);
odds_to_back(myArray, N);
for (size_t i = 0; i < N; ++i) std::cout << myArray[i] << " ";
return 0;
}
Oh, that is a hard one. You are calling swap (arr, end) and not your own int_swap. So, at least with my test code the function std::swap which is changing the pointers (and not the values pointed to) is called.
Changing the call to your int_swap looks promising.

using only part of an array

I have a dynamically allocated array of float and I need to pass this array as an argument to three different functions but each function need to get a different range of the array. Is there some way I can send the array with elements 0 to 23 to one function, elements 24 to 38 to another, and elements 39 to 64 to a third function.
In some languages(like python I think) you can do something like this:
somefunction(my_array[0:23]);
somefunction(my_array[24:38]);
somefunction(my_array[39:64]);
However I am using c++ and I am not aware of any way to do this in c++.
Does anybody know how to do this?
somefunction(); is a function from an API so I can not modify the arguments it takes.
If you write the functions to operate on a pair of forward iterators rather than an array, you could just pass it like so:
somefunction1(my_array, my_array + 24);
somefunciton2(my_array + 24, my_array + 39);
somefunction3(my_array + 39, my_array + 65);
Pointers are forward iterators, and this would allow the functions to be used over parts of vectors, queues, or other STL containers as well.
The python example is making copies. If that's okay for your use case, you could do something like this (I'm swapping out your vanilla arrays for std::vector):
#include <iostream>
#include <vector>
void somefunction(std::vector<int> v) {
std::cout << "vector has " << v.size() << " elements,"
<< " first value is " << *v.begin() << ","
<< " last value is " << *(v.end()-1) << std::endl;
}
int main() {
std::vector<int> a;
for (int i=0; i<65; i++) {
a.push_back(i);
}
somefunction(std::vector<int>(a.begin(),a.begin()+23));
somefunction(std::vector<int>(a.begin()+24,a.begin()+38));
somefunction(std::vector<int>(a.begin()+39,a.begin()+65));
}
which outputs:
vector has 23 elements, first value is 0, last value is 22
vector has 15 elements, first value is 23, last value is 37
vector has 27 elements, first value is 38, last value is 64
But it sounds like you can't use std::vector, because somefunction() has a signature you can't change. Luckily, you can do similar gymnastics just manually copying parts of the array, as below:
#include <iostream>
#include <string.h>
void somefunction(int v[], int len) {
std::cout << "vector has " << len << " elements,"
<< " first value is " << v[0] << ","
<< " last value is " << v[len-1] << std::endl;
}
int main() {
int a[65];
for (int i=0; i<65; i++) {
a[i] = i;
}
int b[23];
memcpy(b, a, 23*sizeof(int));
somefunction(b, 23);
int c[15];
memcpy(c, a+23, 15*sizeof(int));
somefunction(c, 15);
int d[27];
memcpy(d, a+38, 27*sizeof(int));
somefunction(d, 27);
}
which again outputs:
vector has 23 elements, first value is 0, last value is 22
vector has 15 elements, first value is 23, last value is 37
vector has 27 elements, first value is 38, last value is 64
Your function is going to need some way to determine the size of the array anyway. I suggest you make the function take begin and end iterators, in the style of the standard library algorithms, like so:
template<typename I>
void somefunction(I begin, I end);
Then, you can call it with your array like this:
somefunction(my_array, my_array + 24);
somefunction(my_array + 24, my_array + 39);
somefunction(my_array + 39, my_array + 65);
There are two ways you could do it:
void useArray(int array[], size_t len) { ... }
...
useArray(myArray, 24);
useArray(&myArray[24], 15);
useArray(&myArray[39], 26);
OR
void useArray(int *start, int *end) { ... }
...
useArray(myArray, myArray + 24);
useArray(myArray + 24, myArray + 39);
useArray(myArray + 39, myArray + 65);
The first is more of a C way, the second a more C++ way. Note that with the second way, the range is [start, end) - end isn't included in the range as you see a lot in C++.
EDIT: You edited your post to mention that you're using glTexCoordPointer(). In that case pass the start of the array to glTexCoordPointer(), which will be either myArray, myArray + 24 or myArray + 39.
The size of the array still has to be known though, and is passed to functions such as glDrawArrays or glDrawElements(), which will then start reading from the array. If you were using glDrawArrays(), the length of the array is passed as the second argument. Therefore your code could be something like:
glTexCoordPointer(..., ..., ..., my_array);
...
glDrawArrays(..., 0, 24);
glTexCoordPointer(..., ..., ..., my_array + 24);
...
glDrawArrays(..., 0, 15);
glTexCoordPointer(..., ..., ..., my_array + 39);
...
glDrawArrays(..., 0, 26);
There is no upper bound range checking, so you have to take care of that yourself. But you can pass &my_array[0] to one function, and &my_array[24] to another. Maybe add a len parameter to your function to take care of upper range.
You could refactor your functions to use 'iterators': a pointer to the begin and to the end of the array-range you're interested in:
void somefunction( int* begin, int* end ) {
for( int* i=begin; i != end; ++i ) {
//stuff with *i
}
}
// usage:
somefunction( my_array+0, my_array+23 );
somefunction( my_array+24, my_array+38 );
somefunction( my_array+39, my_array+64 );
Bonus points: if you make your function a template, you can use it with other iterators too:
template<typename T>
void somefunction( T begin, T end ) {
for( T i=begin; i != end; ++i ) {
//stuff with *i
}
}
vector<int> values(100);
somefunction( values.begin(), values.end() );
somefunction( values.rbegin(), values.rend() );
...
I would return or do something like std::pair<pointer_type, pointer_type> which contains {Begin_Pointer, End_Pointer} so, Let's if we need to slice a raw array(in C/C++ land just a pointer) with specific parts/blocks. I would return take something like
pointer_type element_begin = raw_array+begin;
pointer_type element_end = raw_array+end;
std::pair<pointer_type, pointer_type> = std::make_pair(element_begin, element_end);
I will have a convenient function to which I give those begin and end non-negative values and it will return me a std::pair