Passing a reference to an offset position in an STL vector - c++

I'm trying to convert some old C functions to C++. My original programme stores a matrix in a single array, and I just pass a pointer to the first element to a function so that I am working on the correct row, e.g.
double f1(int *a){
return a[0] + a[1];
}
int main(void){
int x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(i = 0; i < 5; i++){
printf("%d\n", f1(&x[2 * i]));
}
I would like to be able to do something similar using the STL without copying. So my programme would look something like this
double f1(vector<int>& a){
return a[0] + a[1];
}
int main(void){
int x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
vector<int> y(x, x + 10);
for(i = 0; i < 5; i++){
cout << f1(y) << endl; // This is clearly wrong
}
How would I do this? I could change my function to receive a reference to a vector::iterator I guess, but is there another way?

You could simply pass an iterator to the function. Random access iterators are very similar to pointers (in fact, pointers qualify as random access iterators.) For example,
#include <vector>
double f1(std::vector<int>::const_iterator a)
{
return a[0] + a[1];
}
#include <iostream>
int main()
{
vector<int> y{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto it = y.cbegin();
for(int i = 0; i < y.size()/2; ++i)
std::cout << f1(it + 2*i) <<std::endl;
}

Write array view. An array view is a pair of pointers with begin end size empty, operator[], front and back methods, and constructors from C arrays, std::array<T,N>&, std::vector<T,A>&, std::vector<non_const_T,A>const&, std::array<non_const_T,N>const&, std::initializer_list<non_const_T>, etc.
Oh, and T*,size_t and T*,T* ctors, which are great for slicing (use forwarding ctors: T*,size_t->T*,T*, and everything else to those 2).
It does not own its data, so all of its methods are const except operator=. (non-const methods would be methods that change the view range -- changing the elements is a const operation on a view).
Then
double f1(array_view<const int> a){
return a[0] + a[1];
}

You don't need to make so many changes:
double f1(int *a)
{
return a[0] + a[1];
}
int main(void)
{
vector<int> y = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i = 0; i < 5; i++) {
cout << f1(&y[2 * i]) << endl;
}
}

Related

C++ generalize two dimension array in function

I want to write a function in C++ that take a matrix of any size and print it.
my code is as follows and it works. But my questions:
1) Is it the best practice?
2) Why casting using (int *) works but static_cast<int *> does not?
Thanks
#include <iostream>
using namespace std;
void print_matrix(int *, int, int);
int main()
{
int mat[3][3] = {{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int mat2[5][5] = {{1, 2, 3, 40, 50},
{4, 5, 6, 70, 80},
{7, 8, 9, 10, 20},
{17, 18, 19, 10, 20},
{71, 81, 91, 110, 120}
};
print_matrix((int *)mat2, 5, 5);
cout << endl;
print_matrix((int *)(mat), 3, 3);
cout << endl;
// static cast does not work:
// error: invalid static_cast from type 'int [3][3]' to type 'int*'|
// print_matrix(static_cast<int *>(mat), 3, 3);
return 0;
}
void print_matrix(int *matPtr, int row, int col)
{
for(int i = 0; i < row; i++) {
for(int j = 0; j < col; j++)
cout << *(matPtr + col * i + j) << '\t';
cout << endl;
}
}
Is it the best practice?
No, it is not.
It will be better to use a function template.
template <size_t NR, size_t NC>
void print_matrix(int (&matrix)[NR][NC])
{
...
}
and call it as:
print_matrix(mat2); // NR and NC are deduced by the compiler
Why casting using (int *) works but static_cast<int *> does not?
Given
int mat[3][3] = { ... };
the following pointers have the same numerical value even though the pointers are of different types.
int (*p1)[3][3] = &mat;
int (*p2)[3] = &mat[0];
int *p3 = &mat[0][0];
Because of this coincidence, use of (int*) works.
Using static_cast<int*> does not work because when a 2D array decays to a pointer, it does not decay to int* -- mat decays to int (*)[3] (pointer to an "array of 3 ints") and mat2 decays to int (*)[5] (pointer to an "array of 5 ints"). They cannot be cast to int* in general.

Rotate array to right instead of left

I have some code that rotates a number array to the left but instead, I need it to rotate it to the right. There is other code online that rotates array to the right but that code lets you only rotate numbers in the middle of the array.
I have tried decrementing the loops differently & and changing where its initialized but doesn't seem to rotate the correct way.
Expected output: if array is this {1, 2, 3, 4, 5, 6, 7}. Then it should look like: {7, 1, 2, 3, 4, 5, 6}
Current output: {2, 3, 4, 5, 6, 7, 1}
#include <iostream>
using namespace std;
/*Function to left Rotate arr[] of size n by 1*/
void leftRotatebyOne(int arr[], int n);
/*Function to left rotate arr[] of size n by d*/
void leftRotate(int arr[], int d, int n)
{
int i;
for (i = 0; i < d; i++)
leftRotatebyOne(arr, n);
}
void leftRotatebyOne(int arr[], int n)
{
int i, temp;
temp = arr[0];
for (i = 0; i < n-1; i++)
arr[i] = arr[i+1];
arr[i] = temp;
}
/* utility function to print an array */
void printArray(int arr[], int size)
{
int i;
for(i = 0; i < size; i++)
cout << arr[i] << " ";
}
/* Driver program to test above functions */
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7};
printArray(arr, 7);
leftRotate(arr, 1, 7);
cout << "___" << endl;
printArray(arr, 7);
getchar();
return 0;
}
leftRotateByOne is the key function here. The others can stay the same. Have a look at what it is doing, preferably with a pen and paper to keep track of the operations:
Keeps a copy of the first element.
Moves all elements to the "left" (that is, to the element with index
one less), being careful not to overwrite anything you need later.
Puts the first element in the last place.
So you need to do the opposite:
Keep a copy of the last element.
Moves all elements to the "right" (that is, to the element with index
one more), being careful not to overwrite anything you need later.
Puts the last element in the first place.
For example:
void rightRotatebyOne(int arr[], int n)
{
int i, last;
last = arr[n-1];
for (i = n-1; i > 0; i--)
arr[i] = arr[i-1];
arr[0] = last;
}

