Loading...

Go Back

Next page
Go Back Course Outline

C++ Full Course


Basics of C++ Syntax

Basics of C++ Syntax

Data Types

Data types specify the kind of values that a variable can hold and the operations that can be performed on it. C++ offers a variety of built-in (primitive) data types.

1. Primitive Types:

int (Integer)

Used to store whole numbers (both positive and negative) without any decimal point. The size of an int can vary depending on the system architecture but is typically 4 bytes.

        
#include <iostream>

int main() {
  int age = 30;
  int count = -10;
  std::cout << "Age: " << age << std::endl;
  std::cout << "Count: " << count << std::endl;
  return 0;
}
        
        
    
Age: 30 Count: -10
float (Floating-Point)

Used to store single-precision floating-point numbers (numbers with a decimal point). Typically occupies 4 bytes.

        
#include <iostream>
#include <iomanip> // For std::fixed and std::setprecision

int main() {
  float price = 19.99f; // 'f' suffix indicates a float literal
  float temperature = -5.5f;
  std::cout << "Price: " << std::fixed << std::setprecision(2) << price << std::endl;
  std::cout << "Temperature: " << temperature << std::endl;
  return 0;
}
        
        
    
Price: 19.99 Temperature: -5.5
double (Double-Precision Floating-Point)

Used to store double-precision floating-point numbers, offering more precision than float. Typically occupies 8 bytes. It's often the default choice for floating-point numbers unless memory is a significant constraint.

        
#include <iostream>
#include <iomanip>

int main() {
  double pi = 3.14159265358979323846;
  double gravity = 9.81;
  std::cout << "Pi: " << std::fixed << std::setprecision(15) << pi << std::endl;
  std::cout << "Gravity: " << gravity << std::endl;
  return 0;
}
        
        
    
Pi: 3.141592653589793 Gravity: 9.810000000000000
char (Character)

Used to store single characters (letters, digits, symbols). Typically occupies 1 byte. Character literals are enclosed in single quotes.

        
#include <iostream>

int main() {
  char initial = 'A';
  char digit = '7';
  char symbol = '$';
  std::cout << "Initial: " << initial << std::endl;
  std::cout << "Digit: " << digit << std::endl;
  std::cout << "Symbol: " << symbol << std::endl;
  return 0;
}
        
        
    
Initial: A Digit: 7 Symbol: $
bool (Boolean)

Used to store truth values, which can be either true or false.

        
#include <iostream>

int main() {
  bool is_valid = true;
  bool is_finished = false;
  std::cout << "Is valid: " << std::boolalpha << is_valid << std::endl; // std::boolalpha prints true/false instead of 1/0
  std::cout << "Is finished: " << std::boolalpha << is_finished << std::endl;
  return 0;
}
        
        
    
Is valid: true Is finished: false


2. auto Keyword (C++11 and later):

The auto keyword allows the compiler to deduce the data type of a variable based on its initializer. This can make code more concise, especially when dealing with complex types.

        
#include <iostream>
#include <vector>

int main() {
  auto number = 10;        // number will be of type int
  auto pi = 3.14159;      // pi will be of type double
  auto message = "Hello"; // message will be of type const char*
  std::vector<int> numbers = {1, 2, 3, 4, 5};
  for (auto it = numbers.begin(); it != numbers.end(); ++it) { // Type of 'it' is deduced
    std::cout << *it << " ";
  }
  std::cout << std::endl;
  for (auto val : numbers) { // Range-based for loop, type of 'val' is deduced
    std::cout << val * 2 << " ";
  }
  std::cout << std::endl;
  return 0;
}
        
        
    
1 2 3 4 5 2 4 6 8 10

Important Note about auto: While convenient, overuse of auto can sometimes reduce code readability if the type of the variable is not immediately obvious from its initialization.

Variables & Constants

Variables:

Variables are named storage locations in memory that can hold values of a specific data type. The value stored in a variable can be changed during the program's execution.

        
#include <iostream>

