How do pointers work for an array and a vector object
For array_1
#include <iostream>
#include <array>
using namespace std;
int main(){
int a[3][4]={0,1,3,3,4,5,6,7,8,9,10,11};
//int (*pi)[4]=a;
for( auto *pi=a; pi!=a+3; ++pi ){
for( auto p=*pi; p!=*pi + 4; ++p){
cout << *p << "\n";
}
}
}
For array_2
#include <iostream>
#include <array>
using namespace std;
int main(){
int a[3][4]={0,1,3,3,4,5,6,7,8,9,10,11};
//int (*pi)[4]=a;
for( auto pi=a; pi!=a+3; ++pi ){
for( auto p=*pi; p!=*pi + 4; ++p){
cout << *p << "\n";
}
}
}
For vector_1
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> a{0,1,3,3,4,5,6,7,8,9,10,11};
for(auto i=a.begin(); i!=a.end(); ++i ){
// we can also use begin(a) and end(a)
cout << *i << "\n";
}
}
For vector_2
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> a{0,1,3,3,4,5,6,7,8,9,10,11};
for(auto *i=a.begin(); i!=a.end(); ++i ){
// we can also use begin(a) and end(a)
cout << *i << "\n";
}
}
Both codes (for array_1 and for array_2) give the same output i.e (0-11)
you can see that there is a difference in the first for loop of both pieces of code.
In the For vector_1 ,as far as I understood, I think, I am creating a pointer i to the beginning of the vector and then dereferencing it to fetch the value of that corresponding position. Now my doubt is, how come in the For array_1 and For array_2 when I use the *pi in the 2nd for loop, instead of getting dereferenced(like in the case of vector), it is fetching me the iterative values?
And why does the For vector_2 not work the same way as For vector_1?
And what is the return type of the size() and begin()/end() function for vector?
Cause when I use for(decltype(a.size()) i=0; i!=end(); ++i), it is giving me a type conversion error.
The code for array_1, for array_2 and for vector_1 gives the same output(0-10). It is the for vector_2 that is giving an error.
Thanks.
In case of vector_1 you are not creating a pointer, but an iterator - in most basic use cases, like printing vector results, iterator works and is used like a pointer, but it is not the same and shouldn't be handled the same way you handle a pointer. In case of vector_2 you do something nasty since this is the job of the auto keyword to determine whether the variable is to be a pointer or not.
The last example causes an error, because you are trying to create a pointer to iterator, and the type returned by the begin() function is an iterator (a value), not the address of the iterator object.
If you want to know the return types of functions like size(), begin(), etc. you can always refer to one of the several large C++ reference websites, for example:
www.cplusplus.com
www.cppreference.com
Related
I'm having problems with a program that only accepts arrays. I'm having plenty of pointers to different arrays, but using *p seems to only give me the first element of the array. I want to return all the elements of the array. I know the length of the array, if that helps.
#include <typeinfo>
#include <iostream>
int i[10];
int* k=i;
cout<<typeid(i).name()<<'\n';
cout<<typeid(*k).name()<<'\n';
results in 'int [10]' and 'int' respectively. I want some way of returning k as 'int [10]'.
Your k is a pointer to int. It points to the first element of the array. If you want a pointer to the whole array then you need to declare it as such.
#include <typeinfo>
#include <iostream>
int main() {
int i[10];
int* k=i;
int(*p)[10] = &i;
std::cout<<typeid(i).name()<<'\n';
std::cout<<typeid(*k).name()<<'\n';
std::cout<<typeid(*p).name()<<'\n';
}
Output:
A10_i
i
A10_i
However, as others have said, std::array is much less confusing to work with. It can do (almost) anything a c-array can do without its quirks.
Certainly there is a solution to your actual problem that does not require to get the array from a pointer to a single integer.
Example to show you how much more convenient C++ array/vector is then "C" style arrays with pointers :
#include <vector>
#include <iostream>
// with std::vector you can return arrays
// without having to think about pointers and/or new
// and your called cannot forget to call delete
std::vector<int> make_array()
{
std::vector<int> values{ 1,2,3,4,5,6 };
return values;
}
// pass by reference if you want to modify values in a function
void add_value(std::vector<int>& values, int value)
{
values.push_back(value);
}
// pass by const refence if you only need to use the values
// and the array content should not be modified.
void print(const std::vector<int>& values)
{
// use range based for loops if you can they will not go out of bounds.
for (const int value : values)
{
std::cout << value << " ";
}
}
int main()
{
auto values = make_array();
add_value(values, 1);
print(values);
std::cout << "\n";
std::cout << values.size(); // and a vector keeps track of its own size.
return 0;
}
I'm new to C++ and I'm learning with C++20. I'm trying on a struct function, which is to wrap a function in a struct, while we can claim local attributes in this struct.
The thing is that when I pass this struct function to a for_each function, it does not work.
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
using namespace std;
struct accumulateAmount{
int total_amount;
accumulateAmount() { total_amount = 100 ;} //constructor
void operator()(int num){
total_amount += num;
}
};
int main(){
vector<int> nums{1,2,3,4,5};
accumulateAmount acctor;
for_each(nums.begin(), nums.end(), acctor);
cout << acctor.total_amount << endl;
return 0;
}
The output is 100. It does not realize the accumulator functionality.
While if I change the loop from for_each to ordinary for loop as the following:
for (int i = 0; i < nums.size(); i++){
acctor(nums[i]);
}
It works.
So I wonder if it's because 'for_each' encompasses parallel computing hence for each int in the vector, we are using independent functions on them?
std::for_each takes the function by value. So your function gets copied, and std::for_each calls the copy. That’s why your acctor does not get modified.
You can force passing by reference though, by using std::ref:
for_each(nums.begin(), nums.end(), std::ref(acctor));
Alternatively, and perhaps more idiomatically, you can capture the return value of std::for_each:
auto const result = for_each(nums.begin(), nums.end(), accumulateAmount());
std::cout << result.total_amount << "\n";
The good thing about this code is that you don’t even need to introduce a name for acctor: you can pass a temporary and create the function object on the fly. This is nice because it means that you can make all your local objects const.
That said, std::for_each with a mutable function object is absolutely not idiomatic C++. Finding the suitable algorithm isn’t always obvious, but always worth it. In this case, you’d use std::reduce:
auto const result = std::reduce(nums.begin(), nums.end(), 100);
std::cout << result << "\n";
The quickest fix:
acctor = std::for_each(nums.begin(), nums.end(), accumulateAmount());
But rather than spinning your own functor from scratch, use C++'s lambdas (C++11+).
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
int main(){
std::vector<int> nums{1,2,3,4,5};
int val = 100;
std::for_each(nums.begin(), nums.end(), [&val](int n) { return val += n; });
std::cout << val << '\n';
return 0;
}
Some quick notes on the lambda:
[] is where you can 'capture' variables outside the scope of the lambda, that shouldn't be passed as arguments. In this case I capture val by reference. You are not required to capture anything, but the [] is required.
() parameter list, pretty straightforward.
{} function body, also straightforward.
As pointed out in a comment to another answer, this specific example is solved even simpler with std::accumulate or std::reduce (Shown in another answer (this one was new to me, and pretty cool)).
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
int main() {
std::vector<int> nums{1, 2, 3, 4, 5};
std::cout << std::accumulate(nums.begin(), nums.end(), 100) << '\n';
return 0;
}
I am faced with the task of comparing two c++ arrays that are of int data type. I specifically cannot use any loops (for, while) of my own, and was encouraged to use an STL function. I found std::mismatch() and it seems to be what I want, but I am unable to get it working with a basic array.
Here is my code:
#include <iostream> // cout
#include <algorithm> // std::mismatch
#include <utility> // pair
int main()
{
int a[10] = {1,3,5,7,9,11,13,15,17,19};
int b[10] = {2,4,6,8,10,12,14,16,18,20};
std::pair<int, int> result =
std::mismatch(a, a + 9, b);
std::cout<<result.first<<" "<<result.second<<std::endl;
return 0;
}
I am getting the following error:
error: conversion from 'std::pair' to non-scalar type 'std::pair' requested
I am pretty new to C++, so I don't really know what this means.
std::mismatch returns a pair of iterators to the container, not a pair of ints. In this case, since you have an array, the iterator type is int*.
The simple solution is to deduce the type when calling it instead:
auto result = std::mismatch(a, a + 9, b);
From c++17, you can name the individual elements of the pair as well:
auto [i, j] = std::mismatch(a, a + 9, b);
std::mismatch() returns a std::pair of iterators. In your example, you are using iterators of type int* (an int[] array decays to an int* pointer to its 1st element). So you need to change your result variable from pair<int, int> to pair<int*, int*>. And then you need to dereference those iterators when printing their values to cout, eg:
#include <iostream> // cout
#include <algorithm> // std::mismatch
#include <utility> // pair
int main()
{
int a[10] = {1,3,5,7,9,11,13,15,17,19};
int b[10] = {2,4,6,8,10,12,14,16,18,20};
int *a_end = a + 10;
std::pair<int*, int*> result = std::mismatch(a, a_end, b);
if (result.first != a_end)
std::cout << *(result.first) << " " << *(result.second) << std::endl;
else
std::cout << "no mismatch found" << std::endl;
return 0;
}
I was reading up on this : http://www.cplusplus.com/reference/algorithm/random_shuffle/
and wondered if its possible to random_shuffle an array of int elements. This is my code
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int a[10]={1,2,3,4,5,6,7,8,9,10};
cout << a << endl << endl;
random_shuffle(a[0],a[9]);
cout<<a;
}
I got this error:
error C2893: Failed to specialize function template
'iterator_traits<_Iter>::difference_type *std::_Dist_type(_Iter)'.
My question are:
Is it possible to shuffle an int array using random_shuffle. If yes, I would like to learn how to do it.
Is random_shuffle only applicable to templates?
What does my error mean?
You need to pass pointers to a[0] and a[10], not the elements themselves:
random_shuffle(&a[0], &a[10]); // end must be 10, not 9
In C++11, you can use std::begin and std::end:
random_shuffle(std::begin(a), std::end(a));
Try replacing
random_shuffle(a[0],a[9]);
with
random_shuffle(&a[0], &a[10]);
From: http://www.java2s.com/Code/Cpp/STL-Basics/Userandomshufflealgorithmswitharray.htm
random_shuffle takes iterators, rather than elements. Try either:
std::random_shuffle(a, a + 10);
or
std::random_shuffle(std::begin(a), std::end(a));
std::random_shuffle can be used on any pair of random access iterators, and will shuffle the elements in the range denoted by those iterators.
The error occurs because ints are not iterators, and so std::random_shuffle is unable to use the given ints as iterators.
Just changing the arr to a pointer does not solve the solution. This will make the array swap to one type of permutation. This means that if you rerun the program, your array will be shuffled into the exact same way as it did in the previous run.
To fix this - the function offers a third parameter which acts as a seed. So the correct implementation of the function is as follows.
1) Have a function or a lamda that generates a random number. This will act as your seed.
int myrandom (int i) { return std::rand()%i;}
Make sure to set the seed of the internal random number generator.
std::srand ( unsigned ( std::time(0) ) );
2) Insert this function as the third arguement in the random_shuffle function call.
std::random_shuffle ( myvector.begin(), myvector.end(), myrandom);
This will result in an always random shuffled array.
Make sure to include the following:
#include <algorithm> // std::random_shuffle
#include <vector> // std::vector
#include <ctime> // std::time
#include <cstdlib> // std::rand, std::srand
Worked for me this way:
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int a[10]={0,1,2,3,4,5,6,7,8,9};
for (unsigned i = 0; i < 10; i++)
{
cout << a[i];
}
cout << endl;
random_shuffle(&a[0],&a[10]);
for (unsigned i = 0; i < 10; i++)
{
cout << a[i];
}
cout << endl;
}
I know you can just do: &theVector[0], but is this standard? Is this behavior always guaranteed?
If not, is there a better, less 'hackish' way to do this?
Yes, that behavior is guaranteed. Although I can't quote it, the standard guarantees that vector elements are stored consecutively in memory to allow this.
There is one exception though:
It will not work for vector<bool> because of a template specialization.
http://en.wikipedia.org/wiki/Sequence_container_%28C%2B%2B%29#Specialization_for_bool
This specialization attempts to save memory by packing bools together in a bit-field. However, it breaks some semantics and as such, &theVector[0] on a vector<bool> will not work.
In any case, vector<bool> is widely considered to be a mistake so the alternative is to use std::deque<bool> instead.
C++11 provides the data() method on std::vector which returns a T*. This allows you to do:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vector = {1,2,3,4,5};
int* array = vector.data();
std::cout << array[4] << std::endl; //Prints '5'
}
However, doing this (or any of the methods mentioned above) can be dangerous as the pointer could become invalid if the vector is resized. This can be shown with:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vector = {1,2,3,4,5};
int* array = vector.data();
vector.resize(100); //This will reserve more memory and move the internal array
//This _may_ end up taking the place of the old array
std::vector<int> other = {6,7,8,9,10};
std::cout << array[4] << std::endl; //_May_ now print '10'
}
This could could crash or do just about anything so be careful using this.
We can do this using data() method. C++11 provides this method.
It returns a pointer to the first element in the vector. vector Even if it is empty, we can call this function itself without problems
vector<int>v;
int *arr = v.data();
A less 'hackish' way? Well you could simply copy :
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vect0r;
int array[100];
//Fill vector
for(int i = 0; i < 10 ; i++) vect0r.push_back( i ) ;
//Copy vector to array[ ]
for( i = 0; i < vect0r.size(); i++) array[i] = vect0r[i];
//Dispay array[ ]
for( i = 0; i < vect0r.size(); i++) cout<< array[i] <<" \n";
cout<<" \n";
return 0;
}
More here : How to convert vector to array in C++