Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Core C Programming: Syntax, Types, Control Flow, and Arrays

Tech 2

Origins and Characteristics of C

C emerged from Bell Labs, crafted by Dennis Ritchie to facilitate the development of the Unix operating system. Prior languages were either too hardware-bound (Assembly) or lacked the necessary abstraction. C bridged this gap, evolving from the B language to offer both high-level structures and low-level memory manipulation.

Key attributes include:

  • Efficiency: Compiles directly to optimized machine instructions.
  • Portabiltiy: Codebase adapts across different hardware architectures with minimal changes.
  • Modularity: Supports functional decomposition and structured programming.
  • Standardization: Governed by ANSI/ISO standards ensuring long-term stability.

Basic Syntax and Structure

A C program relies on a defined entry point and preprocessor directives.

#include <stdio.h>

int main(void) {
    printf("System initialized.\n");
    return 0;
}
  • #include <stdio.h>: Imports the standard I/O library header.
  • main(): The mandatory entry point of execution.
  • printf(): Outputs formatted text to the console.
  • return 0;: Signals successful termination to the OS.
  • Semicolons terminate statements. Curly braces define code blocks.

Comments are written as // for single lines or /* ... */ for blocks.

Variables and Keywords

Variables must be declared with a data type before use. Naming rules dictate that identifiers begin with a letter or underscore, avoiding reserved keywords.

int counter;      // Declaration
counter = 42;     // Initialization
float ratio = 3.14f; // Declaration and initialization

Reserved keywords (e.g., int, return, while, struct, const) cannot be used as variable names.

Data Types and Memory Sizes

Data types define the size and interpretation of variables.

  • Character: char (1 byte). Stores ASCII values. c char letter = 'A'; printf("%c %d\n", letter, letter); // Prints A 65 // Case conversion char lower = letter + ('a' - 'A');

  • Boolean: _Bool or bool via <stdbool.h> (1 byte, true or false).

  • Integers: short, int, long, long long.

  • Floating-point: float, double, long double.

The sizeof operator returns memory consumption in bytes (result is of type size_t, printed using %zu).

printf("int size: %zu bytes\n", sizeof(int)); // Typically 4
printf("double size: %zu bytes\n", sizeof(double)); // Typically 8

Portable Integer Types

To ensure consistent byte widths across platforms, <stdint.h> provides fixed-width types like int8_t, uint32_t, and int64_t.

Constants

Values that remain unchanged during execution.

  1. Literals: Direct values (e.g., 100, 3.14f, 'X').

  2. Preprocessor Macros: Defined globally without semicolons. c #define MAX_USERS 50

  3. Const Qualifier: Enforces immutability at compile time. c const float PI = 3.14159f;

Numeral Systems and Memory Representation

C supports decimal, octal (prefix 0), hexadecimal (prefix 0x), and binary (prefix 0b) literals.

int dec = 15;
int oct = 017;
int hex = 0xF;
int bin = 0b1111;
printf("%d %#o %#x\n", dec, oct, hex);

Signed integers use two's complement representation. The most significant bit (MSB) indicates the sign (0 for positive, 1 for negative), with negative values formed by inverting bits and adding one.

Standard Input and Output

printf handles formatted output using specifiers (%d for int, %f for float, %c for char, %s for string, %p for pointesr).

scanf captures user input. It requires the address-of operator & for standard variables.

#define _CRT_SECURE_NO_WARNINGS // For MSVC compiler safety warnings
#include <stdio.h>

int main(void) {
    int age;
    scanf("%d", &age);
    printf("Age received: %d\n", age);
    return 0;
}

Operators

  • Arithmetic: +, -, *, /, %, ++, --
  • Relational: ==, !=, <, >, <=, >=
  • Logical: && (AND), || (OR), ! (NOT)
  • Bitwise: &, |, ^, ~, <<, >>

Bitwise Manipulation

Bitwise operators are essential for low-level hardware control and flags management.

#include <stdio.h>
#include <stdint.h>

int main(void) {
    uint8_t config = 0b01010101;

    // Set bit 4 (force to 1)
    config |= (1 << 4);

    // Clear bit 0 (force to 0)
    config &= ~(1 << 0);

    // Toggle bit 7
    config ^= (1 << 7);

    printf("Modified config: 0x%02X\n", config);
    return 0;
}

Type Conversions

  • Implicit (Widening): Automatically converts smaller types to larger types (e.g., int to double) to prevent data loss during arithmetic operations.
  • Explicit (Casting): Manually forcing a type conversion using the cast operator. c double pi = 3.14159; int truncated = (int)pi; // truncated becomes 3

Control Flow

Conditional Branching

if-else executes blocks based on boolean expressions.

if (score >= 90) {
    printf("Grade A\n");
} else if (score >= 80) {
    printf("Grade B\n");
} else {
    printf("Grade C\n");
}

switch evaluates an integer or character against discrete cases.

switch (opcode) {
    case '+': compute_add(); break;
    case '-': compute_sub(); break;
    default: printf("Invalid operation\n");
}

Iteration

  • for loop: Ideal for known iteration counts. c for (int i = 0; i < 10; i++) { /* ... */ }

  • while loop: Evaluates condition before execution. May execute zero times. c while (is_active) { /* ... */ }

  • do-while loop: Evaluates condition after execution. Guarantees at least one iteration. c do { /* ... */ } while (retry_flag);

break exits the loop entirely, while continue skips the current iteration and proceeds to the next cycle.

Functions

Functions encapsulate reusable logic. They must be declared (prototyped) or defined before use.

// Definition
int add(int x, int y) {
    return x + y;
}

int main(void) {
    int sum = add(5, 7); // Invocation
    return 0;
}

Variables declared inside functions are local (stack-allocated, scope-limited). Variables declared outside are global (static storage duration, accessible file-wide).

Arrays

Arrays store contiguous blocks of homogenous data.

int data[5] = {10, 20, 30, 40, 50};
int length = sizeof(data) / sizeof(data[0]);

Array indices begin at 0. The array name acts as a constant pointer to the first element. Bounds checking is not enforced; out-of-bounds access causes undefined behavior.

Memory Layout and Dynamic Allocation

Elements reside in adjacent memory addresses. For a 32-bit int array, &data[1] is exactly 4 bytes after &data[0].

For variable-length requirements, dynamic memory allocation is used.

#include <stdlib.h>

int count = 20;
int *dyn_array = (int*)malloc(count * sizeof(int));
if (dyn_array != NULL) {
    // Usage
    dyn_array[0] = 99;
    free(dyn_array); // Release memory
}

Array Operations and Function Passing

When passed to functions, arrays decay to pointers, losing size information. The length must be passed separately.

void reverse_array(int arr[], int len) {
    int start = 0;
    int end = len - 1;
    while (start < end) {
        int temp = arr[start];
        arr[start] = arr[end];
        arr[end] = temp;
        start++;
        end--;
    }
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.