I know iterator can be used for vector either with std::vector::begin or with std::begin defined in <iterator>. Same for std::end.
Can I also use iterators with C arrays? I tried the following but it didn't work.
#include <iostream>
#include <iterator>
using std::cin;
using std::cout;
using std::endl;
using std::begin;
using std::end;
void print(const int *arr) {
for (auto cbeg = cbegin(arr); cbeg != cend(arr); ++cbeg) {
cout << *cbeg << endl;
}
}
int main() {
int arr[] = {9, 18, 31, 40, 42};
print(arr);
}
edit:
I thought i could do this because of this piece of code in C++ primer where they used begin and end to get iterators to first and to one past the end element:
#include <iterator>
using std::begin; using std::end;
#include <cstddef>
using std::size_t;
#include <iostream>
using std::cout; using std::endl;
// const int ia[] is equivalent to const int* ia
// size is passed explicitly and used to control access to elements of ia
void print(const int ia[], size_t size)
{
for (size_t i = 0; i != size; ++i) {
cout << ia[i] << endl;
}
}
int main()
{
int j[] = { 0, 1 }; // int array of size 2
print(j, end(j) - begin(j));
return 0;
}
Yes, iterators can be used on arrays. For example
int main()
{
int arr[] = {9, 18, 31, 40, 42};
for (auto cbeg = cbegin(arr); cbeg != cend(arr); ++cbeg) {
cout << *cbeg << endl;
}
will print all elements of arr.
The problem is that, your print() function accepts a pointer, so iterators cannot be used in that case.
However, if you change print() to
void print(int(&arr)[5])
{
// same body as before
}
or (if you don't want the size fixed as 5) to
template<int N> void print(int(&arr)[N])
{
// same body as before
}
you will find it will work, since the array is passed by reference. Note that these functions will not compile if pointers are passed to them.
You can use std::begin and std::end on c-style arrays. You can't use them on pointers. C-style arrays decay to pointers when passed to functions unless you pass them by reference. Dynamic arrays (allocated by new) are also accessed via a pointer, so that doesn't work either.
Passing by reference like void print(int (&arr)[5]) {...} should work. Remark that you need templates if you want variable sized arrays.
You seem to be looking for
// use array pointer to dodge array decay of function parameters:
void obfuscated_meta_programming (int (*arr)[5])
{
for(auto it = std::begin(*arr); it != std::end(*arr); it++)
{
cout << *it << endl;
}
}
int main()
{
int arr[] = {9, 18, 31, 40, 42};
obfuscated_meta_programming(&arr);
}
Which can be rewritten in a sane way like this:
void print (int arr[5])
{
for(size_t i=0; i<5; i++)
{
cout << arr[i] << endl;
}
}
int main()
{
int arr[] = {9, 18, 31, 40, 42};
print(arr);
}
Not this way. Your function print gets only const int * pointer. This pointer has no information about the length of array arr[] from function main, so if you have pointer to int as parameter, then even theoretically, there is no way you could iterate in function "print", regardless whether you use iterator or not. One way to go would be to use std::array and initialize it with char[], like this:
#include <iterator>
#include <iostream>
#include <array>
using std::cin;
using std::cout;
using std::endl;
template<size_t N> void print(std::array<int,N> &arr) {
for (const auto &s : arr) {
cout << s << endl;
}
}
int main() {
std::array<int,5> arr = {9, 18, 31, 40, 42};
print(arr);
}
Compile with --std=c++11
C arrays are not length prefixed. If you have the size, you can create a pointer which satisfies Iterator requirements:
begin = arr;
end = arr + size;
some_algorithm(begin, end);
Related
I have a function which contains more than one array and I want to use those two arrays in my main function in this way
void fun () //which data type should I place here int OR char ?
{
int array[4]={1,2,3,4}
char array2[3]={'a','b','c'}
return array,array2;
}
int main(){
int array1[4];
char array2[3];
array1=fun(); is it possible to get these array here ?
array2=fun();
}
If you really want to return arrays, you could put them in a std::pair of std::arrays:
#include <array>
#include <utility>
auto fun() {
std::pair<std::array<int, 4>, std::array<char, 3>> rv{
{1, 2, 3, 4},
{ 'a', 'b', 'c' }
};
return rv;
}
int main() {
auto[ints, chars] = fun();
}
Use std::tuple of std:arrays:
#include <iostream>
#include <array>
#include <tuple>
std::tuple<std::array<int, 4>, std::array<char, 3>> fun()
{
std::array<int, 4> a1 = { 1, 2, 3, 4 };
std::array<char, 3> a2 = { 'a', 'b', 'c' };
return std::make_tuple(a1, a2);
}
int main()
{
auto mixedArrays = fun();
for (const auto& i : std::get<0>(mixedArrays))
{
std::cout << i << std::endl;
}
for (const auto& i : std::get<1>(mixedArrays))
{
std::cout << i << std::endl;
}
}
Demo
This way you can extend the code to make fun() return more stuff in the future if need be.
Using a struct, code would look like this (using range based for loops for output).
#include <array>
#include <iostream>
// struct holding two arrays with clear names
struct myfun_retval_t
{
std::array<int, 4> integers;
std::array<char, 3> characters;
};
// function returning the struct with two arrays
myfun_retval_t myfun()
{
myfun_retval_t retval
{
{1,2,3,4},
{'a','b','c'}
};
return retval;
}
int main()
{
// call function and store result
auto retval = myfun();
// then output content, using clear readable names for the arrays
for (const int value : retval.integers)
{
std::cout << value << " ";
}
std::cout << "\n";
for (const char c : retval.characters)
{
std::cout << c << " ";
}
return 0;
}
Pass pointers to your arrays in main to your function
Like this
void fun(int* array, char* array2)
{
...
}
int main()
{
int array1[4];
char array2[3];
fun(array1, array2);
}
Hopefully that will get you started, but really you need to read about arrays and pointers and function parameters in your C++ book. This is a complicated topic, and one that many newbies get wrong.
I keep getting a compilation error if I use an array passed as parameter to a method on std::begin or std::end such as this:
#include <iostream>
#include <algorithm>
using namespace std;
class Test
{
public:
static bool exists(int ints[], int size, int k)
{
if (std::find(std::begin(ints), std::end(ints), k) != std::end(ints)) {
return true;
}
return false;
}
};
I tried casting it to &int[0] but it will still not compile.
The parameter ints is not an array, so you aren't passing an array into std::begin / std::end in the example. A function parameter is never an array in C++. When you declare a function array to be an array such as in your example, that parameter is adjusted to be a pointer to the element of such array. In your case, the type of the parameter ints has been adjusted to be a pointer to int i.e. int*, and you cannot pass a pointer into std::begin / std::end, as the error message surely explains.
You have passed the size as another parameter, so you could instead use:
std::find(ints, ints + size, k)
A more modern API design is to wrap the pointer and the size into a single class. The C++20 standard library comes with such class template: std::span. It also has convenient range algorithms that are quite convenient:
static bool exists(std::span<const int> ints, int k)
{
if (std::ranges::find(ints, k) != std::end(ints)) {
Even moreso, C++20 standard library has a function template that makes your function unnecessary:
std::ranges::contains(some_array, k);
Use std::span.
try this:
#include <algorithm>
#include <iostream>
#include <span>
bool exists(std::span<int> span, int needle) {
return std::find(span.begin(), span.end(), needle) != span.end();
}
int main() {
int arr[] = {0, 1, 2, 3, 4};
bool ok = exists(arr, 3);
if (ok) {
std::cout << "ok" << '\n';
} else {
std::cout << "not ok" << '\n';
}
return 0;
}
Here is a working example.
#include <iostream>
#include <vector>
bool exists(int x[], const int size, const int k)
{
std::vector<int> v(x, x + size);
if (std::find( v.begin(), v.end(), k) != v.end()) {
return true;
}
return false;
}
int main()
{
int const sz = 10;
int arrayi[sz] = { 1, 2, 3,4 ,5 ,6 ,7 , 8, 9, 0 };
if (exists(arrayi, sz, 4))
std::cout << "exist" << std::endl;
else
std::cout << "it does not" << std::endl;
}
i am trying to wirte a function to find a the max value in a vector recursively. To do that i want to test in the findMax function if it can return the last value in the list right. But at the end, when the list has just one element, it returns me the adress of variable and not the value. Why is it?
/// finding max value in a list recursively
template <typename T>
int findMax(std::vector<T> arrayVector)
{
if(arrayVector.size()==1)
{
return arrayVector[0];
}
int op1= arrayVector[0];
std::vector<T> newVector (arrayVector.cbegin() + 1, arrayVector.cend());
disPlay(newVector);
int op2= findMax(newVector);
}
/// print vector
template <typename T>
void disPlay(std::vector<T> vectorArray)
{
for (int i=0; i< vectorArray.size(); i++)
{
std::cout << vectorArray[i] << "\t";
}
std::cout << "\n";
}
main()
{
std::vector<int> arrayVector = {6, 8, 19, 20, 23, 41, 49, 53, 56};
std::cout << findMax(arrayVector) << endl;
return 0;
}
I ran you program and it triggered several warnings, the one that probably justifies the unwanted behaviour is the lack of return value in int findMax(std::vector<T> arrayVector).
template <typename T>
int findMax(std::vector<T> arrayVector)
{
if(arrayVector.size()==1)
{
return arrayVector[0];
}
int op1= arrayVector[0];
std::vector<T> newVector (arrayVector.cbegin() + 1, arrayVector.cend());
disPlay(newVector);
int op2= findMax(newVector);
return op2; //<-- added return
}
I corrected the problems in https://wandbox.org/permlink/Kts9qs7MooG4dEQL
It seems ok now.
Use compiler warnings, it can save you a lot of time an headaches.
Now, this solves the issues with your code, but I would advise the use of std::max_element to get max values in a C++ data structure.
Here is a test sample of a function to get the max value recursively in an unordered vector witch loses the last element in each iteration:
template <typename T>
void findMax(std::vector<T>& arrayVector)
{
if(arrayVector.size() == 0) //stop condition
return;
int max = *std::max_element(arrayVector.begin(), arrayVector.end());
std::cout << "Max value: "<< max << std::endl;
arrayVector.erase(arrayVector.end() - 1); //last element being deleted in every recursion
findMax(arrayVector);
}
Check it in https://wandbox.org/permlink/0oyGnXoQdwhl3kUJ
template<typename T>
T findMax(const std::vector<T> vec, size_t index=0){
if(index==vec.size()-1) return vec[vec.size()-1];
return ( vec[index] > findMax(vec,index+1))?vec[index]:findMax(vec,index+1) ;
}
Your code is convoluted:
it's not actually computing the max of the vector
not all paths return a value
you are copying std::vector objects around with no real purpose
STL has the advantage of abstracting iterators, which make your attempt rather trivial:
template<typename T, typename C>
T findMax(C begin, C end)
{
if (begin+1 == end)
return *begin;
else
return std::max(*begin, findMax<T,C>(begin+1, end));
}
Mind: the code is not checking for correctness of input.
Can't be a recursive solution without ol' std::accumulate:
#include <iostream>
#include <vector>
#include <numeric>
#include <limits>
int main(int argc, char *argv[])
{
std::vector<int> arrayVector = {6, 8, 19, 20, 23, 41, 49, 53, 56};
const int max = std::accumulate(
arrayVector.cbegin(),
arrayVector.cend(),
std::numeric_limits<int>::min(),
[](int x, int y) { return x > y ? x : y; }
);
std::cout << max << '\n';
return 0;
}
Earlier solution by Rietty to similar question and solutions in this thread follow vector from 0 to end. Next follows vector from end to 0 to simplify recursive function:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
template<typename T>
T findMax (vector<T> values, size_t end) {
if (0 == end) return values[0];
return max (findMax (values, end - 1), values[end]);
}
template<typename T>
T inline findMax (vector<T> values) {
return findMax (values, values.size() - 1);
}
int main () {
vector<int> values = { 6, 8, 19, 20, 23, 41, 49, 53, 56 };
cout << findMax (values) << endl;
return 0;
}
Simple code:
int find_max(int a[], int length){
if (length == 0) return a[length];
return std::max(a[length-1], find_max(a, length-1));
}
#include "iostream"
#include "vector"
using namespace std;
int maxre(vector<int> array);
int main()
{
vector<int> data = {210, 800, 2,150 ,19,600};
cout << maxre(data);
return 0;
}
int maxre(vector<int> array)
{
static int index = -1;
if (array.size() == index + 1)
{
return 0;
}
else
{
index++;
int current = array[index];
int back = maxre(array);
return current > back ? current : back;
}
return 0;
}
If I pass a lambda as a reference argument to sort algorithm it is working. But when I pass the same lambda to stable_sort it is not compiling and I have to declare the argument const? Why it is so?
// sort algorithm example
#include <iostream> // std::cout
#include <algorithm> // std::sort
#include <vector> // std::vector
using namespace std;
void print(std::vector<int> &vec)
{
for (auto i : vec)
{
cout << i << " ";
}
cout << endl;
}
int main() {
std::vector<int> myvector = { 32, 71, 12, 45, 26, 80, 53, 33 };
sort(myvector.begin(), myvector.end(), [](int &i, int &j)//working
{
return i < j;
});
stable_sort(myvector.begin(), myvector.end(), [](int &i, int &j)//not compiling
{
return i < j;
});
stable_sort(myvector.begin(), myvector.end(), [](const int &i, const int &j)//compiling
{
return i < j;
});
print(myvector);
return 0;
}
[Bug libstdc++/82891] stable_sort() won't compile with function object that takes parameters by non-const reference
There is now an LWG issue submission request waiting to become published for
this. I'll return when it has been added.
There are issues for both GCC and LLVM but they wait on a request[3] to the Library Working Group to change the standard.
The error reads:
request for member 'begin', 'end' in 'arr' which is non class type int[5],
unable to deduce from expression error.
My code:
#include <iostream>
using namespace std;
int main()
{
int * mypointer;
int arr[5] = {1,3,5,7,9};
mypointer = arr;
for(auto it = arr.begin(); it != arr.end(); ++it) {
cout<<*mypointer<<endl;
mypointer++;
}
return 0;
}
Arrays have no member functions as they aren't a class type. This is what the error is saying.
You can use std::begin(arr) and std::end(arr) from the <iterator> header instead. This also works with types that do have .begin() and .end() members, via overloading:
#include <array>
#include <vector>
#include <iterator>
int main()
{
int c_array[5] = {};
std::array<int, 5> cpp_array = {};
std::vector<int> cpp_dynarray(5);
auto c_array_begin = std::begin(c_array); // = c_array + 0
auto c_array_end = std::end(c_array); // = c_array + 5
auto cpp_array_begin = std::begin(cpp_array); // = cpp_array.begin()
auto cpp_array_end = std::end(cpp_array); // = cpp_array.end()
auto cpp_dynarray_begin = std::begin(cpp_dynarray); // = cpp_dynarray.begin()
auto cpp_dynarray_end = std::end(cpp_dynarray); // = cpp_dynarray.end()
}
For a standard fixed-length C array, you can just write
int c_array[] = {1,3,5,7,9}, acc = 0;
for (auto it : c_array) {
acc += it;
}
The compiler does the behind-the-scenes work, eliminating the need to create all those begin and end iterators.
In C++, arrays are not classes and therefore do not have any member methods. They do behave like pointers in some contexts. You can take advantage of this by modifying your code:
#include <iostream>
using namespace std;
int main()
{
int * mypointer;
const int SIZE = 5;
int arr[SIZE] = {1,3,5,7,9};
mypointer = arr;
for(auto it = arr; it != arr + SIZE; ++it) {
cout<<*mypointer<<endl;
mypointer++;
}
return 0;
}
Of course, this means that mypointer and it both contain the same address, so you don't need both of them.
One thing I'd like to point out for you is that you really don't have to maintain a separate int* to use in dereferencing the array elements, apart from the whole member thing others have well pointed out.
Using a more modern approach, the code is both more readable, as well as safer:
#include <iostream>
#include <algorithm>
#include <array>
#include <iterator>
using namespace std;
int main()
{
std::array<int, 5> cpp_array{1,3,5,7,9};
// Simple walk the container elements.
for( auto elem : cpp_array )
cout << elem << endl;
// Arbitrary element processing on the container.
std::for_each( begin(cpp_array), end(cpp_array), [](int& elem) {
elem *= 2; // double the element.
cout << elem << endl;
});
}
Using the lambda in the second example allows you to conveniently perform arbitrary processing on the elements, if needed. In this example, I'm just showing doubling each element, but you can do something more meaningful within the lambda body instead.
Hope this makes sense and helps.
Perhaps here is a cleaner way to do it using templates and lambdas in c++14:
Define:
template<typename Iterator, typename Funct>
void my_assign_to_each(Iterator start, Iterator stop, Funct f) {
while (start != stop) {
*start = f();
++start;
}
}
template<typename Iterator, typename Funct>
void my_read_from_each(Iterator start, Iterator stop, Funct f) {
while (start != stop) {
f(*start);
++start;
}
}
And then in main:
int x[10];
srand(time(0));
my_assign_to_each(x, x+10, [] () -> int { int rn{}; rn = rand(); return rn; });
my_read_from_each(x, x+10, [] (int value) { std::cout << value << std::endl; });
int common_value{18};
my_assign_to_each(x, x+10, [&common_value] () -> int { return common_value; });
my_read_from_each(x, x+10, [] (int value) { std::cout << value << std::endl; });
Quite late but I think it's worth to mention that:
void findavgTime(int n)
{
int wt1[n];
fill_wt(wt1,n); //Any method that puts the elements into wt1
int wt2[3];
int sum = accumulate(begin(wt1), end(wt1), 0); // Fails but wt2[3] will pass. Reason: variable-sized array type ‘int [n]’ is not a valid template argument)
}