Search

2.1 — Fundamental variable definition, initialization, and assignment

Addressing memory

This lesson builds directly on the material in the section “1.3 -- A first look at variables“.

In the previous lesson on variables, we talked about the fact that variables are names for a piece of memory that can be used to store information. To recap briefly, computers have random access memory (RAM) that is available for programs to use. When a variable is defined, a piece of that memory is set aside for that variable.

The smallest unit of memory is a binary digit (bit), which can hold a value of 0 or 1. You can think of a bit as being like a traditional light switch -- either the light is off (0), or it is on (1). There is no in-between. If you were to look at a random segment of memory, all you would see is …011010100101010… or some combination thereof. Memory is organized into sequential units called memory addresses (or addresses for short). Similar to how a street address can be used to find a given house on a street, the memory address allows us to find and access the contents of memory at a particular location. Perhaps surprisingly, in modern computers, each bit does not get its own address. The smallest addressable unit of memory is known as a byte. The modern standard is that a byte is comprised of 8 sequential bits. Note that some older or non-standard machines may have bytes of a different size -- however, we generally need not worry about these. For these tutorials, we’ll assume a byte is 8 bits.

The following picture shows some sequential memory addresses, along with the corresponding byte of data:

Memory Addressing

Because all data on a computer is just a sequence of bits, we use a data type (often called a “type” for short) to tell us how to interpret the contents of memory in some meaningful way. You have already seen one example of a data type: the integer. When we declare a variable as an integer, we are telling the compiler “the piece of memory that this variable addresses is going to be interpreted as a whole number”.

When you assign a value to a data type, the compiler and CPU take care of the details of encoding your value into the appropriate sequence of bits for that data type. When you ask for your value back, your number is “reconstituted” from the sequence of bits in memory.

There are many other data types in C++ besides the integer, most of which we will cover shortly. As shorthand, we typically refer to a variable’s “data type” as its “type”.

Fundamental data types

C++ comes with built-in support for certain data types. These are called fundamental data types (in the C++ specification), but are often informally called basic types, primitive types, or built-in types.

Here is a list of the fundamental data types, some of which you have already seen:

Category Types Meaning Example Notes
boolean bool true or false true
character char, wchar_t, char16_t, char32_t a single ASCII character ‘c’ char16_t, char32_t are C++11 only
floating point float, double, long double a number with a decimal 3.14159
integer short, int, long, long long a whole number 64 long long is C99/C++11 only
void no type void n/a

This chapter is dedicated to exploring these basic data types in detail.

Defining a variable

In the “basic C++” section, you already learned how to define an integer variable:

To define variables of other data types, the idea is exactly the same:

In the following example, we define 5 different variables of 5 different types.

Note that void has special rules about how it can be used, so the following won’t work:

Variable initialization

When a variable is defined, you can immediately give that variable a value. This is called variable initialization (or initialization for short).

C++ supports three basic ways to initialize a variable. First, we can do copy initialization by using an equals sign:

Note that the equals sign here is just part of the syntax, and is not the same equals sign used to assign a value once the variable has been created.

Second, we can do a direct initialization by using parenthesis.

Even though direct initialization form looks a lot like a function call, the compiler keeps track of which names are variables and which are functions so that they can be resolved properly.

Direct initialization can perform better than copy initialization for some data types, and comes with some other benefits once we start talking about classes. It also helps differentiate initialization from assignment. Consequently, we recommend using direct initialization over copy initialization.

Rule: Favor direct initialization over copy initialization

Uniform initialization in C++11

Because C++ grew organically, the copy initialization and direct initialization forms only work for some types of variables (for example, you can’t use either of these forms to initialize a list of values).

In an attempt to provide a single initialization mechanism that will work with all data types, C++11 adds a new form of initialization called uniform initialization (also called brace initialization):

Initializing a variable with an empty brace indicates default initialization. Default initialization initializes the variable to zero (or empty, if that’s more appropriate for a given type).

Uniform initialization has the added benefit of disallowing “narrowing” type conversions. This means that if you try to use uniform initialization to initialize a variable with a value it can not safely hold, the compiler will throw an warning or error. For example:

Rule: If you’re using a C++11 compatible compiler, favor uniform initialization

