How does this overloading of square brackets work [duplicate] - c++

This question already has answers here:
How does cout << " \n"[i == n - 1]; work?
(2 answers)
Is literal string indexing standard C?
(3 answers)
Closed 3 days ago.
I want to avoid printing space (" ") or an underscore ("_") after the last element of an array while printing them using a for loop. The problem mentions one of the way to do so, I want to understand how and why this happens.
vector<int> v1 = {1, 2, 3, 4, 5};
int n = v1.size();
for (int i = 0; i < n; i++) {
cout << v1[i] << "_"[i==n-1];
}
this prints 1_2_3_4_5 which is as expected.
I want to get around the working of this operator. How it functions and what other aspects does it cover.

There is nothing special going on with [] here. Its the usual element access. "_" is a const char [2] where first character is _ and the second is a null terminator \0.
You could do the same with a string:
vector<int> v1 = {1, 2, 3, 4, 5};
int n = v1.size();
for (int i = 0; i < n; i++) {
cout << v1[i] << std::string{"_"}[i==n-1];
}
Note, that std::string is an excepetion among containers and it is ok to read the \0 from str[str.size()].
\0 is not a printable character, hence you see the output you see.
Perhaps the code more clear if you use an empty string explicitly:
vector<int> v1 = {1, 2, 3, 4, 5};
std::vector<std::string> d{ "_",""};
int n = v1.size();
for (int i = 0; i < n; i++) {
cout << v1[i] << d[i==n-1];
}
Alternatively, as you are using an index based loop anyhow (rather than a range based loop, which should be prefered), you can start the loop at the second element:
std::vector<int> v1 = {1, 2, 3, 4, 5};
std::vector<std::string> d{ "_",""};
int n = v1.size();
if (n) std::cout << v1[0];
for (int i = 1; i < n; i++) {
std::cout << "_" << v1[i];
}

In this statement
cout << v1[i] << "_"[i==n-1];
the expression "_"[i==n-1] is an expression with the string literal "_".
String literals have types of constant character arrays. The literal "_" has the type const char[2] and is represented in memory like
{ '_', '\0' }
So the expression "_"[i==n-1] uses the subscript operator with the string literal that is with an array. The expression i == n-1 is always equal to false that is converted to integer 0 when i is not equal to n-1. Otherwise it is equal to true that is converted to 1.
So you have either "_"[0] that yields the character '_' or "_"[1] that yields the character '\0';.
That is when i is not equal to n-1 you in fact have
cout << v1[i] << '_';
and when i is equal to n -1 you in fact have
cout << v1[i] << '\0';
Pay attention to that in this expression "_"[i==n-1] the string literal is implicitly converted to pointer to its first element.
Alternatively you could write with the same effect
vector<int> v1 = {1, 2, 3, 4, 5};
int n = v1.size();
const char literal[] = "_";
for (int i = 0; i < n; i++) {
cout << v1[i] << literal[i==n-1];
}
To enlarge your knowledge bear in mind that this expression "_"[i==n-1] you may also rewrite like ( i == n-1 )["_"] though such an expression will only confuse readers of the code.
From the C++17 Standard (8.2.1 Subscripting)
1 A postfix expression followed by an expression in square brackets is
a postfix expression. One of the expressions shall be a glvalue of
type “array of T” or a prvalue of type “pointer to T” and the other
shall be a prvalue of unscoped enumeration or integral type. The
result is of type “T”. The type “T” shall be a completely-defined
object type.66 The expression E1[E2] is identical (by definition) to
*((E1)+(E2)) [ Note: see 8.3 and 8.7 for details of * and + and 11.3.4 for details of arrays. — end note ] , except that in the case of an
array operand, the result is an lvalue if that operand is an lvalue
and an xvalue otherwise. The expression E1 is sequenced before the
expression E2.
Pay attention to that this code snippet
vector<int> v1 = {1, 2, 3, 4, 5};
int n = v1.size();
for (int i = 0; i < n; i++) {
cout << v1[i] << "_"[i==n-1];
}
could look more clear using the range-based for loop. For example
std::vector<int> v1 = {1, 2, 3, 4, 5};
bool next = false;
for ( const auto &item : v1 )
{
if ( next ) std::cout << '_';
else next = true;
std::cout << item;
}
If the compiler supports the C++20 Standard then you can write also like
std::vector<int> v1 = {1, 2, 3, 4, 5};
for ( bool next = false; const auto &item : v1 )
{
if ( next ) std::cout << '_';
else next = true;
std::cout << item;
}