int main() {
  int counter = 0; // Declaration and initialization of an integer variable
  std::cout << "Initial counter: " << counter << std::endl;
  counter = 5;      // Assigning a new value to the variable
  std::cout << "Updated counter: " << counter << std::endl;
  counter = counter + 2; // Modifying the variable's value
  std::cout << "Incremented counter: " << counter << std::endl;
  return 0;
}
        
        
    
Initial counter: 0 Updated counter: 5 Incremented counter: 7

Constants:

Constants are variables whose values cannot be changed after they are initialized. C++ provides several ways to define constants:

const Keyword:

Used to declare variables whose values are read-only after initialization. const variables can be initialized at runtime.

        
#include <iostream>

int main() {
  const double PI = 3.14159;
  // PI = 3.0; // Error: assignment of read-only variable 'PI'
  std::cout << "Value of PI: " << PI << std::endl;
  return 0;
}
        
        
    
Value of PI: 3.14159
constexpr Keyword (C++11 and later):

Used to declare constants whose values must be known at compile time. This allows the compiler to perform optimizations. constexpr can also be used with functions that can be evaluated at compile time given constant arguments.

        
#include <iostream>

constexpr int MAX_SIZE = 100;
constexpr double EULER = 2.71828;

constexpr int square(int n) {
  return n * n;
}

int main() {
  std::cout << "Max size: " << MAX_SIZE << std::endl;
  std::cout << "Euler's number: " << EULER << std::endl;
  constexpr int squared_five = square(5); // Value is computed at compile time
  std::cout << "Square of 5 (constexpr): " << squared_five << std::endl;
  return 0;
}
        
        
    
Max size: 100 Euler's number: 2.71828 Square of 5 (constexpr): 25
volatile Keyword:

The volatile keyword is a type qualifier used to indicate that a variable's value might be changed by factors outside the normal execution flow of the program (e.g., by hardware, an interrupt handler, or another thread). This prevents the compiler from making optimizations that assume the variable's value remains unchanged unless modified by the program itself.

        
#include <iostream>
#include <thread>
#include <chrono>

volatile bool data_ready = false;

void worker_thread() {
  std::this_thread::sleep_for(std::chrono::seconds(2));
  data_ready = true; // Value changed by another thread
  std::cout << "Worker thread: Data is now ready." << std::endl;
}

int main() {
  std::thread t(worker_thread);
  while (!data_ready) {
    std::cout << "Main thread: Waiting for data..." << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
  }
  std::cout << "Main thread: Data processing started." << std::endl;
  t.join();
  return 0;
}
        
        
    
Main thread: Waiting for data... Main thread: Waiting for data... Main thread: Waiting for data... Main thread: Waiting for data... Worker thread: Data is now ready. Main thread: Data processing started.

Explanation: Without volatile, the compiler might optimize the while (!data_ready) loop in main() by assuming data_ready never changes within the loop's context, leading to an infinite loop. volatile forces the compiler to re-read the value of data_ready from memory each time the condition is checked.

Operators

Operators are symbols that perform operations on operands (variables or values).

1. Arithmetic Operators:

  • + (Addition)
  • - (Subtraction)
  • * (Multiplication)
  • / (Division)
  • % (Modulo - remainder of integer division)
  • ++ (Increment - prefix or postfix)
  • -- (Decrement - prefix or postfix)
        
#include <iostream>

int main() {
  int a = 10, b = 3;
  std::cout << "a + b = " << a + b << std::endl;
  std::cout << "a - b = " << a - b << std::endl;
  std::cout << "a * b = " << a * b << std::endl;
  std::cout << "a / b = " << a / b << std::endl; // Integer division
  std::cout << "a % b = " << a % b << std::endl;
  std::cout << "a++ = " << a++ << " (a is now " << a << ")" << std::endl;
  std::cout << "++b = " << ++b << " (b is now " << b << ")" << std::endl;
  return 0;
}
        
        
    
a + b = 13 a - b = 7 a * b = 30 a / b = 3 a % b = 1 a++ = 10 (a is now 11) ++b = 4 (b is now 4)