Variable assignment

When a variable is given a value after it has been defined, it is called a copy assignment (or assignment for short).

C++ does not provide any built-in way to do a direct or uniform assignment.

Uninitialized variables

A variable that is not initialized is called an uninitialized variable. In C++, a fundamental variable that is uninitialized will have a garbage value until you assign a valid one. We discuss this in previous lesson A first look at variables, initialization, and assignment.

Side note: C++ also has other non-fundamental types, such as pointers, structs, and classes. Some of these do not initialize by default, and some of them do. We’ll explore these types in future lessons. For now, it’s safer to assume all types do not initialize by default.

Rule: Always initialize your fundamental variables, or assign a value to them as soon as possible after defining them.

Defining multiple variables

It is possible to define multiple variables of the same type in a single statement by separating the names with a comma. The following 2 snippets of code are effectively the same:

You can also initialize multiple variables defined on the same line:

There are three mistakes that new programmers tend to make when defining multiple variables in the same statement.

The first mistake is giving each variable a type when defining variables in sequence. This is not a bad mistake because the compiler will complain and ask you to fix it.

The second error is to try to define variables of different types on the same line, which is not allowed. Variables of different types must be defined in separate statements. This is also not a bad mistake because the compiler will complain and ask you to fix it.

The last mistake is the dangerous case. In this case, the programmer mistakenly tries to initialize both variables by using one initialization statement:

In the top statement, variable “a” will be left uninitialized, and the compiler may or may not complain. If it doesn’t, this is a great way to have your program intermittently crash and produce sporadic results.

The best way to remember that this is wrong is to consider the case of direct initialization or uniform initialization:

This makes it seem a little more clear that the value 5 is only being assigned to variable b.

Because defining multiple variables on a single line AND initializing them is a recipe for mistakes, we recommend that you only define multiple variables on a line if you’re not initializing any of them.

Rule: Avoid defining multiple variables on a single line if initializing any of them.

Where to define variables

Older C compilers forced users to define all of the variables in a function at the top of the function:

This style is now obsolete. C++ compilers do not require all variables to be defined at the top of a function. The proper C++ style is to define variables as close to the first use of that variable as you reasonably can:

This has quite a few advantages.

First, variables that are defined only when needed are given context by the statements around them. If x were defined at the top of the function, we would have no idea what it was used for until we scanned the function and found where it was used. Defining x amongst a bunch of input/output statements helps make it obvious that this variable is being used for input and/or output.

Second, defining a variable only where it is needed tells us that this variable does not affect anything above it, making our program easier to understand and requiring less scrolling.

Finally, it reduces the likelihood of inadvertently leaving a variable uninitialized, because we can define and then immediately initialize it with the value we want it to have.

Most of the time, you’ll be able to declare a variable on the line immediately preceding the first use of that variable. However, you will occasionally encounter a case where this is either not desirable (due to performance reasons), or not possible (because the variable will get destroyed and you need it later). We’ll see examples of these cases in future chapters.

Rule: Define variables as close to their first use as you reasonably can.

2.2 -- Void
Index
1.12 -- Chapter 1 comprehensive quiz

