References, Logical Operators, and Loop Condition - c++

I'm having a problem understanding what I'm doing wrong in my code. What I'm trying to do is write a condition for a ternary operator and a do-while loop to recognize if one of my variables is above 1. Well, it is giving me an error that I don't know how to fix. What puzzles me the most is what I'll give an example of shortly. Here's my overall code. Keep in mind I'm a beginner, so there may be things that make you cringe or parts that could be improved.
#include <iostream>
using namespace std;
void getInfo(int&, int&, double&);
int main() {
int ordered, stock;
double charges = 10.00;
getInfo(ordered, stock, charges);
system("pause");
return 0;
}
void getInfo(int& ordered, int& stock, double& charges) {
do {
printf("Enter the amount of spools ordered, in stock, and handling charges: ");
scanf_s("%i %i %lf", &ordered, &stock, &charges);
printf((&ordered > 1 && &stock > 0 && &charges > 0) ? "All added!\n"
: "You messed one up. AGAIN!\n");
} while (&ordered > 1 && &stock > 0 && &charges > 0);
}
Now, the error I'm getting is specifically in the ternary and the while condition. It gives me an error where the > is after ordered for both. Now, if I make it ordered instead of &ordered, the error goes away. Yet, I never get an error for &stock or &charges. I don't know why it's treating &ordered differently. It also doesn't check ordered correctly when I take off the &, for reasons I'm not entirely sure on.
Thank you to whomever is willing to help!

...(&ordered > 1 && &stock > 0 && &charges > 0) ? "All added!\n"
Here, "&ordered" means "the address of the ordered variable. You're obviously not trying to compare the address of ordered, but rather ordered itself. This should be
...(ordered > 1 && stock > 0 && charges > 0) ? "All added!\n"
The same problem is with your while() statement too.
In C++, "&" means two things. In declarations, it's used to declare a reference. In expression, it's the "address of" operator.
Once you declare a reference, like:
int &whatever;
Subsequently, using just whatever refers to the referenced object itself.
: "You messed one up. AGAIN!\n");

The & operator does different things depending on where you put it. If it's in a type declaration (e.g. int& foo), it means that the type is a reference. If however the & is used as an unary operator in an expression it becomes the Address-of operator, and returns a pointer to the object it's used on. So for example int* bar = &spam (assuming spam is an integer) would assign a pointer to spam in in the pointer bar.
Note that reference types behaves identical to the real type. This is perhaps better illustrated with a piece of code:
#include <iostream>
int main() {
int foo = 12;
int& bar = foo; // a reference expects a variable of the same type in the initializer
bar = 24; // Once the reference has been made the variable behaves indentically to the
// to the variable it's a reference to.
std::cout << foo << std::endl; // outputs 24
// if you use the & operator on a reference you get the address the variable it is a
// reference to.
std::cout << &bar << ' ' << &foo << std::endl; // Outputs two equal addresses.
}
There is also a third meaning of & in C++. As the bitwise and operator. foo & bar would result in the bitwise and of the variable foo and bar.

Related

Strange behavior when initializing template structure

I have a structure:
template < class L, class R > struct X {
X()
{ }
friend std::ostream& operator<<(std::ostream& str, X& __x)
{
return str << '(' << __x.__val1 << ", " << __x.__val2 << ')';
}
private:
L __val1;
R __val2;
};
and create it without initializing anything:
X<std::size_t, std::string> x;
std::cout << x << std::endl;
It always gives output: (2, )
But, when i do:
X<std::string, std::size_t> x;
std::cout << x << std::endl;
I have "right" behaviour with uninitialized variable: (, 94690864442656).
Why?
There is no "right" value of an uninitialized variable.
The value is said to be "indeterminate". Using an indeterminate value leads to undefined behavior. Your program could output anything or nothing.
Assuming (, 94690864442656) to be "right", because it looks like some "uninitialized value" while (2, ) looks like something was initialized, is wrong.
2 is just as wrong as 94690864442656. When the behavior of your code is undefined, then it is undefined.
If it helps, think of it like this: You are supposed to calculate the result of 2*3. Instead of actually carrying out the calculation you call the number that comes to your mind in that moment. Most of the time you will say the wrong result. Once in a while you will answer with a result that looks meaningful, because you correctly guessed 6, or you said 5 or 7 which is just off by one. However, getting the expected result sometimes, does not imply that your way of getting the result is correct.
Or consider this: (but be careful with the use of randomness here. Uninitialized values are not random!) Suppose instead of calculating the result of 2*3 you use the wrong way of rolling a dice (instead of actually calculating the number). Now assume you roll a 6. Would you be surprised to get the "correct" result, even though your algorithm is wrong?
If you really care why you get 2 in one case and 94690864442656 in the other, you need to study the assembly generated by the compiler, because C++ does not specify what is the outcome of compiling code with undefined behavior. It just says: It is undefined.
Note that also using identifiers that contain a double underscore is not allowed, as such names are reserved (https://en.cppreference.com/w/cpp/language/identifiers).

putting a '&' after the type [duplicate]

This question already has answers here:
ampersand (&) at the end of variable etc
(5 answers)
Closed 3 years ago.
I am fairly new to programming. I am just moving on to C++ from C in my college courses, and I encountered something that I haven't seen before in C. Sometimes after the type, either in a function declaration or passing a parameter, a & immediately follows the type. For example, we use a struct called Customer in one of our projects, and some of the functions pass Customer&. Why is the ampersand after the type, as opposed to in front? Thanks!
References in C++ simply allow for a cleaner way to execute the following code:
int x = 16;
int* y = &x;
cout << *y;
Which could be written instead as
int x = 16;
int& y = x;
cout << y;
When defining functions, a reference allows a function to change the value of parameters without causing the user of the function to put an ampersand before everything. E.g.
void func( int& a )
{
a = 5;
}
void main()
{
int A = 10;
func( A );
cout << A; // Will output '5'
}
Be careful with this type of mutation, as a programmer using functions like this without checking the implementation might not realize that the function is changing the value of the parameters unless the intent is obvious. init_server(my_server) would be an example of a case where it's obvious, but to_json(my_struct) would clearly be an example where you should not be using a reference to change the struct in any way.
But, one of the most important uses of references, would be function like
int sum_vector( const vector<int>& a ) {
int sum = 0;
for( int i = 0; i < a.size(); i++ ) {
sum += a[i];
}
return sum;
}
If you tried to make sum_vector take in a vector, and you passed in a vector with 100 million entries, then it would have to copy them all over, taking forever. You could take in a pointer, but then the internal parts of the function would have to constantly dereference, and it must called with sum_vector(&myvec), which is more annoying than sum_vector(myvec). In this way, using a const reference, you can prevent the highly inefficient copying of the whole vector into the function body, while keeping syntax neat. Using const lets you reassure yourself that you're not going to change the vector that you were given. And, it also assures the user of your function that you won't change it. Similarly, void to_json(const some_struct&) would be a better function definition as it ensures you won't change the user's data.

could not convert from 'unsigned int' to 'unsigned int&'

I'm creating a method and one parameter of that method asks for a reference of an unsigned int, but I want to put a default value on that parameter. For example:
#include <iostream>
using namespace std;
class A {
public:
void sender();
private:
unsigned int score = 10;
};
class B {
public:
void receiver(unsigned int & score);
};
void A::sender() {
cout << "Before: " << score << endl;
B b;
b.receiver(score);
cout << "After: " << score << endl;
}
void B::receiver(unsigned int & score) {
score = 100;
}
int main() {
A a;
a.sender();
return 0;
}
Live demo: in here
The error happen when I do this:
void receiver(unsigned int & score = 10u);
And the compiler returns:
error: could not convert ‘10u’ from ‘unsigned int’ to ‘unsigned int&’
Live demo: in here
You cannot assign a literal1 to a non-const reference.
There are two scenarios where one will suit your situation:
You intend to modify the argument being passed to receiver()
If that is the case, the use a non-const reference (unsigned int & score) without the default parameter. In situations where you pass a literal or temporary object to it, then it will result in a compiler error.
a.receiver(10); // Error
The above wouldn't make any much sense considering that you want to modify that argument (you wouldn't see the modification if C++ had allowed that2).
You intend to just use the parameter in a read-only fashion
Just use plain, non-reference, unsigned int, because const unsigned int& score is just a pain to write. In cases where you determine that an object is expensive to copy, then that is the time where you should have the parameter a const reference.
UPDATE: There are some cases where you want to modify something, but that something may or may not exist. In cases like that, you may want to use a non-owning pointer as the parameter.
// Declaration
void receiver(unsigned int* score = nullptr);
void B::receiver(unsigned int* score) {
if(score) *score = 100;
}
...
a.receiver(); // Uses the default parameter
unsigned int x;
a.reciever(&x);
In this case, it only assigns to score when it points to some (assumed) valid variable. Pointers aren't that bad at all.
UPDATE 2: However, as #Potatoswatter have pointed out, you may be better off with function overloading.
void B::receiver() {
// Do something else
}
void B::receiver(unsigned int& score) {
score = 100;
}
You should use this in cases where you want your overloads to behave differently on different parameters.
However again, I prefer the first, non-default parameter option, rather than the pointer option and the overloading option, as it requires that the caller provide a parameter, which is much better when you are modifying something through a function.
UPDATE 3: You should also consider to have your function return the value instead of modifying it through a parameter. In cases where you don't need the current state of the object being modified, having a function return a value is much more intuitive. One caveat though is that the caller may forget to capture (assign) the return value, which could be dangerous if you are using that value as some resource ID to free something up.
1 And in general, a temporary object.
2 And the universe would probably blow up if 10 was magically transformed into 100 ;)
You want the argument type to be const unsigned int&. Otherwise, you can do something crazy, like try to assign 10 = 20, which doesn't make sense.
And that happens to be exactly that you did. The score = 100 line doesn't seem to be what you actually meant.
the value "10" isn't a reference- it's a value. By having a by-reference parameter, it must be called with a reference. Using a default parameter means you could call the function without specifying the parameter and the compiler would use the default.
Similarly, calling b.receiver(10); is not valid, but
int someInt = 10;
b.receiver(someInt);
is valid.

