Lesson 02-C Language Basic Syntax

Comments and Preprocessor Directives

Comments

Comments are used to explain the purpose of code and are ignored by the compiler, but they are crucial for programmers to understand the code.

Single-Line Comments

Single-line comments start with // and affect the content from that point to the end of the line.

// This is a single-line comment
int main() {
    int a = 10; // This variable stores an integer
    return 0;
}

Multi-Line Comments

Multi-line comments start with /* and end with */, allowing comments to span multiple lines.

int main() {
    /*
    This is a multi-line comment,
    which can include multiple lines of text.
    */
    int a = 10;
    return 0;
}

Preprocessor Directives

Preprocessor directives are executed by the preprocessor before compilation and begin with the # character.

File Inclusion (#include)

The #include directive inserts the contents of another file into the current source file.

#include <stdio.h> // Includes the standard input/output header file

int main() {
    printf("Hello, World!\n");
    return 0;
}

Macro Definition (#define)

The #define directive defines macros, which can be constants or function-like macros.

#define PI 3.14159 // Defines the PI macro

int main() {
    double radius = 1.0;
    double circumference = 2 * PI * radius;
    return 0;
}

Conditional Compilation

Conditional compilation directives like #ifdef, #ifndef, #if, #else, #elif, and #endif control whether certain code segments are compiled based on predefined symbols.

#ifdef DEBUG
#define LOG(x) printf("%s\n", x)
#else
#define LOG(x)
#endif

int main() {
    LOG("Debug message");
    return 0;
}

Conditional Compilation Example

#include <stdio.h>

#define DEBUG

int main() {
#if defined(DEBUG)
    printf("This is debug code.\n");
#else
    printf("This is release code.\n");
#endif

    return 0;
}

Predefined Macros

The preprocessor provides predefined macros such as __FILE__, __LINE__, __DATE__, and __TIME__, which represent the current source file name, line number, compilation date, and time, respectively.

#include <stdio.h>

int main() {
    printf("This file is %s and line number is %d\n", __FILE__, __LINE__);
    printf("Compiled at %s %s\n", __DATE__, __TIME__);
    return 0;
}

Example Analysis

Here’s a comprehensive example demonstrating the use of comments and preprocessor directives:

#include <stdio.h>

#define MAX(a, b) ((a) > (b) ? (a) : (b)) // Defines a macro to find the maximum

int main() {
    int x = 10, y = 20;

    // Outputs the larger of two numbers
    printf("The maximum of %d and %d is %d\n", x, y, MAX(x, y));

    /* 
    The following code is unused and can be commented out
    */
    // printf("This will not be compiled\n");

    #ifdef DEBUG
    printf("Debugging information...\n");
    #endif

    return 0;
}

In this example, #include imports the standard I/O library, #define creates a maximum-finding macro, single-line and multi-line comments explain the code, and conditional compilation controls debug output.

Data Types

Basic Data Types

Basic data types include integers, floating-point numbers, characters, and enumerations.

Integer Types

Integer types store whole numbers. C provides several integer types to accommodate different sizes:

  • char: Typically 1 byte, often used to store a single character.
  • short: Typically 2 bytes.
  • int: Typically 4 bytes, the most commonly used integer type.
  • long: Typically 4 or more bytes, depending on the compiler.
  • long long: At least 8 bytes, for very large integers.

Integers can be prefixed with signed or unsigned to specify whether they can store negative numbers.

Floating-Point Types

Floating-point types store real numbers with decimal parts.

  • float: Single-precision, typically 4 bytes.
  • double: Double-precision, typically 8 bytes, offering higher precision than float.
  • long double: Extended precision, larger and more precise than double.

Character Type

The char type stores a single character, typically 1 byte. In C, characters are stored as integers corresponding to ASCII or Unicode values.

Enumeration Type

The enumeration type (enum) is a user-defined type consisting of a set of named integer constants.

enum colors {red, green, blue};

Composite Data Types

Composite data types are combinations of basic types, including arrays, structures, unions, and enumerations.

Arrays

An array is a data structure that stores a collection of elements of the same type, accessed via indices starting at 0.

int numbers[5]; // Defines an array of 5 integers

Structures

A structure (struct) is a composite type that can contain members of different data types.

struct student {
    char name[50];
    int age;
    float grade;
};

Unions

A union (union) is similar to a structure, but all members share the same memory space.

union data {
    int i;
    float f;
    char c;
};

Pointer Types

Pointer types store the memory addresses of other variables. The pointer’s type must match the type of the variable it points to.

int x = 10;
int *p = &x; // p is a pointer to an integer

Void Type

The void type (void) indicates the absence of a type, often used for function parameters or return types.

void myFunction(void); // Function with no parameters or return value

Type Conversion

C allows explicit type conversion using parentheses to specify the new type:

float f = 3.14;
int i = (int)f; // Converts a float to an integer

Variables and Constants

Variables

Variables are identifiers used to store data in a program. Each variable has a specific data type that determines the range and kind of values it can hold.

Declaring Variables: Variables must be declared with a type and name before use.

int age; // Declares an integer variable

Initializing Variables: Variables can be assigned an initial value during declaration.

int age = 25; // Declares and initializes an integer variable

Using Variables: Variables can be used in expressions or updated via assignment statements.

age = 26; // Updates the variable's value

Constants

Constants are immutable values. In C, the const keyword is used to declare constants.

const int MAX_SIZE = 100; // Declares an integer constant

Operators

Arithmetic Operators

  • Addition: +
  • Subtraction: -
  • Multiplication: *
  • Division: /
  • Modulus: %

Comparison Operators

  • Equal to: ==
  • Not equal to: !=
  • Less than: <
  • Greater than: >
  • Less than or equal to: <=
  • Greater than or equal to: >=

Logical Operators

  • Logical AND: &&
  • Logical OR: ||
  • Logical NOT: !

Bitwise Operators

  • Bitwise AND: &
  • Bitwise OR: |
  • Bitwise XOR: ^
  • Bitwise NOT: ~
  • Left shift: <<
  • Right shift: >>

Assignment Operators

  • Simple assignment: =
  • Compound assignment: +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=

Expressions and Statements

Expressions

An expression is a sequence of operations in C that produces a value. Expressions can be simple, like a variable or constant, or complex, involving multiple operators and operands. They often appear in assignment statements, function calls, conditionals, or loops.

Types

  • Arithmetic Expressions: Use arithmetic operators (+, -, *, /, %) for mathematical calculations.
  • Relational Expressions: Use comparison operators (==, !=, <, >, <=, >=) for comparisons.
  • Logical Expressions: Use logical operators (&&, ||, !) for logical evaluations.
  • Bitwise Expressions: Use bitwise operators (&, |, ^, ~, <<, >>) for bit-level operations.
  • Assignment Expressions: Use assignment operators (=, +=, -=, *=, /=, %=) for assignments.
  • Comma Expressions: Multiple expressions separated by commas (,), with the value of the last expression.

Example

int a = 5, b = 10;
int result = a + b; // Arithmetic expression
bool isEqual = a == b; // Relational expression
bool isTrue = true && false; // Logical expression
int bitwiseAnd = a & b; // Bitwise expression
a += 5; // Assignment expression
int lastValue = (a++, b, a); // Comma expression

Statements

A statement is the smallest executable unit in C, instructing the compiler to perform an action. Statements typically end with a semicolon (;).

Types

  • Expression Statements: Execute an expression, such as assignments.
  • Compound Statements: A group of statements enclosed in braces ({}), treated as a single block.
  • Control Statements: Control program flow, such as if, for, while, do-while, switch.
  • Function Call Statements: Invoke functions, possibly receiving return values.
  • Empty Statements: Consist only of a semicolon, performing no action.
int a = 5; // Expression statement
{
    int b = 10; // Compound statement
    printf("Inside block.\n");
}
if (a > 0) { // Control statement
    printf("a is positive.\n");
}
printf("Hello, world!"); // Function call statement
;

Sequential Structure

The sequential structure is the simplest control structure, where the program executes each line of code in the order it appears. This is the default execution mode and requires no special syntax.

Code Example

#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    printf("This is a simple program.\n");
    return 0;
}

In this example, the program first prints “Hello, World!”, then “This is a simple program.”, and finally returns 0, ending the main function.

Branching Structure

Branching structures allow the program to choose different execution paths based on conditions. C provides if and switch statements for branching.

if Statement

The if statement is the most common branching structure, executing code based on whether a condition is true or false.

Syntax

if (condition) {
    // Code executed if condition is true
} else {
    // Code executed if condition is false
}

Example

#include <stdio.h>

int main() {
    int x = 10;
    if (x > 0) {
        printf("x is positive.\n");
    } else {
        printf("x is not positive.\n");
    }
    return 0;
}

switch Statement

The switch statement provides a concise way to select a branch based on multiple conditions, cleaner than multiple if statements.

Syntax

switch (expression) {
    case value1:
        // Executed when expression equals value1
        break;
    case value2:
        // Executed when expression equals value2
        break;
    default:
        // Executed when expression matches no case
}

Example

#include <stdio.h>

int main() {
    int day = 3;
    switch (day) {
        case 1:
            printf("Monday\n");
            break;
        case 2:
            printf("Tuesday\n");
            break;
        case 3:
            printf("Wednesday\n");
            break;
        default:
            printf("Not a weekday\n");
    }
    return 0;
}

Looping Structure

Looping structures allow the program to repeat a block of code until a condition is met. C provides for, while, and do-while loops.

for Loop

The for loop is commonly used when the number of iterations is known.

Syntax

for (initialization; condition; increment) {
    // Loop body
}

Example

#include <stdio.h>

int main() {
    for (int i = 0; i < 5; i++) {
        printf("%d\n", i);
    }
    return 0;
}

while Loop

The while loop repeats a block of code as long as a condition is true.

Syntax

while (condition) {
    // Loop body
}

Example

#include <stdio.h>

int main() {
    int i = 0;
    while (i < 5) {
        printf("%d\n", i);
        i++;
    }
    return 0;
}

do-while Loop

The do-while loop executes the loop body at least once before checking the condition.

Syntax

do {
    // Loop body
} while (condition);

Example

#include <stdio.h>

int main() {
    int i = 0;
    do {
        printf("%d\n", i);
        i++;
    } while (i < 5);
    return 0;
}
Share your love