149 comments to 2.1 — Fundamental variable definition, initialization, and assignment

  • James Smith

  • Muru

    My dear teacher,

    Thank you so much for these tutorials. I had been banging my head against wall to learn C++. You made it accessible for me with your tips and clear examples.

    Thank you.

    Regards,
    muru

  • Zero Cool

    Hey Alex. How are you doing?
    I think you should update the table of fundamental types to say that some types like char16_t or char32_t are C++14 standard too.

    Once again thanks for the great website you have made.

    • Alex

      char16_t and char32_t are part of the C++11 standard, not the C++14 standard. Compilers that are C++11 compliant or newer (including compilers that are C++14 compliant) should be able to use these.

  • Xenel

    I was wondering what the best choice is for initialization of variables. There was another comment saying that list (uniform) initialization was the safest because of conversion but I was wondering what the actual best practice in the real world was as opposed to it simply being safer.

    I’ve read through a bit more of the chapters and I mostly only see direct initializations used but my understanding was that uniform initializations are the best choice if using at least C++11 and variable conversion isn’t planned.

    • Alex

      Uniform initialization is best in the real world. It’s the safest and most consistent option, and it doesn’t add additional burden.

      Many of these tutorials do copy or direct initialization because they were written pre-C++11 and then adapted. Ideally they should be updated but I’ve been focused on other things like answering comments. 🙂

      • Xenel

        Thanks for the reply. It’s greatly appreciated. I don’t mind that it isn’t up to date in this constantly changing world. As long as my question is answered, the majority of these tutorials still give me that basic gist of things. Eventually I could have probably figured that out but I’d like to apply the best practice as soon as possible if I can.

        Thanks again.

  • gary wang

    Hi, thanks for the great tutorial. May I ask what do you mean by "Note that the equals sign here is just part of the syntax, and is not the same equals sign used to assign a value once the variable has been created." Can you give an example? thanks so much

    • Alex

      Although these two lines look similar (both use an equals sign) and perform similar functions, C++ treats them differently. The equals signs are not related. In the top line, the equals sign is part of the copy initialization syntax. In the bottom line, the equals sign is the assignment operator, which is evaluated the same way other operators are.

      It doesn’t make a huge amount of difference at this point, but later on we’ll see that we can override the assignment operator -- this doesn’t have any impact on copy initialization, since it doesn’t use the assignment operator.

      • gary wang

        Oh, I see. I always thought they are the same thing.
        So basically, the both equal sign(=) are the same sign but they mean the different thing, just like * operator, one is for the pointer and other is for multiplication.
        Thanks so much for the explanation!

        • Alex

          Exactly! C++ is full of things like this, where symbols are reused but have different meanings in different contexts. & is another one: in some contexts it’s the address-of operator. In other contexts it means reference.

  • Rob

    I have a few questions about memory and addresses

    Can I trust the computer to "leave" my variable at the same address or will the OS move it around if it needs to (assuming the variable not getting destroyed in the meantime). Eg. could I get the address of the variable and just refer to it by address, not name? I understand that this might be dangerous, and probably not useful in most situations, so it’s mostly just curiosity.

    Secondly, can I ask for specific memory addresses for my variable (or maybe just for consecutive ones). Could there be a performance benefit or is reading four addresses at random just as fast as reading four consecutive ones?

    • Alex

      1) Once a variable has been given a memory address, the OS won’t randomly change it -- but only so long as that variable is still in scope. Once that variable is destroyed, the program may reuse that memory address for something else.

      Variables may have different address with each execution of the program, and function parameters may be given different addresses each time the function is called.

      So yes, you can refer to a variable by address if you want. And yes, this is dangerous because the variable may go out of scope and get destroyed, you may end up referencing a memory location that’s been reused for something else.

      2) No, you can’t ask for a specific memory address. There may be some a performance benefit from having data that’s accessed together be close in memory together (due to caching), but in most cases we tend to get that for free anyway via using arrays and classes, both of which allow us to aggregate related data into sequential memory.

  • Theo

    Dear Teacher ,
    can you please better explain whats the diference between (assigning an value to an integer)
    and (initializing it)

    • Alex

      Initialization occurs when you provide an initial value to a variable at the point where it is defined. Assignment happens when you provide a new value to a variable after it is defined.

      In most cases, the end result is the same. However, later on, we’ll start seeing some cases where variables must be initialized, or can not be assigned to. So it’s worth understanding the distinction now, even though in both cases (when it is allowed) the variable acquires the value.

      • Theo

        Dear Teacher ,
        So is there a point in assigning a value to a void function, knowing that it wont return that value to main func.?

        • Alex

          I’m not sure what you mean by “assigning a value to a void function”. Are you talking about return values? It’s a syntax error for a function that returns void to try to return a value back to the caller.

  • Stan

    Just wanted to comment and say this whole tutorial has been very interesting and helpful, thank you!

  • B1

    hi there Alex sorry for bothering you
    but i wrote a small code on Online Compiler (codechef.com)
    and it gave me an error
    i tried the code with (NetBeans) it also gave me the same error

    when i do this

    it gives me this error "prog.cpp:9:1: error: ‘g1’ does not name a type"

    but when i do this

    it compiles fine…is assigning forbidden in the global scope or what ?

    • Alex

      Yes. You can define things in the global scope, but you can not execute code in the global scope. So the definition of g1 is okay, but the assignment is not.

      If you want to do this, you should define g1 with an initializer (int g1 = 44;).

      • B1

        oh..right
        execution of the code will begin & end in main()
        my thick head missed this info

        thank you Alex

      • Jim Smith

        But this is new information. In the global scope C++ allows some statements like definitions (int x;) and forbids other statements like assignments (x = 2;). Shouldn’t this be included in the tutorial?

        • Alex

          Probably, but we haven’t even covered the global scope at this point in the tutorial, so it might be a bit premature to do so before or at this point..

  • dgo

    [code]
    #include <iostream>

    int main()
    {
        int x{3};
        std::cout << "x is initialized as " << x << std::endl;
    }

    Seems like uniform initialization doesn’t work..
    It does not compile and complains that
    [code]
    variable1.cpp:5:10: error: expected ‘;’ at end of declaration
        int x{3};

    A version of the compiler is the following:

    Dongwooks-MacBook-Pro:ch2 dgo$ g++ -version
    Configured with: -prefix=/Library/Developer/CommandLineTools/usr -with-gxx-include-dir=/usr/include/c++/4.2.1
    Apple LLVM version 8.0.0 (clang-800.0.42.1)
    Target: x86_64-apple-darwin16.3.0
    Thread model: posix
    InstalledDir: /Library/Developer/CommandLineTools/usr/bin

  • Georges Theodosiou

    My dear c++ Teacher,
    Please let me say, it is not that every compiler will throw an warning or error if I try to use uniform initialization to initialize a variable with a value it can not safely hold. For your example

    https://www.codechef.com/ide >> 4.
    http://cpp.sh/ >> nothing.
    http://rextester.com/l/cpp_online_compiler_gcc >> 4.
    https://www.tutorialspoint.com/cplusplus/index.htm >>
    main.cpp: In function ‘int main()’:
    main.cpp:5:18: warning: narrowing conversion of ‘4.5e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]
         int value{4.5};
                      ^
    So of the 4 compilers online only one throw an warning.
    With regards and friendship.

    • Alex

      cpp.sh gives a warning, you can see the yellow triangle symbol at the line of code, and if you click on the “compilation” tab you’ll see the warning.

      But you’re right, some of the others don’t appear to be compliant with the C++ specification in this regard. Note that narrowing conversions in a uniform initialization should be an error, not a warning!

  • Nguyen

    Hi Alex,

    "To recap briefly, computers have random access memory (RAM) that is available for programs to use. When a variable is defined, a piece of that memory is set aside for that variable."

    When I read about the Memory addresses, I start getting confused.  Here are what I guess "When a variable is defined, a memory address is set aside for that variable"

    I don’t know if a variable has anything to do with the memory address when a variable is defined?

    Thank you

    • Alex

      Let’s recap:
      1) Your computer has memory.
      2) Memory is used to store values.
      3) Each byte of memory has a unique address.
      4) Memory addresses are hard to work with (because they are just numbers).

      So, when you declare a variable, you’re doing a few things:
      A) You’re telling the compiler to reserve some memory for you.
      B) You’re telling the compiler how to convert the contents of that memory into a specific type of value.
      C) You’re telling the compiler what you want to call that memory.

      For example, when you say

      You’re telling the compiler that you want to reserve 4 bytes of memory, that the value should be interpreted as an integer, and that you want to name that memory location “x”.

  • George

    I’m not too sure I understand with regards to the defining/initialization. Is what you’re saying that you can define a variable separately but with initialization you can define and give it a value on one line? And with the assignment is that simply when you want to give it a value at a lower line so you define it and don’t initialize? I’ve read it a couple times but I’m still not sure.

    Also:
    "When a variable is given a value after it has been defined, it is called ""an"" copy assignment (or assignment for short)."

    • Alex

      When a variable is defined, memory is allocated for it. We can define a variable with no initial value:

      But this is generally bad practice, because x will be given a garbage value, and that’s usually not desirable. So when we define a variable, we can initialize it, which simply means that we’re providing it with an initial value:

      A variable can only be initialized at the point of definition.

      Later on, if we want to _change_ the value that a variable has, we can assign a new value to it, via the assignment operator (=). You can do this regardless of whether the variable was initialized or not.

      Make sense? Also, typo fixed. Thanks!

  • Nick

    Correct me if I’m wrong, but under "Defining a variable" the example of all 5 variable types does not include void, but does include both float and double, which are the same thing, and is thus an incorrect example of all 5 variable types?

    • Alex

      The example isn’t intended to be an example of how to declare all 5 types, least of all because you can’t declare a variable of type void. I’ve added a note to the lesson about that.

      • McSteven

        Can you enlighten me, I don’t understand the difference between float and double types.

        • Alex

          Float and double serve the same purpose (much like a short, int, and long do), but have different ranges and precisions. We talk more about all of these in upcoming lessons in this chapter.

  • Hi Alex,
    I have one doubt related to address concept

    Consider my compiler architecture is 32 bit(4 byte) and size of short is 16 bit and char is 8 bit
    If I have a structure with structure packing is enabled(No padding)
    like

    here both the members are stored in the same address, is it right ?

    then if I read the variable s_var2 like obj.s_var2. variable read the particular memory, so in this case both the member variable have same memory. In this case how we get the correct value of s_var2? or it is impossible ?

    • Alex

      No, if there’s no padding then s_var1 will be stored in the first 8 bytes, and s_var2 will be stored in the next 16 bytes.

      You can prove this yourself by implementing the above, and printing the address of obj.s_var1 and obj.s_var2.

      • Hi Alex,
        Thanks for the replay

        How can I check with structure packing in a compiler, is any configuration in compiler. May be am wrong, My idea about address is, a 32 bit architecture can hold 32 bit data in a single address.
        ie, consider 0x0FFE1 is my address and it have 32 bit, and both the members are stored in the single address 0x00FFE1 is it correct?

        • Alex

          Compilers should have an option to set data structure alignment.

          A 32-bit architecture does not hold 32-bits of data in a single address. Most architectures are byte-addressable, which means that one address holds 1 byte of data. A 32-bit architecture means that the CPU can process 32-bits of data at once (4 addresses worth), as well as address 32-bits of memory addresses (4GB).

          In the future, please try and leave comments on the lessons more appropriate to the topic you’re asking about. This topic is really better discussed in the lesson 4.7 -- Structs.

  • Dragos

    Now when u left a variable uninitialized, isn’t it automatically initialized with 0?

  • Raquib

    I am confused by a portion (copied below) explained in this tutorial---

    ---------------------------------------------------------------------
    The last mistake is the dangerous case. In this case, the programmer mistakenly tries to initialize both variables by using one assignment statement:

    int a, b = 5; // wrong (a is uninitialized!)

    int a= 5, b= 5; // correct
    -----------------------------------------------------------------------

    My question is why is this called to be an assignment statement ?? I thought, the ‘=’ sign here was just a part of syntax for copy initialization and should not be confused with assignment ‘=’.

    Am I missing something ??

    • Alex

      No, you are correct. I’ve updated the tutorial to use “initialization” instead of “assignment”, as it should be.

      • Raquib

        Thanks for your prompt reply. Awesome tutorial BTW. I have already sent a mail expressing how awesome it is so will avoid it here. Thanks a lot.

  • de.rock

    When i Initializing a variable with empty parenthesis i.e int x()  output is 1 and
    Initializing same variable with nothing i.e int x  output is 4291710. Can any please explain why different output for same variable…tnx..

  • Chris

    The line in question (line 30) has a semicolon.

    • Alex

      You’re saying the compiler is complaining about line 30 needing a semicolon even though you already have one? It sounds like your compiler either isn’t C++11 compatible, or maybe that functionality is not turned on. You may need to add compiler option -std=c++11 to your compiler settings. See this page for more info.

  • Chris

    The following code compiled and ran without a problem before I added the third to last statement, the one that is supposed to list initialize value to 4. The compiler complains that a ; needs to be put at the end of this statement.  

    Why does the compiler not recognize this mode of initialization?

    The version of C++ I am using includes cstdint, so I assume I am using C++11

    I am currently using the Eclipse IDE on my mac if that helps.

  • Rafal

    Can you explain me benefits of using direct initialization of variables ? What’s the difference between direct and copy ? I understand them when we are using classes but what about int, float etc?

  • Nyap

    will you update the website when C++17 comes out?
    edit: and btw, why are explicit and implicit initializations called that? is it because explicit is a bit more obvious because of the assignment operator?

    • Alex

      If I’m still around, I will update for C++17.

      I’ve updated the names of the initialization forms to be more in line with accepted standards. Explicit initialization is more commonly called copy initialization, and implicit initialization is more commonly called direct initialization.

      • Nyap

        will you get a guy to replace you when you leave? bc i’ve been making really bad progress because of school, so I might need to hurry up if you’re just going to leave the site without someone at least replying to the comments

  • Chuck

    In the code snippet

    The line

    Is missing a semicolon. Not sure if it was a typo or not.

  • Heitor

    Hi, in a long and complex program it won’t be an hassle to find where it is the declarations of the variables? I have the habit to declare them at the top of the function like in the old C compilers or declare variables in a seperate file, so I can find easily where the declaration of the variables are. Is this a bad way to do it? Just a question that may increase my performance I guess :/

    By the way I am enjoying to read your lessons, you teach very well. More than my old teacher (where she teached me how to use Visual Basic). I like to learn all about the language, not half. You deserve my congratz 😀

    • Alex

      Modern IDEs should show you the variable declarations on hover, so there’s no need to scroll to find them. Also if you generally declare variables as close to the first use as possible, the declarations are right above the code that uses them.

      Keeping your functions short and modular also helps.

  • Lokesh

    Hi Alex,
    I am using -std=c++11 option to compile the following program with g++ along with some other options(-Wall -pedantic) and instead of giving me an error, it just gives me a warning.

    warning: narrowing conversion of ‘5.5999999999999996e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]
    int nValue3{5.6}; // Universal initialization.

    The program compiles and runs with the following output:
    1
    2
    5

    Am I missing something?

    • Alex

      Apparently the compiler is not required to generate an error for a narrowing conversion -- just some kind of diagnostic message. Older versions of GCC gave an error, but they changed it to a warning in newer versions to increase compatibility with older code bases.

  • Javad

    Hi Alex,

    I believe it is not accurate to say "Uniform initialization disallows type conversion" as indicated in the lesson under Uniform initialization in C++11. Uniform initialization disallows type conversion if it involves narrowing. However, if type conversion can be performed without narrowing it is allowed. For example the following code compiles fine:

    char c{ ‘c’ };
    int i{ c };
    bool b{ true };
    int x{ b };
    char z{ 20 };

  • Aimee

    Hi Alex,

    Great tutorials so far but I’m not still not sure if I understand the difference in usage between brackets ‘ () ‘ and squiggly brackets ‘ {} ‘ during initialization of the variables.

    From what I understand, both bracket types seem to be appropriate for the initialization of variables so long as the variable introduced belongs to that class (ie, int nValue(4) is not different from int nValue{4}, but int nValue{4.5} does not work since 4.5 isn’t an integer), and brackets do not work for lists.

    Is this true? Are there any other differences between the two bracket types?

    Thanks 🙂

    • Alex

      Both types are appropriate for initializing variables. The “squiggly” braces {} should be preferred if you’re using a C++11 compatible compiler because they work for all kinds of initialization, whereas the parenthesis braces () work for initializing most (but not all) types. As you correctly note, the squiggly braces also prevent most implicit type conversions, which is generally a good thing.

      • Nick L

        I’m using Visual Studio Community 2015. Should I only use the {} initialization in the future of these tutorials? Also, after the initialization, should I go about as usual and use the = for assignment? so:

        and just ignore the () and = initialization altogether?

  • Sarhad Salam

    If I use uniform initialization, and my compiler supports it. Can I run my app in older computers?. If I follow C++11 rules, will old computers support it? (Say windows xp, or ubuntu 9, or any such)

    Thanks.

    • Alex

      Yes, once your app is compiled into an executable for a certain architecture, the compiler and which set of C++ features you used in our program doesn’t matter.

  • yash

    I am using visual studio 2012….
    Can I use c++11 feature in it?
    When I use use uniform initialization it gives me error…….
    Please give me it’s solution
    And thanks for making this tutorials.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter