C++ compiler warning(?) when passing uninitialized local variable to function - c++

I'm very new to C++ so I'm hoping someone would shed some light. I came across several similar topics but I just need clarification.
So it seems it's valid to pass a local string that has been declared but not initialized to a function. But why does compiler complain when you try it with int or float??
Whether it's string, float, or int, memory address gets referenced when it is declared even tho it may be "garbage"
#include <iostream>
using namespace std;
void load(int);
int main()
{
int salary;
load(salary);
return 0;
}
void load(int sal)
{
cout << "your salary: " << endl;
cin >> sal;
cout << sal << endl;
}
If I declare int or float as global variable, it works as expected without any warnings.
So then is it a better practice to declare variable in global space (I hope not)?
So putting it in global, it works :
#include <iostream>
using namespace std;
int salary;
void load(int);
int main()
{
load(salary);
return 0;
}
void load(int sal)
{
cout << "your salary: " << endl;
cin >> sal;
cout << sal << endl;
}
ok, another example to show that uninitialized global variable works when passing to function as value : (going off of David's comment)
int foo;
int returnit(int j)
{
cout << "your salary";
cin >> j;
return j;
}
int main()
{
int k = returnit(foo);
cout << k;
return 0;
}
anyways, lesson here is to initialize primitive data types before passing to functions.

So it seems it's valid to pass a local string that has been declared but not initialized to a function. But why does compiler complain when you try it with int or float??
If by "string" you mean a std::string object, it's because objects are never uninitialized. When you do:
std::string s;
then the default constructor of std::string is invoked, and the object is initialized.
Variables of primitive data types (such as int and float), unless declared to have static storage duration, will have garbage if not explicitly initialized, however. Making attempts to read and use that garbage rightly trigger warnings. (Variables of primitive data types that do have static storage duration (i.e., global variables or variables declared as static) are implicitly initialized to 0.)
So then is it a better practice to declare variable in global space (I hope not)?
No, a better practice would be to initialize your variables.

The best way to explain why you should never use an uninitialized variable in a function call is because this is logically invalid and sometimes both logically invalid and the syntax is invalid.
To see if your program is logically valid use the box method and trace your program. Global box has global variables in it, int main has its own box which holds its local variables, and when functions are called create a new box for that function and fill it with its parameters and local variables. Go line by line and change variable values as they change in the program. Remember to use only constants as global variables. When writhing a function be careful when you pass by reference that you understand that the function is given that variables address in memory and can change that value. When using pass by value use this kind of syntax in your functions declaration:
int Multiplication(const int Var1, const int Var2);
This protects the values you pass to multiplication.The syntax of c++ is made for speed, and it does not keep you from being logically incorrect.

int salary;
load(salary);
What value do you think you are passing to load here? You're passing a nonsense value.
To be clear, you are not passing an "uninitialized variable", you are passing the value of an uninitialized variable. If you do:
int j=3;
load(j);
You are passing the value of j, that is, 3, to load. If you don't specify otherwise, C++ passes by value.
You'd have the same problem with a global variable:
int foo;
int returnit(int j)
{
return j;
}
int main(void)
{
int j=returnit(foo);
What value do you think j should have here?! You still have to initialize a variable to some particular value before you can pass its value to a function.

To add on David's answer, what you probably wanted to do (I'm guessing) is to modify the original salary variable. To do this you need to pass a reference to the variable, like this:
void load(int& sal)
{
cout << "your salary: " << endl;
cin >> sal;
cout << sal << endl;
}
Note the '&' after int in the function signature.
Also note that you use 'salary' in load() where it's not defined. You should use 'sal' instead.
That way the compiler knows that load() receives a reference to a variable, so if you modify it inside the function, the variable you sent to the function (salary) also changes.
The call itself to the function remains the same.

Related

How can I initialize a variable but when said function is initiated the value of the variable is not reset?

I've made this example to show what I'm talking about. I want to know if there is a way to run through main() without resetting value to 0.
int main(){
int value = 0;
value++;
cout << value << endl;
main();
}
Before answering the question, your example has two big problems
Calling, or even taking the address of, main is not allowed.
Your function has infinite recursion which makes your program have undefined behavior.
A different example where value is saved between calls could look like this. It uses a static variable, initialized to 0 the first time the function is called, and is never initialized again during the program execution.
#include <iostream>
int a_function() {
static int value = 0;
++value;
if(value < 100) a_function();
return value;
}
int main(){
std::cout << a_function(); // prints 100
}
If you want to keep the variable value local to the main function, you can declare it as static int value = 0;.
As has been pointed out in various comments though, recursively calling any function without an escape mechanism like you are is a bad idea. Doing it with main is a worse idea still apparently not even possible.

cant return a string from function

The problem i am having is when i compile my code, i get an error (uninitialized local variable "optionNumber used"
I am using visual studio 2017 on a macbook air for this.
here is my code:
#include "pch.h"
#include <iostream>
int runMenu(int optionNumber) {
std::cout << "Choose an option \n";
std::cout << "1) Create Array \n";
std::cout << "2) View Array \n";
std::cout << "3) Add/Delete Values \n";
std::cin >> optionNumber;
return(optionNumber);
};
int main()
{
int optionNumber;
int optionNum;
optionNum = runMenu(optionNumber);
std::cout << optionNum;
return(0);
}
int main()
{
int optionNumber;
^^^^^^^^^^^^^^^^
Here, you've declared a local variable. You've not provided an initialiser. Therefore the local integer has an indeterminate value. If you read an indeterminate value, the behaviour of your program will be undefined.
optionNum = runMenu(optionNumber);
^^^^^^^^^^^^
Here, you copy the variable whose value is indeterminate into an argument. Therefore the behaviour of the program is undefined. Luckily, your compiler noticed this mistake and warned about it.
Most trivial solution: Initialise the variable:
int optionNumber = 42;
On the other hand, you may want to think a bit about what you've written. The value that you pass to the function runMenu is never used in the function. Whatever value is passed in will be overwritten by whatever is extracted from standard input. The argument is completely pointless. Instead of an argument, you can read the input into a local variable:
int runMenu() {
// your std::cout stuff
int optionNumber;
std::cin >> optionNumber;

How is C++ function's default parameter passed?

Say I have the following code:
#include <iostream>
using namespace std;
int defaultvalue[] = {1,2};
int fun(int * arg = defaultvalue)
{
arg[0] += 1;
return arg[0];
}
int main()
{
cout << fun() << endl;
cout << fun() << endl;
return 0;
}
and the result is:
2
3
which make sense because the pointer *arg manipulated the array defaultvalue. However, if I changed the code into:
#include <iostream>
using namespace std;
int defaultvalue[] = {1,2};
int fun(int arg[] = defaultvalue)
{
arg[0] += 1;
return arg[0];
}
int main()
{
cout << fun() << endl;
cout << fun() << endl;
return 0;
}
but the result is still:
2
3
Moreover, when I print out the defaultvalue:
cout << defaultvalue[0] <<endl;
It turn out to be 3.
My question is, in the second example, should the function parameter be passed by value, so that change of arg will have no effect on defaultvalue?
My question is, in the second example, should the function parameter be passed by value, so that change of arg will have no effect on defaultvalue?
No.
It is impossible to pass an array by value (thanks a lot, C!) so, as a "compromise" (read: design failure), int[] in a function parameter list actually means int*. So your two programs are identical. Even writing int[5] or int[24] or int[999] would actually mean int*. Ridiculous, isn't it?!
In C++ we prefer to use std::array for arrays: it's an array wrapper class, which has proper object semantics, including being copyable. You can pass those into a function by value just fine.
Indeed, std::array was primarily introduced for the very purpose of making these silly and surprising native array semantics obsolete.
When we declare a function like this
int func(int* arg);
or this
int (func(int arg[])
They're technically the same. It's a matter of expressiveness. In the first case, it's suggested by the API author that the function should receive a pointer to a single value; whereas in the second case, it suggests that it wants an array (of some unspecified length, possibly ending in nullptr, for instance).
You could've also written
int (func(int arg[3])
which would again be technically identical, only it would hint to the API user that they're supposed to pass in an int array of at least 3 elements. The compiler doesn't enforce any of these added modifiers in these cases.
If you wanted to copy the array into the function (in a non-hacked way), you would first create a copy of it in the calling code, and then pass that one onwards. Or, as a better alternative, use std::array (as suggested by #LightnessRacesinOrbit).
As others have explained, when you put
int arg[] as a function parameter, whatever is inside those brackets doesn't really matter (you could even do int arg[5234234] and it would still work] since it won't change the fact that it's still just a plain int * pointer.
If you really want to make sure a function takes an array[] , its best to pass it like
template<size_t size>
void func (const int (&in_arr)[size])
{
int modifyme_arr[100];
memcpy(modifyme_arr, in_arr, size);
//now you can work on your local copied array
}
int arr[100];
func(arr);
or if you want 100 elements exactly
void func (const int (&arr)[100])
{
}
func(arr);
These are the proper ways to pass a simple array, because it will give you the guaranty that what you are getting is an array, and not just a random int * pointer, which the function doesn't know the size of. Of course you can pass a "count" value, but what if you make a mistake and it's not the right one? then you get buffer overflow.

Prototyping in C++

If I prototype a function above the main function in my code, do I have to include all parameters which have to be given? Is there a way how I can just prototype only the function, to save time, space and memory?
Here is the code where I came up with this question:
#include <iostream>
using namespace std;
int allesinsekunden(int, int, int);
int main(){
int stunden, minuten, sekunden;
cout << "Stunden? \n";
cin >> stunden;
cout << "Minuten? \n";
cin >> minuten;
cout << "Sekunden= \n";
cin >> sekunden;
cout << "Alles in Sekunden= " << allesinsekunden(stunden, minuten, sekunden) << endl;
}
int allesinsekunden (int h, int m, int s) {
int sec;
sec=h*3600 + m*60 + s;
return sec;
}
"If I prototype a function above the main function in my code, do I have to include all parameters which have to be given?"
Yes, otherwise the compiler doesn't know how your function is allowed to be called.
Functions can be overloaded in c++, which means functions with the same name may have different number and type of parameters. Such the name alone isn't distinct enough.
"Is there a way how I can just prototype only the function, to save time, space and memory?"
No. Why do you think it would save any memory?
No, because it would add ambiguity. In C++ it's perfectly possible to have two completely different functions which differ only in the number and/or type of input arguments. (Of course, in a well-written program what these functions do should be related.) So you could have
int allesinsekunden(int, int, int)
{
//...
}
and
int allesinsekunden(int, int)
{
//...
}
If you tried to 'prototype' (declare) one of these with
int allesinsekunden;
how would the compiler know which function was being declared? Specifically how would it be able to find the right definition for use in main?
You have to declare the full signature of your function, i.e. the name, the return value, all parameters with types, their constness, etc.

Tutorial c++ reference parameters issue

I have some doubts about C++ reference parameters. I am learning from this website:
http://www.doc.ic.ac.uk/~wjk/c++Intro/RobMillerL3.html
First program:
#include<iostream>
using namespace std;
int area(int length, int width);
int main()
{
int this_length, this_width;
cout << "Enter the length: ";
cin >> this_length;
cout << "Enter the width: ";
cin >> this_width;
cout << "\n";
cout << "The area of a " << this_length << "x" << this_width;
cout << " rectangle is " << area(this_length, this_width) << endl;
return 0;
}
int area(int length, int width)
{
int number;
number = length * width
return number;
}
Then the author suggests that "under some circumstances, it is legitimate to require a function to modify the value of an actual parameter that it is passed".After that he introduces new function:
void get_dimensions(int& length, int& width)
{
cout << "Enter the length: ";
cin >> length;
cout << "Enter the width: ";
cin >> width;
cout << "\n";
}
What is the main advantage when we pass values as parameters?
Advantages of passing by reference:
It allows us to have the function change the value of the argument, which is sometimes useful.
Because a copy of the argument is not made, it is fast, even when used with large structs or classes.
We can pass by const reference to avoid unintentional changes.
We can return multiple values from a function.
Disadvantages of passing by reference:
Because a non-const reference can not be made to a literal or an expression, reference arguments must be normal variables.
It can be hard to tell whether a parameter passed by reference is meant to be input, output, or both.
It’s impossible to tell from the function call that the argument may change. An argument passed by value and passed by reference looks the same. We can only tell whether an argument is passed by value or reference by looking at the function declaration. This can lead to situations where the programmer does not realize a function will change the value of the argument.
Because references are typically implemented by C++ using pointers, and dereferencing a pointer is slower than accessing it directly, accessing values passed by reference is slower than accessing values passed by value.
Sources:
http://www.learncpp.com/cpp-tutorial/73-passing-arguments-by-reference/
http://www.functionx.com/cppcli/functions/Lesson10b.htm
https://en.wikibooks.org/wiki/C++_Programming/Code/Statements/Functions
There is already a good answer (imho worth accepting). However, I would like to give a more basic answer, as it seems like you encountered passing by reference for the first time:
This function:
void foo(int x){x +=1;}
can do anything with the value of the passed (by value) parameter, but it has no chance to return anything to the caller, i.e. the x+=1 has practically no effect at all.
On the other hand, this function:
void bar(int& x){x +=1;}
gets not only the value, but it is working on the actual variable that you pass as parameter (by reference). Thus the x+=1 has an effect also outside of the function.
Both functions in action:
int main(){
int a = 1;
foo(a); // foo gets a copy of a and increments its value
// a is still 1
bar(a); // bar directly increments the value of a
// a is now 2
}
This is the main difference of passing a parameters by reference (bar) vs passing by value (foo). The main advantage of passing by reference is that the value of the parameter needs not to be copied. (This is whypassing by value is usually done with a const reference. Passing a const reference is like passing the value because the value cannot be changed even if actually a reference is passed.) However, for more details I refer to Rohits answer.
int &a is a reference to any parameter passed to that function, You should always think of references as Alias to a variable (it is similar to a const pointer).
If your reference is not const you are allowed to changed and therefore change the content of the original variable.
It is useful for many reason first of all it can improve performances by avoiding doing copies when passing a parameter by reference, and it is also useful if you have a function that your expecting to return multiple results for example =:
int f (int &a,int &b,int &c,int&d);
int main
{
int first,second,third,result;
result = f(first,third,result);
}
All your int variables can be change within you function.