your problem has nothing todo with the subscript operator though
you just need to figure out when to print the _ or not based on the position in the array when printing.
#include <vector>
#include <iostream>
// using namespace std; ehr no don't do this
int main()
{
std::vector<int> v1{ 1, 2, 3, 4, 5 };
for (std::size_t i{ 0ul }; i < v1.size(); ++i)
{
if (i != 0ul) std::cout << "_";
std::cout << v1[i];
}
std::cout << "\n";
// with vector use range based for if you can
// and then it becomes
bool print_underscore = false;
for (const int value : v1)
{
if (print_underscore) std::cout << "_";
std::cout << value;
print_underscore = true;
}
std::cout << "\n";
return 0;
}

Related

Is there a binary search algorithm that takes a unary predicate rather than a search value?

I have this exercise:
Given an array of integers, find the first missing positive integer in linear time and constant space. In other words, find the lowest positive integer that does not exist in the array. The array can contain duplicates and negative numbers as well.
For example, input [3, 4, -1, 1] should give 2 and input [1, 2, 0] should give 3.
You can modify the input array in-place.
 
My implementation:
template <typename In_It>
int missingPositiveInt(In_It first, In_It last){
first = std::find_if( first, last, [](int x){return x > 0;} );
if(first == last || *first > 1)
return 1;
for( auto next = first; (++next != last) && ( !(*next - *first > 1) ); )
++first;
return *first + 1;
}
int main(){
std::vector<int> v{5, 2, -1, 7, 0};
std::sort(v.begin(), v.end());
std::cout << missingPositiveInt(v.cbegin(), v.cend()) << '\n';
v = {2, -1, 1, 0};
std::sort(v.begin(), v.end());
std::cout << missingPositiveInt(v.cbegin(), v.cend()) << '\n';
v = {5, 2, -1, 7, 0};
std::sort(v.begin(), v.end());
std::cout << missingPositiveInt(v.cbegin(), v.cend()) << '\n';
v = {3, 4, -1, 1};
std::sort(v.begin(), v.end());
std::cout << missingPositiveInt(v.cbegin(), v.cend()) << '\n';
v = {1, 2, 0};
std::sort(v.begin(), v.end());
std::cout << missingPositiveInt(v.cbegin(), v.cend()) << '\n';
std::cout << '\n';
}
The output:
1
3
1
2
3
The program works just fine but I use the algorithm std::find_if to find the first positive value in the sequence (sorted sequence) and that algorithm does a linear search.
As long as the input sequence is already sorted I want to use some binary search algorithm to speed the process.
I tried using std::binary_search but it requires an argument to be searched for. What I need is to get a version that takes a unary predicate and applies a binary search or any other faster algorithm to find the lowest positive value in the sequence so I can write:
auto it = binary_search(first, last, [](int x){ return x > 0; });
Is it possible? Is my code fine or I need to modify it. So any suggestion, hint is highly appreciated.
Yes, std::partition_point does exactly what you want.
Partial solution based on #numzero's answer. This doesn't handle negative numbers or zero in the array but you can handle that by linearly preprocessing the array to remove them beforehand. It just marks each index as "found" by negating it, then later looks for the first non negative value and thats the one. Even though its a partial solution it shows the core algorithm.
#include <iostream>
using namespace std;
int main() {
int arr[] = {1, 4, 6, 7, 2, 7, 7, 8, 3};
int arrSize = sizeof(arr)/sizeof(int);
for(int i=0; i<arrSize; ++i)
{
int val = abs(arr[i]);
if(val > 0 && val-1 < arrSize)
{
if (arr[val-1]>0)
{
arr[val-1] = -arr[val-1];
}
}
}
for(int i=0; i<arrSize; ++i)
{
if(arr[i] > 0)
{
std::cout << "Smallest is " << (i+1) << std::endl;
return 0;
}
}
std::cout << "Nothing found!" << std::endl;
// your code goes here
return 0;
}

In C++, how can I write a function that flips a 2d array at a specified position?

