I have written a program that flips the elements of an array that are next to each other. for example
1, 2, 1, 2 becomes 2, 1, 2, 1
The code I wrote is:
#include <iostream>
template <class T>
void swap(T& a, T& b){
T temp = a;
a = b;
b = temp;
}
template <class T>
void oReverse(T* p, int size){
for(T* e = p + size; p < e; p+=1){
swap(*p, *p++);
}
}
int main(){
int arr[] = {1,2,1,2,1,2};
oReverse(arr, 6);
for(int i = 0; i < 6; i++){
std::cout << arr[i] << " ";
}
return 0;
}
The oReverse() function takes care of the pointer magic.
The thing i couldn't understand is: Why does swap(*p, *p++) increment p by one.
At first I wrote p+=2 in the for loop, but it didn't work well, but it does with p++.
I thought the program would swap p and p++ then increment p by 2 then swap p and p++ again and again.
I hope i explained the problem clearly enough.
Firstly, *p++ increments p after the value is fetched. So instead of
swap(*p, *p++);
you would like to do this:
swap(*p, *++p);
But this will not work either. The standard does not define in which order the arguments to a function should be evaluated. So instead of
swap(*p, *++p);
write
swap(*p, *(p+1));
p++;
and you'll be safe. Their behavior are not equivalent, because the evaluation order is unspecified. But their expected behavior are equivalent.
With "expected behavior", I mean the behavior someone who does not know that the evaluations order is not defined by the standard typically would expect.
EDIT:
The evaluation order was unspecified before C++17, but from C++17 it is specified from left to right. But still, don't do things like that. "Clever" constructs have a tendency to cause problems.
Related
Here in f() I accept array to be of maximum size 4 but it still runs fine when I pass an array of size greater than 4(here 10), I know arrays in c++ are passed as pointers by default but than when is this method of passing array useful?
#include<iostream>
using namespace std;
void f(int a[4]){
for(int i = 0;i < 3;i++){
a[i] += 10;
}
}
int main(){
int a[10];
for(int i = 0;i < 10;i++)
a[i] = i;
f(a);
for(int i =0 ;i < 10;i++){
cout<<a[i]<<" ";
}
cout<<"\n";
return 0;
}
output: 10 11 12 3 4 5 6 7 8 9
I know arrays in c++ are passed as pointers by default
Correct.
This:
void foo(int a[4])
is literally rewritten to this:
void foo(int* a)
… and then when you call the function your array's name decays to the pointer, matching the rewritten/"real" argument type.
So you're not really passing an array at all.
When is this method of passing array useful?
Never.
This is a shameful oddity inherited from C. One might argue that the [4] is a useful hint to the developer that the pointed-to array "should" have four elements, but modern wisdom is that this is just unnecessarily and dangerously misleading.
Better alternatives include:
Pointer/size pair (two arguments): this is not less dangerous per se, but at least it does not lie about the type and lull you into a false sense of security!
Array by reference: lovely jubbly, but less flexible
std::array<int, 4> (by reference): as above, but neater
Either make f() more restrictive as shown by #songyuanyao or consider using a C++ std::array instead:
#include <iostream>
#include <array>
// make an alias for the array you'd like to accept
using myarray_t = std::array<int, 4>;
// accept the array by reference
void f(myarray_t& a) {
// use a range based for loop to access elements by reference
for(int& a_i : a) a_i += 10;
}
int main() {
// declare your array
myarray_t a;
for(size_t i = 0; i < a.size(); ++i) a[i] = static_cast<int>(i);
f(a);
// and you can use a range based for loop to extract by value too
for(int a__i : a)
std::cout << a_i << " ";
std::cout << "\n";
return 0;
}
If you want to impose restrictions on the size of the array passed in, you can change to pass-by-reference.
void f(int (&a)[4]){
for(int i = 0;i < 3;i++){
a[i] += 10;
}
}
void f(int a[4]) is same as void f(int* a); that means you can pass the array with any size which will decay to pointer (i.e. int*) when being passed.
For the example below, what may cause undefined behavior? and why?
#include <cstddef>
#include <iostream>
template <typename Ty>
bool in_range(const Ty *test, const Ty *r, size_t n)
{
return 0 < (test - r) && (test - r) < (std::ptrdiff_t)n;
}
void f() {
double foo[10];
double *x = &foo[0];
double bar;
std::cout << std::boolalpha << in_range(&bar, x, 10);
}
I have not found the answer in When is pointer subtraction undefined in C?
Pointer arithmetic, including the subtraction of two pointers, is only defined if the pointers point to elements within the same array, or one past the end of that array. In this context, a scalar counts as an array of size 1.
It's pretty pointless to allow pointer arithmetic in any other instance. To do that would unnecessarily constrain the C's memory model and could curtail its flexibility and ability to port to exotic architectures.
For the code, as you've written it, the answer is basically the same for C++ as it is for C: you get defined behavior if and only if the two pointers involved refer to parts of the same array, or one past its end (where, as #bathsheba already noted, a non-array object is treated as being the same as an array of one item).
C++ does, however, add one wrinkle that might be useful to know about here: even though neither subtraction nor ordered comparisons (e.g., <) is required to produce meaningful results when applied to pointers to separate objects, std::less<T> and friends, from <functional> are required to do so. So, given two separate objects like this:
Object a;
Object b;
...comparing the addresses of the two objects with the comparison objects must "yield a strict total order that is consistent among those specializations and is also consistent with the partial order imposed by the built-in operators <, >, <=, >=." (N4659, [comparisons]/2).
As such, you could write your function something like this:
template <typename Ty>
bool in_range(const Ty *test, const Ty *begin, const Ty *end)
{
return std::less_equal<Ty *>()(begin, test) && std::less<Ty *>()(test, end);
}
If you really want to maintain the original function signature, you could do that as well:
template <typename Ty>
bool in_range(const Ty *test, const Ty *r, size_t n)
{
auto end = r + n;
return std::less_equal<Ty *>()(r, test) && std::less<Ty *>()(test, end);
}
[Note that I've written it using std::less_equal for the first comparison, and std:less for the second to match the typically expected semantics of C++, where the range is defined as [begin, end). ]
This does carry one proviso though: you need to ensure that r points to to the beginning of an array of at least n items1, or else the auto end = r + n; will produce undefined behavior.
At least for what I'd expect as the typical use-case for such a function, you can probably simplify usage a little but by passing the array itself, rather than a pointer and explicit length:
template <class Ty, size_t N>
bool in_range(Ty (&array)[N], Ty *test) {
return std::less_equal<Ty *>()(&array[0], test) &&
std::less<Ty *>()(test, &array[0] + N);
}
In this case, you'd just pass the name of the array, and the pointer you want to test:
int foo[10];
int *bar = &foo[4];
std::cout << std::boolalpha << in_range(foo, bar) << "\n"; // returns true
This only supports testing against actual arrays though. If you attempt to pass a non-array item as the first parameter it simply won't compile:
int foo[10];
int bar;
int *baz = &foo[0];
int *ptr = new int[20];
std::cout << std::boolalpha << in_range(bar, baz) << "\n"; // won't compile
std::cout << std::boolalpha << in_range(ptr, baz) << "\n"; // won't compile either
The former probably prevents some accidents. The latter might not be quite as desirable. If we want to support both, we can do so via overloading (for all three situations, if we choose to):
template <class Ty, size_t N>
bool in_range(Ty (&array)[N], Ty *test) {
return std::less_equal<Ty *>()(&array[0], test) &&
std::less<Ty *>()(test, &array[0]+ N);
}
template <class Ty>
bool in_range(Ty &a, Ty *b) { return &a == b; }
template <class Ty>
bool in_range(Ty a, Ty b, size_t N) {
return std::less_equal<Ty>()(a, b) &&
std::less<Ty>()(b, a + N);
}
void f() {
double foo[10];
double *x = &foo[0];
double bar;
double *baz = new double[20];
std::cout << std::boolalpha << in_range(foo, x) << "\n";
std::cout << std::boolalpha << in_range(bar, x) << "\n";
std::cout << std::boolalpha << in_range(baz, x, 20) << "\n";
}
1. If you want to get really technical, it doesn't have to point to the beginning of the array--it just has to point to part of an array that's followed by at least n items in the array.
Undefined behavior in this case usually does not cause a crash, but a meaningless or inconsistent result.
In most modern architectures, subtracting 2 unrelated pointers just computes the difference of addresses divided by the size of the pointed type, approximately this:
A *p1, *p2;
...
ptrdiff_t diff = ((intptr_t)p2 - (intptr_t)p1) / (intptr_t)sizeof(*p1);
Examples of architectures where the behavior would be unexpected are Intel's 16 bit segmented medium and large models:
These models were once prevalent on PCs, before the 386 came along and its 32-bit model.
far pointers were stored in 2 parts: a 16-bit segment (or selector in protected mode) and a 16-bit offset.
comparing 2 pointers for equality required 2 separate compare instructions and conditional jumps for the segment and the offset.
comparing a pointer to NULL was usually optimized as a single comparison of the segment part with 0
subtracting 2 pointers and comparing for relative position was performed on the offset part only, making the silent assumption that both pointers pointed to the same array, hence had the same segment.
in your example, both objects have automatic storage, so they are both in the same segment, pointed to as SS, but for 2 objects allocated from the heap you could have p <= q && q <= p and p != q at the same time, or p - q == 0 with p != q which is covered by undefined behavior.
This question already has answers here:
When a function has a specific-size array parameter, why is it replaced with a pointer?
(3 answers)
Closed 7 years ago.
I am aware that an array can be passed to a function in quite a few ways.
#include <iostream>
#include <utility>
using namespace std;
pair<int, int> problem1(int a[]);
int main()
{
int a[] = { 10, 7, 3, 5, 8, 2, 9 };
pair<int, int> p = problem1(a);
cout << "Max =" << p.first << endl;
cout << "Min =" << p.second << endl;
getchar();
return 0;
}
pair<int,int> problem1(int a[])
{
int max = a[0], min = a[0], n = sizeof(a) / sizeof(int);
for (int i = 1; i < n; i++)
{
if (a[i]>max)
{
max = a[i];
}
if (a[i] < min)
{
min = a[i];
}
}
return make_pair(max,min);
}
My code above passes only the first element while it should be passing an array (or technically, a pointer to the array) and hence, the output is 10, 10 for both max and min (i.e. a[0] only).
What am I doing wrong, I guess this is the correct way.
The contents of the array are being passed to the function. The problem is:
n = sizeof(a) / sizeof(int)
Does not give you the size of the array. Once you pass an array to a function you can't get its size again.
Since you aren't using a dynamic array you can use a std::array which does remember its size.
You could also use:
template <int N>
void problem1(int (&a) [N])
{
int size = N;
//...
}
No, you simply cannot pass an array as a parameter in C or C++, at least not directly.
In this declaration:
pair<int, int> problem1(int a[]);
even though a appears to be defined as an array, the declaration is "adjusted" to a pointer to the element type, so the above really means:
pair<int, int> problem1(int* a);
Also, an expression of array type is, in most contexts, implicitly converted to a pointer to the array's initial element. (Exceptions include an array as the operand of sizeof or unary &). So in a call to the above function:
int arr[10];
problem1(arr);
the array expression arr is equivalent to &arr[0], and that address (pointer value) is what's passed to the function.
Of course you can write code that does the equivalent of passing an array. You can make the array a member of a structure (but then it has to be of fixed length). Or you can pass a pointer to the initial element and pass a separate parameter containing the actual length of the array object.
Or you can use one of the C++ standard library classes that implement array-like data structures; then the length can be taken directly from the parameter.
I highly recommend reading section 6 of the comp.lang.c FAQ, which covers arrays and pointers. It's applicable to C++ as well (though it doesn't mention the C++ standard library).
In C++ language a function parameter declared as int a[] is immediately interpreted as and is equivalent to int *a parameter. Which means that you are not passing an array to your function. You are passing a pointer to the first element of an array.
Trying to apply the sizeof(a) / sizeof(int) technique to a pointer is useless. It cannot possibly produce the size of the argument arraay.
One alternative that hasn't been mentioned is writing your code as a template, and passing the array by reference so the template can deduce the size of the array:
template <class T, size_t n>
pair<T, T> problem1(T(&a)[n]) {
T max = a[0], min = a[0];
for (size_t i = 1; i < n; i++) {
if (a[i]>max) {
max = a[i];
}
if (a[i] < min) {
min = a[i];
}
}
return make_pair(max, min);
}
Note, however, that this will only work if you pass a real array, not a pointer. For example, code like this:
int *b = new int[10];
for (int i = 0; i < 10; i++)
b[i] = rand();
auto result = problem1(b);
...won't compile at all (because we've defined problem1 to receive a reference to an array, and b is a pointer, not an array).
I want to add two arrays by simply writing:
int a[4] = {1,2,3,4};
int b[4] = {2,1,3,1};
int sum[4] = a + b;
I wrote this function but I got an error
int* operator+(const uint32& other) const{
uint32 sum[n];
for(int i=0; i<n; i++){
sum[i] = (*this[i]) + other[i];
}
return sum;
}
Could you help me on this? Thanks in advance.
Let's go through your code, piece by piece, and look at the problems:
int* operator+(const uint32& other) const{
You can't overload operators for built-in types, so this is doomed from the beginning
Even if you could do this (which you can't), it needs to take two parameters since it's non-member binary function.
uint32 sum[n];
You can't make variable-length arrays in C++ (assuming n isn't a compile-time constant) (note: G++ has some extensions that allow this, but it's non-standard C++)
for(int i=0; i<n; i++){
sum[i] = (*this[i]) + other[i];
There's no this pointer to begin with in this code (it's not a member function)...
const uint32& other is not an array/pointer to an array. It's a single reference to a single uint32. That means that other in this code is not an array/pointer to an array, and so you cannot do other[i] (it's like trying to do int x = 3; x[4] = 13;, which makes no sense).
}
return sum;
You're returning a pointer to a locally allocated array, which means this will result in undefined behavior, as the memory associated with sum is going to get annihilated when this function returns.
}
This is probably wrong, but it appears to work (C++11):
#include <iostream>
#include <array>
using namespace std;
template <class T>
T operator+(const T& a1, const T& a2)
{
T a;
for (typename T::size_type i = 0; i < a1.size(); i++)
a[i] = a1[i] + a2[i];
return a;
}
int main()
{
array<int,5> a1 = { 1, 2, 3, 4, 5 };
array<int,5> a2 = { 2, 3, 4, 5, 6 };
array<int,5> a3 = a1 + a2;
for (int i = 0; i < 5; i++)
cout << a1[i] << '+' << a2[i] << '=' << a3[i] << ' ';
cout << endl;
return 0;
}
Output (ideone):
1+2=3 2+3=5 3+4=7 4+5=9 5+6=11
I think the issue is that you're missing a way to pass in the length of the array. You might need to do something a bit more sophisticated. Something like:
class AddingVector : public std::vector<int>
{
public:
typedef AddingVector type;
type operator+(const AddingVector& rhs, const AddingVector& lhs)
{
/* validate that they're the same size, decide how you want to handle that*/
AddingVector retVal;
AddingVector::const_iterator rIter = rhs.begin();
AddingVector::const_iterator lIter = lhs.begin();
while (rIter != rhs.end() && lIter != lhs.end()) {
retVal.push_back(*rIter + *lIter);
++rIter;
++lIter;
}
return retVal;
}
}
You cannot do that. Non-member binary operators must take two arguments (you only provided one), so you could try this:
int* operator+(const uint32& a, const uint32& b)
But that can't possibly work either, since you want to add arrays, not single uint32 variables. So you would think that this would do it:
int* operator+(const uint32[] a, const uint32[] b)
or:
int* operator+(const uint32[4] a, const uint32[4] b)
But no go. It's illegal because you cannot have pointer types as both arguments in an operator overload. Additionally, at least one of the arguments must be a class type or an enum. So what you're trying to do is already impossible on at least two different levels.
It's impossible to do what you want. One correct way to go about it is to write your own class for an array that can be added to another one.
You cannot overload operators for types other than your own defined types. That is, if you create a class X, you can overload operators for X, but you cannot overload operators for arrays or pointers to fundamental types.
first is your code getting compiled properly, you have used 'n' directly in declaring array, is 'n' declared as constant..
And moreover you have taken a local variable in the function and returning it, well, this return a garbage form the stack, wat i can suggest is you malloc some memory and use it,, but again freeing it would be needed...
Hey, what you could do is,
Take a wrapper class "array"
class array
{
int *ipArr;
DWORD size;
};
then in constructor you can pass the size you want to have an array of
array(DWORD dwSize);
{
// then malloc memory of size dwSize;
}
Have an overloaded operator'+' for this class, that will have the above implementation of adding two int arrays,
Note here you will also need to overlaod the '=' assignment operator, so that our array class can you is directly..
now you can free the associated memory in the destructor
You have a few problems. The first is that you aren't passing in both arrays, and then you don't specify what n is, and the last is that you are trying to pass out a pointer to a local variable. It looks like you are trying to make a member operator of a class.
So basically you are trying to add the contents of an unspecified length array to an uninitialised array of the same length and return the stack memory.
So if you pass in pointers to the arrays and the length of the array and an output array then it would work, but you wouldn't have the syntax
sum = a + b;
it would be something like
addArray(&a, &b, &sum, 4);
To get the syntax you want you could make a class that wraps an array. But that is a much more complicated task.
template <typename T>
class Table {
public:
Table();
Table(int m, int n);
Table(int m, int n, const T& value);
Table(const Table<T>& rhs);
~Table();
Table<T>& operator=(const Table& rhs);
T& operator()(int i, int j);
int numRows()const;
int numCols()const;
void resize(int m, int n);
void resize(int m, int n, const T& value);
private:
// Make private because this method should only be used
// internally by the class.
void destroy();
private:
int mNumRows;
int mNumCols;
T** mDataMatrix;
};
template <typename T>
void Table<T>::destroy() {
// Does the matrix exist?
if (mDataMatrix) {
for (int i = 0; i < _m; ++i) {
// Does the ith row exist?
if (mDataMatrix[i]) {
// Yes, delete it.
delete[]mDataMatrix[i];
mDataMatrix[i] = 0;
}
}
// Delete the row-array.
delete[] mDataMatrix;
mDataMatrix = 0;
}
mNumRows = 0;
mNumCols = 0;
}
This is a code sample I got from a book. It demonstrates how to destroy or free a 2x2 matrix where mDataMatrix is the pointer to array of pointers.
What I don't understand is this part:
for(int i = 0; i < _m; ++i) {
// Does the ith row exist?
if (mDataMatrix[i]) {
//.….
}
}
I don't know why the book uses _m for max number of row-ptr. It wasn't even a variable define in class; the variable for max row is mNumRows. Maybe it is some compiler pre-defined variable? Another thing I am quite confuse is why is it ++i? pre-operator, why not i++? Will it make different if I change it into i++?
Another thing I am quite confuse is why is it ++i? pre-operator, why not i++? Will it make different if I change it into i++?
Because ++i is more natural and easier to understand: increment i and then yield the variable i as a result. i++ on the other hand means copy the current value of i somewhere (let's call it temp), increment i, and then yield the value temp as a result.
Also, for user-defined types, i++ is potentially slower than ++i.
Note that ++i as a loop increment does not imply the increment happens before entering the loop body or something. (This seems to be a common misconception among beginners.) If you're not using ++i or i++ as part of a larger expression, the semantics are exactly the same, because prefix and postfix increment only differ in their result (incremented variable vs. old value), not in their side effect (incrementing the variable).
Without seeing the entire class code, it is hard to tell for your first question, but if it hasn't been defined as part of the class, my guess would be that it is a typo.
as for your second question, ++i vs. i++, the prefix increment operator (++i) returns the object you are incrementing, whereas the postfix increment operator returns a copy of the object, in the objects original state. i.e.-
int i=1;
std::cout << i++ << std::endl; // output: 1
std::cout << i << std::endl // output: 2
std::cout << ++i << std::endl // output: 3
as for will the code change with the postfix- no, it works the same in loops, and makes basically no difference in loops for integer types. For user defined types, however, it may be more efficient to use the prefix increment, and is the style many c++ programmers use by default.
If the _mvariable isn't defined anywhere this is an error. From that context it looks like it should contain the number of rows that are allocated with new somewhere (probably in the constructor, or there might be methods like addRow). If that number is always mNumRows, than this would be appropriate for the loop in the destructor.
If you use ++i or i++ in that for loop doesn't make any difference. Both variants increment the integer, and the return value of the expression (that would be different) isn't used anywhere.
I can't speak to the first part of the question, but I can explain the pre- versus post- increment dilemma.
Prefix versions increment and decrement are slightly more efficient and are generally preferred. In the end, though, the extra overhead caused by using i++ over ++i is negligible unless the loop is being executed many, many times.
As others have said, the prefix operator is preferred for performance reasons when dealing with user-defined types. The reason it has no impact on the for loop is because the test involving the value of the variable (i.e. i < _m) is performed before the operation that modifies the variable is performed.
The real mess with this book is the way it illustrates a 2x2 matrix. The problem is here that for 4 elements you have 3 blocks of memory allocated, and not only does it slows down the program but it is certainly much more tricky to handle.
The usual technic is much simpler:
T* mData = new T[2*2];
And then you access it like so:
T& operator()(size_t r, size_t c) { return mData[r * mNbRows + c]; }
This is a bit more work (you have to multiply by the number of rows if you are row major), but then the destroy is incredibly easy:
template <class T>
void Table<T>::destroy()
{
delete[] mData;
mData = 0;
mNbRows = 0;
mNbColumns = 0;
}
Also note that here there is no need for a if: it's fine to call delete on a null pointer, it just doesn't do anything.
Finally, I have no idea why your book is using int for coordinates, do negative coordinates have any meaning in the context of this Table class ? If not, you're better off using an unsigned integral type (like size_t) and throwing the book away.