I recently stumbled upon following code
int array[] = {10, 20, 30};
cout << -2[array];
I understand that array is a pointer to the first element of the array but then what does [pointer] means and then we write -2 in front of it which looks very alien to me.
It is the same as if you'd write
cout << -(2[array]);
which is the same as
cout << -(array[2]);
In C++ operator [] on an array simply offsets the address of the array by the number specified in the brackets. As with any addition, you can swap operands and the result will remain the same.
For example -0[array] will give you -10 in this case.
There are two ways to access an array element via a pointer offset. One is the common
int array[] = {10, 20, 30};
cout << -array[2]; // prints -30
and one is the unusual one that you posted. Both versions are equivalent.
Note that as the unary minus operator has a lower precedence compared to the subscript operator, -2[array] does not involve a negative index, but instead is the same as -(2[array]).
In C and C++ the place of array name and the index can be swapped without changing the meaning i.e. -2[array] and -array[2] are the same. Both will compile and do the same thing. Check this SO post
However, if you try this in a language like C# or Java you will get a compiler error saying Cannot apply indexing with [] to an expression of type 'int' or something similar. This is a good example to understand how code works if the language supports pointers vs if it doesn't.
Note, as pointed out in the comment, negation operator has lower precedence over array index operator so it will compute to -array[2] instead of array[-2]
Related
I decided to compile and run this piece of code (out of curiosity) and the G++ compiler successfully compiled the program. I was expecting to see a compile error or a runtime error, or at least the values of a and b swapped (as 5 > 1), since the std::sort() function is being called with two pointers to integers.
(Please note that I know this is not a good practice and I was basically just playing with pointers)
#include <iostream>
#include <algorithm>
int main() {
int a{5};
int b{4};
int c{1};
int* aptr = &a;
int* bptr = &b;
std::sort(aptr, bptr);
std::cout << a << ' ' << b << ' ' << c << '\n';
return 0;
}
However, upon executing the program, the output I got was this:
5 4 1
My question is, how did C++ allow this call to the std::sort() function? And how did it not end up actually sorting everything between the memory addresses of a and b (potentially including even garbage values in memory)?
I mean, if we tried this with C-style arrays like this (std::sort(arr, arr+n)) it would successfully sort the C-style array, because arr and arr+n are basically just pointers where n is the size of the array and arr is the pointer to the first element.
(I'm sorry if this question sounds stupid. I'm still learning C++.)
Your program is ill formed, no diagnostic required. You passed pointers that do not form a range to a std algorithm.
Any behaviour whatsoever by the program is conforming to the C++ standard.
Compilers optimize around the fact that pointers to unrelated objects are incomparable and their difference is undefined. A sort here would trip over so much UB the optimizer could eliminate branches like crazy (as any branch with UB can be eliminated and replaced with the alternative (whatever code the alternate branch is a legal result of UB)).
Good C++ coding style thus focuses on avoiding UB and IL-NDR code.
C++ accepts your code as it is syntactically right. But it doesn't work because sort(it1, it2) expects it1 one to be some starting position of an array and it2 to be the ending position of the same array. you have provided two different arrays to the sort function which can yield any of two following situations:
positionof(it1) < positionof(it2): suppose in computer's memory array a and b are stored in the like this- 5(a), -1, -2, 10, 4(b). then the sort function will sort from 5 to 4 resulting in : -2(a),-1,4,5,10(b).
positionof(it1) > positionof(it2) (your machine's case): the sort function will do nothing as left_position > right_position.
This question already has answers here:
Why does i[arr] work as well as arr[i] in C with larger data types?
(5 answers)
Closed 7 years ago.
The following code
#include<stdio.h>
int main()
{
int arr[] = {10,20,30};
cout << -2[arr];
return 0;
}
prints -30. How? Why?
In your case,
cout<<-2[arr];
gets translated as
cout<<-(arr[2]);
because,
array indexing boils down to pointer arithmatic, so, the position of array name and the index value can be interchanged in notation.
The linked answer is in C, but valid for C++ also.
regarding the explicit ()s, you can check about the operator precedence here.
Look at this statement
cout << -2[arr];
First, know that even though it looks strange the following is true
2[arr] == arr[2]
That being said operator[] has higher precedence than -. So you are actually trying to invoke
-(arr[2])
In C and C++, 2[arr] is actually the same thing as arr[2].
Due to operator precedence, -2[arr] as parsed as -(2[arr]). This means that the entire expression evaluates to negating the 3rd element of arr, i.e. -30.
I wrote a simple code as follows:
void show(const int a[], unsigned elements);
int main()
{
show(new int[]{1, 2, 3, 45}, 4); //does not work
}
void show(const int a[], unsigned elements)
{
cout << "{ ";
for (int i = 0; i < elements; i++)
{
cout << a[i];
if (i != elements - 1)
cout << ",";
cout << " ";
}
cout << "}";
}
It should just output { 1, 2, 3, 45 }. If I include a size in the brackets
show(new int[4]{1, 2, 3, 45}, 4);
then it works. So naturally I would assume that if I write the new this way I have to specify the size (although I thought that giving it an initialization list would imply the size). But, the odd thing is that when set a breakpoint at the show function call and I run it step by step through the debugger, the program outputs everything correctly and terminates at the end of main like it should. If I don't use the debugger, it either crashes after outputting a '{' or it outputs the whole thing "{ 1, 2, 3, 45 }" and an assertion failure " Program: ... "Expression: _CrtIsValidHeapPointer(pUserData) ... "
I'm curious to know why it is behaving this way. Also, I am using Visual Studio on Windows 8.
EDIT: I am using namepsace std. Please don't comment about using namespaces or about how to better write this code. I'm solely interested in the cause of this issue.
EDIT Responding to additional question in comment.
To be quick, yes it would "still" be a pointer, and yes it compiles with clang and gcc when you add the 4.
There are a couple things going on, however, and my initial answer was a simplification. The problem is that your expression is not well-formed to begin with, so it's not clear what it should evaluate to or what the type should be. Consider
If type is an array type, all dimensions other than the first must be specified as positive integral constant expression (until C++14)converted constant expression of type std::size_t (since C++14), but the first dimension may be any expression convertible to std::size_t.
Source: http://en.cppreference.com/w/cpp/language/new
As it says, either way there must be an expression in the brackets. This makes it difficult to say whether the expression would still evaluate to a pointer. A well-formed new expression would indeed evaluate to a pointer, no matter how many dimensions it has, even if it has zero. When I say pointer here, I strictly mean the representation, not the type.
The point is that the type, at least "inside" new, is different depending on how many dimensions you have. So, whether you do
new int
new int[6]
new int[12][14]
the representation is the same (a pointer), but the type new sees is different in each case. The compiler is able to respond to the different types in new (think by analogy with function overloading). In particular, when the type is an array type, it is possible to initialize the new memory with the braced initializer list containing multiple elements.
My best guess is, since VS was accepting the brackets without an expression, it was allocating memory for either a single int or int[0]. In the former case, it was wrongly allowing you to brace initialize it as if it was an array type, and in the latter case the allocated memory was not enough anyway. Your main then wrote over a heap guard that is there to catch this sort of thing in debug mode. When this was checked at the end of main or at program termination, you saw the symptoms. The flakiness in the output was either due to different heap layouts or due to buffering in the output stream.
Original answer
Your new expression, if it was well-formed, would have scalar type, meaning that the result is a "single value". That single value is a pointer to an integer, specifically to the one at the beginning of the array you are trying to create. That is how "dynamic arrays" are represented in C++. The type system does not "know" their size.
You are trying to initialize this single pointer value with an initializer list of 4 values. This shouldn't work. I am not sure that this should compile at all. It certainly didn't compile with clang or gcc, and I'm surprised that it worked in Visual Studio.
this cold be really obvious but I havent done C++ in about 15 years so thanks in advance.
I have a 2D array of strings and when I read from it I get this:
0x22fc90
Here is my code, any ideas?
std::string results[3][3] = {
{"Draw", "Win", "Lose"} , /* initializers for row indexed by 0 */
{"Lose", "Draw", "Win"} , /* initializers for row indexed by 1 */
{"Win", "Lose", "Draw"} /* initializers for row indexed by 2 */
};
cout << "It's a " << results[choice,compChoice];
choice and compChoice are integers
There is a difference between for example the C++ syntax and the C# syntax for multidimensional arrays. What you wrote in this statement relative to accessing an element of the array
cout << "It's a " << results[choice,compChoice];
is valid in C# and does what you mean.
In C++ this statement
cout << "It's a " << results[choice,compChoice];
is also valid but its meaning is different. There is used the so-called comma operator in the subscript operator results[choice,compChoice] that in fact is equivalent to results[compChoice] except that the first subexpression will not be evaluated. So results[compChoice] gives a row of the two-dimensional array and operator<< outputs its address.
What you want is the following
cout << "It's a " << results[choice][compChoice];
Access the array using results[choice][compChoice].
That's because two dimensional arrays are actually arrays of arrays.
First you need to go into results[choice] and then you select [compChoice] from that.
choice,compChoice just evaluates to compChoice, so you are just outputting the pointer to the start of the choiceth array in results. Use results[choice][compChoice] instead.
results is an array of arrays. Try accessing via
results[choice][compChoice]
So results[choice] "returns" an array that you can access with another [] operator. As far as I know, multiple indices aren't supported in one pair of brackets.
Thanks everyone.Am glad it was a syntax issue am not me missing the point completely!
I'm not sure if the term's actually "Array Addition".
I'm trying to understand what does the following line do:
int var[2 + 1] = {2, 1};
How is that different from int var[3]?
I've been using Java for several years, so I'd appreciate if explained using Java-friendly words.
Edit: Thousands of thanks to everyone who helped me out, Occam's Razor applies here.
It's not different. C++ allows expressions (even non-constant expressions) in the subscripts of array declarations (with some limitations; anything other than the initial subscript on a multi-dimensional array must be constant).
int var[]; // illegal
int var[] = {2,1}; // automatically sized to 2
int var[3] = {2,1}; // equivalent to {2,1,0}: anything not specified is zero
int var[3]; // however, with no initializer, nothing is initialized to zero
Perhaps the code you are reading writes 2 + 1 instead of 3 as a reminder that a trailing 0 is intentional.
It is any different from int var[3]. The compiler will evaluate 2 + 1 and replace it with 3 during compilation.
How is that different from int var[3]?
In no way that I can see.
It isn't any different; it is int var[3].
Someone might write their array like this when writing char arrays in order to add space for the terminating 0.
char four[4 + 1] = "1234";
It doesn't seem to make any sense working with an int array.
var[2 + 1] is not different from var[3]. The author probably wanted to emphasize that var array will hold 2 data items and a terminating zero.
This creates an array of 3 integers. You're right, there is no difference whether you express it as2 + 1 or 3, as long as the value is compile-time constant.
The right side of the = is an initializer list and it tells the compiler how to fill the array. The first value is 2, the second 1 and the third is 0 since no more values are specified.
The zero fill only happens when you use an initializer list. Otherwise there is no guarantee of that the array has any particular values.
I've seen this done with char arrays, to emphasize that one char is reserved for a string terminator, but never for an int array.