what is the value of an array element if I don't assign it myself

what would be the result if I wrote this
int array1[2];
cout << array1[0] ;
and how can I do this pseudocode :
if array1[0] doesn't have a value then assign its value to 1
I'm using C++ on DevCPP
The elements of array are uninitialized, and it is undefined behaviour to read them before writing to them. Your program is ill-formed. There is no way to "check" for this; it is your responsibility to write a correct program.
The initial value of unassigned array values is undefined (unless the array element type is a class/struct, in which case the default constructor will be called for each array element). In your first example, the behavior is undefined since you have not initialized the array element before using it.
If you want to retain an "unassigned" status then you need to use a class that encapsulates this, for example using the nullable pattern for value types.
Consider using Boost.Optional: you'd declare the array as boost::optional<int> array1[2]; and then you can test if (array1[0]) to see if that particular element has a value.
There is one point that the answers I'm seeing thus far seem to have missed. It depends on where your array is defined.
If the array is local to a function, like:
int f() {
int array1[2];
cout << array1[0] ;
}
...then the other answers are correct: the content of array1 contains unspecified values, and your attempt to read the value and send it to cout gives undefined behavior.
On the other hand, you may have defined array1 as a global variable:
int array1[2];
int f() {
cout << array1[0];
}
In this case, the content of array1 is required to be initialized to 0 for any arithmetic type (or NULL for an array of pointers). In a case like this, writing out the value in array1[0] is perfectly fine and gives defined results -- it must be 0. In this case, there is no any way to tell whether an element of an array containing the value 0 has that value because it was automatically initialized to 0, or was assigned that value later.
If you really need to know whether a value has been written to a variable, it's possible to write a class that will do that:
template <class T>
class value {
T val;
bool assigned;
public:
value(T const init=T()) : assigned(false), val(init) {}
value &operator=(T const &t) {
assigned = true;
val = t;
}
operator T() { return val; }
bool was_assigned() { return assigned; }
};
// ...
value<int> array2[2];
if (!array2[0].was_assigned())
array2[0] = 1;
It's usually easier and more efficient to just define the type to always start out initialized to a known value, so you never really care about whether it's been assigned to or not though. In short, although this supports what you've asked for, my immediate reaction is that there's probably a better/cleaner way to accomplish your ultimate goal. Before you even consider using something like this, I'd strongly recommend stepping back from what you're doing, and trying to figure out if there's a better way to do it. My guess is that there is/will be (and if you can't find it, you might want to ask another question, telling us about why you're trying to do this, to see if somebody can see a more direct way to accomplish your goal).
As far I remember that depend on the OS
As other users said, you need to initialize a then use a for loop to test each value one by one and modify them, if they fulfill a condition, I leave you a C snippet:
/* Variable declaration and initialization to 0s (You can use another value as default )*/
int a[ 5 ] = { 0 };
/* If the array[ i ] has 0 as value */
for( i = 0; i < 5; i++){
if ( a[ i ] == 0 ){
a[ i ] = 1;
}
}
If you don't initialise the element yourself, the element will obtain the value from the memory location it is stored on now (and will most probably convert it to its data type). Consider this program :
#include <iostream>
using namespace std;
int foo(int A[])
{
cout << A[0] << A[1];
}
int main()
{
int array[2];
foo(array);
}
This will give the output 00.
But now consider this code :
int main()
{
int array[2];
cout << array[0] << array[1];
}
It will give some random integer output. This is so because the uninitialised array picks up the value stored on the memory location it now occupies. You can check its memory adress by &array[0] and print it in different data types for some thought provoking questions.
eg: cout << &array[0] << char(array[0]) << bool(array[0]) etc.