For my 2d array in C++, the 2d array needs to be flipped at a certain position. I have to write a function that flips the array
Foe instance,
Before:
double A[][2] = {{0,0}, {1,1}, {2,2}, {3,3}, {4,4}, {5,5}, {6,6}, {7,7}}
A B C D
call function invert(or flip): invert(A, 8, 3, 4);
after:
double A[][2] = { {0, 0}, {1, 1}, {2, 2},{6, 6}, {5, 5}, {4, 4}, {3, 3}, {7, 7}}
D C B A
Here is the attempt I have tried
#param A is the list of locations (x,y) of the cities in the current tour.
#param n is the number of cities in A.
#param start is the index of the beginning of the section to be inverted.
#param len is the length of the segment to invert(or flip).
void invert ( double A[][2], int n, int start, int len ) {
int(*tmp)[2] = new int[][2];
for(int i = 0; i >= A.length; i--){
for(int j = 0; j >= A[i].length; j--){
if( i > start)
tmp = A[i][j];
}
}
for(i = start; i < A.length; i++)
for(j = start; j < A[i].length; j++){
while (i <= end){
tmp = A[i][j];
}
}
}
The errors I have are
expressions must have class type
a value of type double cannot be assigned to an entity of type "double(*)[2]
cannot determine which instance of overload function "end" is intended
I am fully aware that most of the errors in my code are evident to find, but I needed to start somewhere.
I admit, I don't know how to do it with a 2D C-array. I can only tell you about the simple way to do it.
First, a general advice: Name your stuff. What if I had to read only your code to see that you are dealing with locations of cities, that have x and y coordinates, instead of having to read your text, wouldn't that be great?
Next, for resizable arrays, you can (/should) use std::vector instead of C-arrays. C-arrays decay to pointers when passed to functions. C-arrays have their size as part of their type, but it is inconvenient to access it (and impossible once decayed to a pointer). And manually resizing dynamic C-arrays isn't much fun either.
Eventually, the "simple way" is to use an existing algorithm. To reverse elements in a range it is std::reverse:
#include <iostream>
#include <vector>
#include <algorithm>
struct location {
int x;
int y;
};
int main() {
std::vector<location> cities{{0,0}, {1,1}, {2,2}, {3,3}, {4,4}, {5,5}, {6,6}, {7,7}};
for (const auto& loc : cities){
std::cout << loc.x << " " << loc.y << "\n";
}
std::cout << "\n";
std::reverse(cities.begin()+ 3,cities.begin() + 7);
for (const auto& loc : cities){
std::cout << loc.x << " " << loc.y << "\n";
}
}
Output:
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
0 0
1 1
2 2
6 6
5 5
4 4
3 3
7 7
Actually with a 1-D c-array it is almost the same. The major difference is that c-arrays do not have begin as member. This produces same output as above:
location cities2[] = {{0,0}, {1,1}, {2,2}, {3,3}, {4,4}, {5,5}, {6,6}, {7,7}};
for (const auto& loc : cities2){
std::cout << loc.x << " " << loc.y << "\n";
}
std::cout << "\n";
std::reverse(std::begin(cities2)+ 3,std::begin(cities2) + 7);
for (const auto& loc : cities2){
std::cout << loc.x << " " << loc.y << "\n";
}
And if you want to wrap it in a function you need to take care of the array decaying to a pointer:
void my_reverse(location* loc, size_t len, size_t first, size_t last){
std::reverse(loc + first, loc + last + 1);
}
(I choose last to be the last element to be reversed. Note that the algorithm takes an iterator to the element one past the last element to be reversed).
Complete example with all three variants: https://godbolt.org/z/WMdea7WP3
That's how I'd write the function if I knew it would always be used with 2 column arrays
void invert(double cities[][2], int size, int start, int len) {
if (size < 0 || len < 0)
return;
double tempCoordsX, tempCoordsY;
int endPos = start + len - 1;
for (int i = start; i < (start + len/2); i++) {
int mirroredPos = (endPos - (i - start)) % size;
tempCoordsX = cities[i][0];
tempCoordsY = cities[i][1];
cities[i][0] = cities[mirroredPos][0];
cities[i][1] = cities[mirroredPos][1];
cities[mirroredPos][0] = tempCoordsX;
cities[mirroredPos][1] = tempCoordsY;
}
}
I repeat: please name your stuff

How to erase an element of a vector and check for a condition on other elements

How do I erase an element one by one in a vector? I want to check the vector using some conditions after a specific element is removed.
I tried it in this way, but it doesn't work. What's wrong? v is already initialized
long long max = maxSubArraySum(v);
long long t = 0;
for(long long i = 0; i < n ; i++){
std::vector<long long> cv;
cv = v;
//cout << "i = " << i << "v = " <<v[i] << '\n';
cv.erase(find(cv.begin(),cv.end(),v[i])); // <—- wrong
// EDIT
// cv.erase(cv.begin()+i); <—- fix.
t = maxSubArraySum(cv);
//cout << "t = " << t << '\n';
if(t > max){
max = t;
//cout << max << '\n';
}
}
// cout << max << '\n';
}
}
For example, v = {1, -2 , 3, -2 ,5 },
I remove first 1, then maxSubArraySum will be for cv = {-2,3,-2,5 } which is 6 for this subarray {3,-2,5}.
Next I remove -2, then maxSubArraySum will be for cv = {1, 3,-2,5} which is 6 for this subarray {3,-2,5}
Next I remove 3, then maxSubArraySum will be for cv = {1, -2,-2,5} which is -2 for this subarray {-2,5}
Next I remove -2, then maxSubArraySum will be for cv = {1, -2, 3, 5} which is 8 for this subarray {3,5}
Next I remove 5, then maxSubArraySum will be for cv = {1, -2,3,-2} which is 4 for this subarray {1,-2,3}
How do I code it in C++?
EDIT :
I got the answer.
My code is was slightly off as it was deleting the first element find found. In case of duplicates, this showed the error.
So I changed it to delete indexes only.
Thank you.
You don't need to use find. Try this:
cv.erase(cv.begin()+i);
This will find the element at the ith position and delete it, using pointer arithmetic.
Declare the vector cv before the for loop (outside) and your problem will be solved. To simplify, use the v directly instead of making a copy
while (!v.empty()) {
v.erase(v.begin());
cout << endl;
long long t = maxSubArraySum(v);
if (t > max) {
max = t;
// cout << max << endl;
}
}