2. Logical Operators:

  • && (Logical AND) - Returns true if both operands are true.
  • || (Logical OR) - Returns true if at least one operand is true.
  • ! (Logical NOT) - Returns the opposite of the operand's boolean value.
        
#include <iostream>

int main() {
  bool p = true, q = false;
  std::cout << "p && q = " << std::boolalpha << (p && q) << std::endl;
  std::cout << "p || q = " << std::boolalpha << (p || q) << std::endl;
  std::cout << "!p = " << std::boolalpha << (!p) << std::endl;
  std::cout << "!q = " << std::boolalpha << (!q) << std::endl;
  return 0;
}
        
        
    
p && q = false p || q = true !p = false !q = true

3. Bitwise Operators:

These operators perform operations at the bit level.

  • & (Bitwise AND)
  • | (Bitwise OR)
  • ^ (Bitwise XOR - Exclusive OR)
  • ~ (Bitwise NOT - One's complement)
  • << (Left Shift)
  • >> (Right Shift)
        
#include <iostream>
#include <bitset> // For std::bitset

int main() {
  unsigned int a = 5;  // Binary: 0101
  unsigned int b = 3;  // Binary: 0011
  std::cout << "a & b = " << (a & b) << " (Binary: " << std::bitset<4>(a & b) << ")" << std::endl;
  std::cout << "a | b = " << (a | b) << " (Binary: " << std::bitset<4>(a | b) << ")" << std::endl;
  std::cout << "a ^ b = " << (a ^ b) << " (Binary: " << std::bitset<4>(a ^ b) << ")" << std::endl;
  std::cout << "~a = " << (~a) << " (Binary: " << std::bitset<8>(~a) << ")" << std::endl; // Assuming 8-bit int for demonstration
  std::cout << "a << 1 = " << (a << 1) << " (Binary: " << std::bitset<4>(a << 1) << ")" << std::endl;
  std::cout << "a >> 1 = " << (a >> 1) << " (Binary: " << std::bitset<4>(a >> 1) << ")" << std::endl;
  return 0;
}
        
        
    
a & b = 1 (Binary: 0001) a | b = 7 (Binary: 0111) a ^ b = 6 (Binary: 0110) ~a = 4294967290 (Binary: 11111111111111111111111111111010) a << 1 = 10 (Binary: 1010) a >> 1 = 2 (Binary: 0010)

Note: The output of ~a depends on the size of the unsigned int type on your system. The std::bitset is used here to visualize the binary representation.

4. Ternary Operator:

The ternary operator (?:) is a concise way to express a simple if-else condition.

        
#include <iostream>
#include <string>

int main() {
  int age = 18;
  std::string status = (age >= 18) ? "Adult" : "Minor";
  std::cout << "Age: " << age << ", Status: " << status << std::endl;

  int x = 10, y = 5;
  int max = (x > y) ? x : y;
  std::cout << "The maximum of " << x << " and " << y << " is: " << max << std::endl;
  return 0;
}
        
        
    
Age: 18, Status: Adult The maximum of 10 and 5 is: 10

5. sizeof Operator:

The sizeof operator returns the size (in bytes) of a data type or an expression.

        
#include <iostream>

int main() {
  std::cout << "Size of int: " << sizeof(int) << " bytes" << std::endl;
  std::cout << "Size of float: " << sizeof(float) << " bytes" << std::endl;
  int numbers[5];
  std::cout << "Size of numbers array (5 ints): " << sizeof(numbers) << " bytes" << std::endl;
  int x = 10;
  std::cout << "Size of variable x (int): " << sizeof(x) << " bytes" << std::endl;
  return 0;
}
        
        
    
Size of int: 4 bytes Size of float: 4 bytes Size of numbers array (5 ints): 20 bytes Size of variable x (int): 4 bytes

Note: The exact sizes of primitive data types can sometimes vary slightly depending on the compiler and the target architecture.

Control Structures

Control structures dictate the flow of execution in a program, allowing you to make decisions and repeat blocks of code.



1. if-else Statement:

The if statement executes a block of code if a specified condition is true. The optional else block executes if the condition is false. You can also have multiple conditions using else if.

        
#include <iostream>

int main() {
  int age = 20;
  if (age >= 18) {
    std::cout << "You are an adult." << std::endl;
  } else {
    std::cout << "You are a minor." << std::endl;
  }

  int grade = 75;
  if (grade >= 90) {
    std::cout << "Excellent!" << std::endl;
  } else if (grade >= 80) {
    std::cout << "Very good." << std::endl;
  } else if (grade >= 70) {
    std::cout << "Good." << std::endl;
  } else {
    std::cout << "Needs improvement." << std::endl;
  }
  return 0;
}
        
        
    
You are an adult. Good.

2. switch Statement:

The switch statement allows you to execute different blocks of code based on the value of a single variable (the switch expression).

        
#include <iostream>

int main() {
  int day = 3;
  switch (day) {
    case 1:
      std::cout << "Monday" << std::endl;
      break;
    case 2:
      std::cout << "Tuesday" << std::endl;
      break;
    case 3:
      std::cout << "Wednesday" << std::endl;
      break;
    case 4:
      std::cout << "Thursday" << std::endl;
      break;
    case 5:
      std::cout << "Friday" << std::endl;
      break;
    case 6:
    case 7:
      std::cout << "Weekend" << std::endl;
      break;
    default:
      std::cout << "Invalid day" << std::endl;
  }
  return 0;
}
        
        
    
Wednesday

Important Notes about switch:

  • The break statement is crucial to exit the switch block after a case is matched. Without break, execution will "fall through" to the next case.
  • The default case is optional and is executed if none of the other cases match the switch expression.
  • The switch expression must evaluate to an integer or enumeration type.

3. for Loop:

The for loop is used to execute a block of code a specific number of times. It typically has three parts: initialization, condition, and increment/decrement.

        
#include <iostream>

int main() {
  for (int i = 0; i < 5; ++i) {
    std::cout << "Iteration: " << i << std::endl;
  }
  return 0;
}
        
        
    
Iteration: 0 Iteration: 1 Iteration: 2 Iteration: 3 Iteration: 4

4. Range-based for Loop (C++11 and later):

This provides a more concise way to iterate over elements in a range (e.g., arrays, vectors, strings).

        
#include <iostream>
#include <vector>

int main() {
  std::vector<int> numbers = {10, 20, 30, 40, 50};
  for (int num : numbers) { // Iterates through each element in 'numbers'
    std::cout << "Number: " << num << std::endl;
  }

  std::string message = "Hello";
  for (char ch : message) { // Iterates through each character in 'message'
    std::cout << "Character: " << ch << std::endl;
  }
  return 0;
}
        
        
    
Number: 10 Number: 20 Number: 30 Number: 40 Number: 50 Character: H Character: e Character: l Character: l Character: o

5. while Loop:

The while loop executes a block of code as long as a specified condition is true. The condition is checked before each iteration.

        
#include <iostream>

int main() {
  int count = 0;
  while (count < 3) {
    std::cout << "Count is: " << count << std::endl;
    count++;
  }
  return 0;
}
        
        
    
Count is: 0 Count is: 1 Count is: 2

6. do-while Loop:

The do-while loop is similar to the while loop, but the condition is checked after each iteration. This guarantees that the loop body will execute at least once.

        
#include <iostream>

int main() {
  int num = 0;
  do {
    std::cout << "Num is: " << num << std::endl;
    num++;
  } while (num < 2);
  return 0;
}
        
        
    
Num is: 0 Num is: 1

Understanding these fundamental C++ syntax elements is crucial for building more complex programs. Mastering data types, variables, constants, operators, and control structures will allow you to write logic that can make decisions, perform calculations, and repeat actions as needed. Remember to practice writing small programs using these concepts to solidify your understanding.

Go Back

Next page