Using the comma operator in if statements

I tried the following:
if(int i=6+4==10)
cout << "works!" << i;
if(int i=6+4,i==10)
cout << "doesn't even compile" << i;
The first works fine while the second doesn't compile. Why is this?
EDIT: Now I know that the first one may not work as I intend it to. The value of i inside the if scope will be 1, not 10. (as pointed out by one of the comments on this question).
So is there a way to initialize and use a variable inside of an if statement at the same time similar to for(int i=0;i<10;i++)? So that you could produce something like if((int i=6+4)==10) (which will not compile) where the value of I inside the if scope would be 10?
I know you could declare and initialize I before the if statement but is there a way to do this within the statement itself?
To give you an idea why I think this would be usefull.
if(int v1=someObject1.getValue(), int v2=someObject2.getValue(), v1!=v2)
{
//v1 and v2 are visible in this scope
//and can be used for further calculation without the need to call
//someObject1.getValue() und someObject2.getValue() again.
}
//if v1==v2 there is nothing to be done which is why v1 und v2
//only need to be visible in the scope of the if.
The expression used as an initializer expression must be an assignment-expression so if you want to use a comma operator you must parenthesize the initializer.
E.g. (not that what you are attempting makes much sense as 6 + 4 has no side effects and the value is discarded and i == 10 uses the uninitialized value of i in its own initializer.)
if (int i = (6 + 4, i == 10)) // behaviour is undefined
Did you really mean something like this?
int i = 6 + 4;
if (i == 10)
When using the form of if that declares a new variable the condition checked is always the value of the initialized variable converted to bool. If you want the condition to be an expression involving the new variable you must declare the variable before the if statement and use the expression that you want to test as the condition.
E.g.
int i;
if ((i = 6 + 4) == 10)
I doubt seriously either example works to do anything useful. All that it does is evaluate to "true" in a complicated fashions.
But the reason the second one doesn't compile is that it's interpreted as two declarations: int i = 6+4; int i==10 and int i==10 isn't valid because that's an equality operator, not an assignment.
There are different alternatives, because what you want cannot be done (you cannot mix the comma operator with declarations). You could, for example, declare the variable outside of the if condition:
int i = 6+4;
if ( i == 10 ) ...
Or you can change the value of i to be 0 instead of 10 and recalculate i inside the else block:
if ( int i = (6+4)-10 ) ; else {
i += 10;
// ...
}
Much simpler, don't declare the variable at all, since you know the value inside the loop:
if ( (6+4)==10 ) {
int i = 10;
// ...
}
Unless of course you need the value of i in the case where it is not 10, in which case the second option is the most appropriate.
As of C++17 what you were trying to do is finally possible:
if (int i=6+4; i==10)
cout << "works, and i is " << i << endl;
Note the use of ; of instead of , to separate the declaration and the actual condition.