UPI Study › Courses › C++ Programming › Free lessons › Lesson 2.6 Free with a free account
Putting Data Into Variables
C++ Programming · Chapter 2: Getting Started with C++Section 2.6 · lesson 13 of 84video coming soon
← Named Containers for Data: VariablesNext lesson: Your First C++ Output Program →
In this lesson
Initialization, assignment, and the ones that fail silently.
- Tell declaring, initializing and assigning apart
- Use brace initialization to catch narrowing
- Read an assignment's two sides correctly
- Avoid uninitialized variables and hidden conversions
Transcript
Everything said in the video, section by section (1,392 words). Read along, or search it.
Opening Question
Not All Initializing Forms Are Equal
There are several ways to give a variable its first value, and one way to replace it afterward. They're not interchangeable. One quietly discards data that won't fit. One refuses to compile when that would happen. And one leaves the variable holding whatever was already in memory. Knowing which is which is the difference between a program that's wrong, and one that tells you it's wrong.
Definitions
Declaring, Initializing, and Assigning Compared
A variable is a named place in memory, holding one value at a time. Three separate things can happen to it. Declaring makes the place. Int score creates it, but it holds whatever bits were there before. Initializing fills it as it's made. Int points, with seven in braces, supplies the value at the moment of creation. Assigning replaces the contents later. Score equals twelve gives an existing place a new value. Initialization happens once, at birth. Assignment can happen any number of times afterward. And initialization offers a protection that assignment can't.
Syntax Forms
Ways to Initialize and the Brace Habit
C++ gathered several ways to initialize over its history, and all are still legal. You'll meet them in other people's code. Copy initialization, int a equals five, is the shape borrowed from mathematics. Direct initialization uses parentheses. Brace initialization, int c with five in braces, means: make c from exactly five. It refuses to compile if the value can't be represented faithfully. That's why it's the recommended default. Copy list, equals with braces, carries the same protection. And empty braces give zero for numbers, or false. Now a trap. Int f, with empty parentheses, doesn't make a variable holding zero. It declares a function named f. Clang even warns about it. Int f with empty braces is what you meant, which is the clearest argument for the brace habit.
Key Concept
Narrowing Conversions and Build-Time Errors
A narrowing conversion is one where the destination can't faithfully hold every value the source could supply. A number with a fraction into a whole-number variable is narrowing. So is a large number into a small type, or a negative into a type with no negatives. The value doesn't vanish. It's silently altered to fit. Here, a measured value of three point nine goes into an int with equals. It builds without a word, even with warnings on, and x is three. Now write the same line with braces. It won't build. The compiler reports a narrowing conversion. Both lines describe the same intention. Only one tells you the intention was impossible, at build time, when it costs seconds instead of hours.
Examples
Which Narrowing Lines Braces Reject
Here's narrowing in practice. Each of these lines, written with equals, compiles. Written with braces, every one is rejected, except the last. Minus three point nine into an int gives minus three. The fraction is cut off toward zero, not rounded. Minus one into an unsigned gives a very large positive number, almost never what was meant. Five into a bool gives true, since any nonzero value converts to true. And a char given three hundred ends up holding some unrelated value. But seven into a double loses nothing, so braces accept that one too. Braces don't object to conversion. They object to possible loss, which is exactly the line you'd draw yourself.
Assignment Rules
Left Side Place, Right Side Value
Once a variable exists, equals replaces what it holds. The two sides play different roles. The right side is worked out first, producing a value. It's read, not written. Then that value is stored into the place named on the left. Count equals other copies four into count, and other keeps its own value. Assignment copies. It doesn't move. Ten equals count is rejected: a literal is a value, not a place. Count plus one equals ten is rejected: an expression's result has no home. And limit equals ten is rejected, because limit is a place you declared unmodifiable. The traditional names: the left must be an lvalue, with an address to write to. The right need only be an rvalue, something that yields a value. One more caution. A single equals sign stores. Testing whether two values are equal is a different operator, and mixing them up still compiles, with just a warning, and behaves strangely.
Quick Check
Chained Assignment Runs Right to Left
Because an assignment produces a value, the value just stored, assignments can be chained. They group right to left. So a equals b equals c equals seven works from the right. Seven is stored in c, and that yields seven. Then seven is stored in b, yielding seven again. Then it's stored in a. The value travels leftward, one store at a time. Quick check. With an int i and a double d, what do i and d hold after i equals d equals three point seven? D keeps three point seven, and i receives three. Each store converts separately. So two variables a casual reader would assume are equal, aren't. When the types differ, write separate statements.
Common Mistake
Reading a Variable Before Writing It
Declaring a variable without a value doesn't give you a variable holding zero. It gives you whatever bits were already at that address. Reading it before writing to it is undefined behavior: the language requires no particular result at all. With warnings on, Clang points straight at the line. But the compiler isn't required to tell you. You might expect it to be zero. Sometimes it is, by accident, and that's the dangerous part. It may be right on your machine, and wrong on another. The cure is one or two characters. Empty braces hold zero, deliberately, at no extra cost. Better still, initialize with the real value straight away.
Conversions
Silent Type Conversion in Assignment
Assignment doesn't require both sides to be the same type. When they differ, the value is converted to the destination's type. And unlike brace initialization, plain assignment performs narrowing without an error. The protection covers initialization only. Assign nine point nine nine to an int, and it becomes nine. Assign nine to a double, and it becomes nine point oh. And assigning that double back to the int gives nine again, legally and silently. Clang warns about the literal, but not about the variable. Fractional into whole drops the fraction toward zero, so minus nine point nine nine gives minus nine, not minus ten. Whole into fractional is exact, though very large whole numbers can lose precision. And a number into a bool is false only for zero. Zero point four is true, and so is minus one. Sometimes dropping the fraction is exactly what you want. The problem is that a reader can't tell whether you meant it. So where a narrowing is intended, make it visible: a comment now, and an explicit conversion once you've learned how.
Type Deduction
Letting auto Choose the Type
When a variable is initialized, the compiler already knows the type of the initial value. The keyword auto asks it to use that type. This isn't a flexible type. The variable gets one fixed type, chosen at build time, exactly as if you'd typed it. Ten gives an int. Two point five gives a double, and two point five with an f suffix gives a float. A quoted character gives a char, and true gives a bool. And auto with nothing to initialize from is an error, because there's nothing to deduce from. Use auto when the type is long and obvious from the right side. Avoid it when a reader can't tell the type, or when you want a different type than the literal's.
Good Habits
Fixed Types and Habits to Adopt
One more thing about auto. The deduced type is fixed for good. Auto n equals zero makes an int. Assigning it a reading of three point nine later doesn't turn it into a fractional variable. It stores three. So here are the habits worth adopting now. Initialize everything when you declare it. If you have no value yet, write empty braces. Prefer braces: they reject exactly the conversions you wouldn't have wanted. Declare late, right before the first real value. And keep compiler warnings on.
Key Takeaways
Summary and a Brace Puzzle
To summarize. Declaring makes the place, initializing fills it at creation, and assigning replaces its contents later. Brace initialization rejects narrowing. Equals and parentheses accept it silently, and so does plain assignment. An assignment works out the right side first, then stores a copy into the place on the left, which must be a writable lvalue. And never read a variable before giving it a value. Two characters cure it. Something to think about: int n, with two point oh in braces, fails to compile. Why, when two point oh has no fraction to lose?
About C++ Programming at UPI Study
C++ Programming (Computer Science 242) is a self-paced online course of 84 video lessons in 11 chapters, from your first program to decisions, loops, arrays, functions, classes, files, pointers and inheritance. It carries a NCCRS credit recommendation for 3 semester credits.
Every lesson transcript is free on pages like this one, and the videos are free with a free UPI Study account. Enrolling adds a practice quiz after each lesson, the graded work and final exam that earn the credit, lifetime access, and an official transcript on completion. UPI Study has helped over 130,000 students with college credits. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.
Enroll now → Course details Download the syllabus Every course with PRO →
Why take it here
Why students take C++ Programming with UPI Study
Where the credit goes
Universities that work with NCCRS
C++ Programming carries a NCCRS credit recommendation. These universities work with NCCRS; some are UPI Study's signed partners. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.
Thomas Edison State UniversitySigned partner
University of the PeopleSigned partner
Charter Oak State CollegeSigned partner
Strayer UniversitySigned partner
Columbia Southern UniversitySigned partner
Indiana TechSigned partner
Penn StateWorks with NCCRS
Southern New Hampshire UniversityWorks with NCCRS
SUNYWorks with NCCRS
+many more cooperating universitiesFind my college →Find my college → Not listed? Ask Athena in the corner of this page, or book a 15-minute call.
FAQ
Questions students ask us
About Putting Data Into Variables
What is the difference between declaring, initializing, and assigning a variable in C++?
What is a narrowing conversion in C++, and how does brace initialization catch it?
What happens if you use an uninitialized variable in C++?
Why does 10 = count fail in C++ when count = 10 works?
About the C++ Programming course
How many college credits is C++ Programming?
How much does C++ Programming cost and what is included?
Which universities accept UPI Study credits?
How long does C++ Programming take?
How are the exams done?
How do my credits reach my college?
Ready for the full course? Earn 3 credits in C++ Programming.
84 video lessons, a quiz after each one, and the graded work that earns the credit. Recommended for credit by NCCRS.
3 credits · NCCRSEnroll →