set multiple array variables at the same time (c++)

I'm trying to make an ASCII art using C++, and having some problems in arrays.
Is there any way to set multiple array variables at the same time?
Let me be more specific.
When you initialize an array, you can do this way.
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
By the way shown above, you can set 10 array variables at the same time.
However, I want to (re) set some of the array variables like this?
a[1] = 3;
a[4] = 2;
a[5] = 2;
a[7] = 2;
Since there is NO rule in the variables, I can't do
for(int i=0; i<10; i++) a[i] = i+1;
fill(n);
I can't use an for statement or the fill, fill_n function, since there is no regularity.
To sum up,
Is there any way to set more than 1 array variables at the same time? (Like the second code snipplet above?
Given a index-value mapping list, and assign it one by one.
template<typename T, size_t N>
void Update(T(&arr)[N], const std::vector<std::pair<size_t, T>>& mappings)
{
for (const auto& mapping : mappings)
if(mapping.first < N)
arr[mapping.first] = arr[mapping.second];
}
int main()
{
int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Update(arr, { {1, 3}, {4, 2}, {5, 2}, {7, 2} });
return 0;
}
As far as I'm aware without a pattern a control structure is kind of redundant, you might be better served reading from a file.
// for user input
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
for (int i = 0; i < 10; i++) {
cout << "Please input your value for array index " << i << endl;
cin >> arr[i];
}
// for manual input in initalization
int arr[10] = { 0, 3, 2, 2, 2, 5, 6, 7, 8, 9 };
However a better approach might be to read it from a file, http://www.cplusplus.com/forum/general/58945/ Read "TheMassiveChipmunk"'s post there for exactly how to do it.
Assuming you know which indices you will be changing upfront you can use a separate index array:
int ind[4]= {1,4,5,7};
..and an accompanying array with values
int new_val[4] = {3,2,2,2};
The you can use the following for loop to assign the values:
for (int i=0; i<4; i++)
arr[ind[i]] = new_val[i];
You should also use some variable signifying the number of indices to be changed like int val_num = 4 instead of plain number 4.
Changes that are defined in runtime to an array can be easily implemented by using a list to save tuples that represent the changes you want to make. As an example, we can write:
#include <tuple>
#include <list>
#include <iostream>
using namespace std;
typedef tuple <int, int> Change;
int main() {
int a[5] = {1,2,3,4,5};
list<Change> changes;
//represents changing the 2-th entry to 8.
Change change(2,8);
changes.push_back(change);
for(auto current_change: changes)
a[get<0>(current_change)] = get<1>(current_change);
cout << a[2] << '\n';
}
Prints 8.

Array Split in C++

I am trying to split an array, and this is how I am doing it:
int arr1[] = {1, 2, 3, 4, 5};
int *arr2 = arr1 + 1;
Now I need to do this in a loop. In every iteration, I am trying to decrease the size of the array by 1 element or 2 elements based on a condition. For obvious reasons I can't declare int arr2[some_variable] .
But I want a new array to be created in every iteration of the loop whose size is 1 less than its parent array. I am not sure how I can achieve this. Can anyone help please?
In Java, there is a function which can do this: int newArr[] = Arrays.copyOfRange(arr, 1, arr.length); I wanted something similar to this in C++.
Use std::vector<int> from the C++ standard library:
#include <string>
#include <iostream>
#include <vector>
void dump(std::vector<int> &v)
{
for (std::vector<int>::iterator it = v.begin(); it != v.end(); it++)
std::cout << *it << " ";
}
int main()
{
int a[] = { 1, 2, 3, 4, 5 };
std::vector<int> v(a, a + 5);
std::vector<int> v2(v.begin() + 1, v.begin() + 4);
dump(v);
std::cout << std::endl;
dump(v2);
}
And if you really-really-really can't use vector (why, seriously?), then just memcpy.
int arr[] = { 1, 2, 3, 4, 5 };
int cp[3];
memcpy(cp, arr + 1, sizeof(cp));
I'm not sure exactly why you want to have a new one each time, but you can use a standard container, like std::vector:
std::vector<int> arr1{1, 2, 3, 4, 5}; //std::iota is another option
int index{};
/*loop header*/ {
//make sure arr1.size() is at least 1
std::vector<int> arr2(std::next(std::begin(arr1), ++index), std::end(arr1));
}
I use std::next because it works in more scenarios. All this does is create a vector from two iterators: as far past the beginning as necessary, and the end (one past because it's exclusive).
Though C++11 is nice, it's not always a reality. In that case, this should work:
int arr1temp[] = {1, 2, 3, 4, 5};
std::vector<int> arr1(arr1temp, arr1temp + sizeof(arr1temp)/sizeof(arr1temp[0]));
int index = 0;
/*loop header*/ {
//make sure arr1.size() is at least 1
std::vector<int>::iterator start = arr1.begin();
std::advance(start, ++index);
std::vector<int> arr2(start, arr1.end());
}
/why/ do you think you need to make a copy of the array? Pointers and arrays are somewhat interchangeable, so all you need to do is track size and modify that.
void doSomethingWithArray(int* array, size_t arraySize) {
....
}
const size_t arraySize = 5;
int arry1[arraySize] = { 1, 2, 3, 4, 5 };
int* array = arr1;
int* arrayEnd = arr1 + arraySize;
for (int i = 0; i < 10; ++i) {
if ((*array) & 1 == 1) {
array += 1;
} else {
array += 3;
}
if(array >= arrayEnd)
break;
size_t howBigIsMySlice = arrayEnd - array;
if(howBigIsMySlice > && (rand() % 1) == 0)
howBigIsMySlice -= 1;
doSomethingWithArray(array, howBigIsMySlice);
}
You made no copies of data, and as far as "doSomethingWithMyArray" is concerned, the array is as big as we tell it.

array copy reversal in c++

Is there a way to copy an array to another way in reverse order by using a while loop in c++??
I'm pretty sure I know how to do one with a for loop, but I'm curious if anyone knows of a way by using a while loop
Why not something like this?
#include <algorithm>
int src[] = {1, 2, 3, 4, 5};
int dst[5];
std::reverse_copy(src, src+5, dst);
int anArray = {1, 2, 3, 4, 5};
int reverseArray[5];
int count = 4;
int place = 0;
while(place < 5) {
reverseArray[place] = anArray[count];
count--;
place++;
}
As you said that you have done using for loop, you can follow following steps to convert it to while loop.
for(int i = sizeof(arr) - 1; i >= 0; i--)
{
// your logic
}
now convert it to,
int i = sizeof(arr);
for(; i >= 0; )
{
// your logic
i--;
}
simply replace for with while and remove ; within the braces.
int i = sizeof(arr);
while(i >= 0)
{
// your logic
i--;
}
You can use std::reverse for reversing the same array and std::reverse_copy for reversing to another output array as:
int main() {
int a[]= {1,2,3,4,5,6,7,8,9,10};
const int size = sizeof(a)/sizeof(int);
int b[size];
//copying reverse to another array
reverse_copy(a, a + size, b);
cout << "b = {";
copy(b, b + size, ostream_iterator<int>(cout, ", "));
cout << "}" << endl;
//reverse the same array
reverse(a, a + size);
cout << "a = {";
copy(a, a + size, ostream_iterator<int>(cout, ", "));
cout << "}" << endl;
return 0;
}
Output:
b = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, }
a = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, }
Demo : http://www.ideone.com/Fe5uj
There's been a few questions similar to this recently. I wonder if it is homework or an interview question somewhere. Here's one answer:
#define ELEMENT_COUNT(a) (sizeof((a))/sizeof((a)[0]))
int anArray[] = { 1, 2, 3, 4, 5 };
int reverseArray[ELEMENT_COUNT(anArray)];
int n = ELEMENT_COUNT(anArray);
int i = 0;
while(n--)
reverseArray[i++] = anArray[n];
I think it might be probing to see if you understand when expression like i++ and n-- are evaluated.