cout pointer to array item is printing out different value than expected

Why is it that my pointer value doesn't change when I print it to the console using this method:
int main()
{
int array[] = {1, 2, 3, 4, 5};
int *p = array;
p++;
*p = 100;
for ( int i = 0; i < 5; i++)
{
cout << *array + i << ", ";
}
return 0;
}
when I print this to the console I get 1, 2, 3, 4, 5. What is the pointer actually pointing to in this instance? In this example array[1] should have the value of 100 but it doesn't change.
I also know that if I start the array at 5 for example, the counter will just print in order up from 5. What is happening behind the scenes to cause this to happen?
*array resolves to the first element of the array. *array + i adds i to that element because due to operator precedence it is parsed as (*array) + i. So your loop prints 1 + 0, 1 + 1, etc.
If you want to print the elements of the array, you can do this:
for (auto e : array) cout << e << ", ";
If you want to use pointer arithmetic explicitly, the you will have to use parentheses in the right places:
for ( int i = 0; i < 5; i++)
cout << *(array + i) << ", ";
You're printing array[0] + i i.e. 1 + i for i in [0, 5). No way has binary + operator higher precedence than unary *. Use parentheses around + to form the right expression:
*(array + i) // or array[i]
Try
cout << *(array + i) << ", ";

Adding to Individual Array Elements - C++

I need to add either +0.25 or -0.25 to all elements within an array. Here is what I have so far. Any help would be appreciated.
int main() {
double i;
// Arrays
double x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
double x2[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(i=1; i<=10; i++) {
const double pM[2] = {-1, 1};
int randoid = rand() % 2;
for(i=1; i<=10; i++){
x2[i] = x[i] + pM[randoid]*0.25; //Error Line
}
}
cout << x;
cout << x2;
}
I get this error at the marked line: "invalid types 'double[10][double] for array subscript"
The problem is that i is a double. Then you write x2[i].
It's not a very good error message; however with the [] operator, one of the operands must be a pointer and the other must be an integer. There is no implicit conversion of floating-point to integer when using this operator.
To fix this change double i; to int i;
Another issue is that your code accesses out of bounds of the arrays. double x2[10] means that there are 10 elements whose indices are 0 through 9. But your loop tries to write to x2[10]. This causes undefined behaviour, which could explain your strange output.
There is also a potential logic error. Maybe you meant to use a different variable for the inner loop than the outer loop. As it stands, the inner loop will take i to 11 (or 10 if you fix the code) and then the outer loop will be complete and not execute any more iterations.
Based on your description though, perhaps you only meant to have one loop in the first place. If so, remove the outer loop and just leave the contents there.
Also you do not need two separate arrays, you could just perform the addition in-place.
Regarding the output, cout << x and cout << x2 will output the number of the memory address at which the array is located. To output the contents of the array instead you will need to write another loop, or use a standard library algorithm that iterates over containers.
I see 3 issues -
Change the type of i to int.
x and x2 are arrays of size 10. You need to loop from i =
0 to i = 9. But you are looping from i = 1 to i = 10. x[10]
is out of bounds since arrays are 0 indexed.
cout << x - This is a wrong way to print an array. You need
to loop through the array and print - e.g. -
for(i = 0; i < 10; i++)
cout << x[i] << " ";
Try this, it works, I converted to C
int main( )
{
int i = 0;
// Arrays
double x[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
double x2[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for ( i = 1; i < 10; i++ )
{
const double pM[2] = { -1, 1 };
int randoid = rand( ) % 2;
for ( i = 1; i <= 10; i++ )
{
x2[i] = x[i] + pM[randoid] * 0.25; //Error Line
printf( "\nx[%d]==%2.2f", i, x[i] );
printf( "\nx2[%d]==%2.2f", i, x2[i] );
}
}
}