Introduction to C

A foundational look into the C programming language.

History of C

The C programming language was developed in the early 1970s by Dennis Ritchie at Bell Labs. It was created to be a system implementation language for the nascent Unix operating system.

C is a procedural, general-purpose language that provides low-level access to memory and machine instructions, making it highly efficient. Its influence is widespread, with many later languages like C++, C#, Java, and Python borrowing concepts directly from it.

Variables & Variable Names

In C, a variable is a name given to a storage area that our programs can manipulate. Each variable in C has a specific type, which determines the size and layout of the variable's memory.

Rules for Naming Variables:

  • Variable names can contain letters (both uppercase and lowercase), digits, and the underscore character (_).
  • The first character of a variable name must be a letter or an underscore. It cannot be a digit.
  • There is no rule on how long a variable name can be. However, some compilers might have restrictions.
  • Variable names are case-sensitive. For example, age and Age are two different variables.
  • Keywords (like int, while, etc.) cannot be used as variable names.

Data Types and Sizes

C provides a set of built-in data types. The size of these types can vary between different compilers and computer architectures.

Data Type Typical Size (bytes) Description Format Specifier
int 4 Integer values %d or %i
char 1 Single character %c
float 4 Single-precision floating-point number %f
double 8 Double-precision floating-point number %lf

Declaration of Variables and Constants

A declaration specifies a name and a type for a variable or constant. You must declare all variables before they can be used.

Declaring Variables

int score;          // Declares an integer variable named 'score'
float temperature = 98.6; // Declares and initializes a float
char grade = 'A';     // Declares and initializes a character

Defining Constants

Constants are fixed values that cannot be altered by the program. There are two primary ways to define them:

1. Using the `const` keyword:

const double PI = 3.14159;
const int MAX_USERS = 100;

2. Using `#define` preprocessor directive:

#define PI 3.14159
#define MAX_USERS 100

Arithmetic Operations

C supports the standard arithmetic operators. These operators follow a specific order of precedence, with multiplication, division, and modulo having higher precedence than addition and subtraction. You can use parentheses `()` to override the default precedence.

Operator Meaning Example
+ Addition a + b
- Subtraction a - b
* Multiplication a * b
/ Division a / b
% Modulo (remainder of division) a % b

Relational Operations

Relational operators are used to compare two values. The result of a relational operation is a boolean value: either true (represented by 1) or false (represented by 0).

Operator Meaning Example
== Equal to a == b
!= Not equal to a != b
> Greater than a > b
< Less than a < b
>= Greater than or equal to a >= b
<= Less than or equal to a <= b

Logical Operations

Logical operators are used to combine or negate conditions. They are often used with relational operators to create complex expressions. C uses short-circuit evaluation. For `&&`, if the first operand is false, the second is not evaluated. For `||`, if the first operand is true, the second is not evaluated.

Operator Meaning Example
&& Logical AND. True if both operands are true. (x > 5) && (y < 10)
|| Logical OR. True if at least one operand is true. (a == 0) || (b == 0)
! Logical NOT. Reverses the logical state of its operand. !(isFinished)

Practical Problems & Solutions

Problem 1: Sum of Two Numbers

Write a C program to ask the user for two integers, calculate their sum, and display the result.

Solution:

#include <stdio.h>

int main() {
    // Declare variables to store the two numbers and their sum
    int num1, num2, sum;

    // Prompt the user to enter the first number
    printf("Enter first integer: ");
    scanf("%d", &num1);

    // Prompt the user to enter the second number
    printf("Enter second integer: ");
    scanf("%d", &num2);

    // Calculate the sum
    sum = num1 + num2;

    // Print the result
    printf("Sum: %d\n", sum);

    return 0;
}

Explanation:

The program uses `printf()` to display prompts to the user and `scanf()` to read the integer values entered by the user. The `&` symbol before `num1` and `num2` in `scanf()` is the "address-of" operator; it tells `scanf` where in memory to store the input. Finally, it calculates the sum and prints it to the console.

Problem 2: Area of a Circle

Write a C program that calculates the area of a circle. Define PI as a constant, ask the user for the radius, and print the area.

Solution:

#include <stdio.h>

#define PI 3.14159

int main() {
    // Declare variables for radius and area
    float radius, area;

    // Prompt user for the radius
    printf("Enter the radius of the circle: ");
    scanf("%f", &radius);

    // Calculate the area using the formula: PI * r^2
    area = PI * radius * radius;

    // Display the result
    printf("The area of the circle with radius %.2f is %.2f\n", radius, area);

    return 0;
}

Explanation:

Here, `PI` is defined as a constant using `#define`. The program takes a floating-point number (`float`) as input for the radius. The area is calculated and then printed using `printf()`. The `%.2f` format specifier is used to display the floating-point numbers with only two digits after the decimal point.

Problem 3: Swap Two Numbers

Write a C program to swap the values of two integer variables using a third temporary variable.

Solution:

#include <stdio.h>

int main() {
    int a = 10, b = 20;
    int temp;

    printf("Before swapping: a = %d, b = %d\n", a, b);

    // Swapping logic
    temp = a;   // Store the value of 'a' in temp
    a = b;      // Assign the value of 'b' to 'a'
    b = temp;   // Assign the value stored in temp to 'b'

    printf("After swapping: a = %d, b = %d\n", a, b);

    return 0;
}

Explanation:

This classic problem demonstrates variable manipulation. To swap the values of `a` and `b`, we need a third variable, `temp`, as a temporary placeholder. We first copy the value of `a` into `temp`. Now that `a`'s original value is safe, we can overwrite `a` with the value of `b`. Finally, we take the original value of `a` (which is stored in `temp`) and assign it to `b`, completing the swap.

Problem 4: Check if a Number is Even or Odd

Write a C program that takes an integer from the user and checks whether the number is even or odd using the modulo operator.

Solution:

#include <stdio.h>

int main() {
    int number;

    printf("Enter an integer: ");
    scanf("%d", &number);

    // Check if the remainder when divided by 2 is 0
    if (number % 2 == 0) {
        printf("%d is an even number.\n", number);
    } else {
        printf("%d is an odd number.\n", number);
    }

    return 0;
}

Explanation:

This program introduces basic conditional logic with an `if-else` statement. The core of the logic is the expression `number % 2`. The modulo operator (`%`) gives the remainder of a division. Any integer that is perfectly divisible by 2 is even, meaning the remainder is 0. If the condition `number % 2 == 0` is true, the `if` block is executed; otherwise, the `else` block is executed.

Problem 5: Convert Fahrenheit to Celsius

Write a C program to convert a temperature from Fahrenheit to Celsius. The formula is C = (F - 32) * 5 / 9.

Solution:

#include <stdio.h>

int main() {
    float fahrenheit, celsius;

    printf("Enter temperature in Fahrenheit: ");
    scanf("%f", &fahrenheit);

    // Note: We use 5.0/9.0 to ensure floating-point division
    celsius = (fahrenheit - 32.0) * 5.0 / 9.0;

    printf("%.2f Fahrenheit is equal to %.2f Celsius.\n", fahrenheit, celsius);

    return 0;
}

Explanation:

This example deals with floating-point arithmetic. It's important to use `float` or `double` for temperatures to get accurate decimal results. In the calculation, we use `32.0`, `5.0`, and `9.0` instead of `32`, `5`, and `9`. This is crucial because in C, dividing two integers (e.g., `5 / 9`) results in an integer (which would be `0`), truncating the decimal part. By using floating-point literals, we ensure that the compiler performs floating-point division, yielding a correct decimal result.

Problem 6: Leap Year Checker

Write a C program to check if a year entered by the user is a leap year. A leap year is divisible by 4, but century years are not leap years unless they are divisible by 400.

Solution:

#include <stdio.h>

int main() {
    int year;

    printf("Enter a year: ");
    scanf("%d", &year);

    // A year is a leap year if it's divisible by 400
    // OR if it's divisible by 4 but NOT by 100.
    if ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)) {
        printf("%d is a leap year.\n", year);
    } else {
        printf("%d is not a leap year.\n", year);
    }

    return 0;
}

Explanation:

This problem is a great exercise for logical operators. The condition `(year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)` perfectly translates the rule for leap years into C code. The parentheses are important to enforce the correct order of operations. The `&&` (AND) has higher precedence than `||` (OR), but using parentheses makes the logic explicit and easier to read.

Problem 7: Sum of the Digits of a 3-Digit Number

Write a C program that takes a 3-digit integer from the user and calculates the sum of its digits.

Solution:

#include <stdio.h>

int main() {
    int number, originalNumber;
    int digit1, digit2, digit3, sum;

    printf("Enter a 3-digit number: ");
    scanf("%d", &number);

    originalNumber = number; // Save the original number for the output message

    // Extract the last digit
    digit3 = number % 10;
    number = number / 10; // Remove the last digit

    // Extract the new last digit (the middle one)
    digit2 = number % 10;
    number = number / 10; // Remove the last digit

    // The remaining number is the first digit
    digit1 = number;

    sum = digit1 + digit2 + digit3;

    printf("The sum of the digits of %d is %d.\n", originalNumber, sum);

    return 0;
}

Explanation:

This program demonstrates a powerful use of the modulo (`%`) and integer division (`/`) operators. `number % 10` always gives you the last digit of the number. `number / 10` (with integers) effectively removes the last digit. By repeating this process, we can isolate each digit of the number and then add them together.

Problem 8: Convert Lowercase Character to Uppercase

Write a C program that reads a lowercase letter from the user and converts it to uppercase.

Solution:

#include <stdio.h>

int main() {
    char lower, upper;

    printf("Enter a lowercase letter: ");
    scanf(" %c", &lower); // Note the space before %c

    // The ASCII values for 'a' through 'z' and 'A' through 'Z' are sequential.
    // The difference between a lowercase letter and its uppercase version is constant.
    upper = lower - 'a' + 'A';

    printf("The uppercase equivalent is: %c\n", upper);

    return 0;
}

Explanation:

This example highlights that `char` variables are internally treated as small integers representing ASCII values. Because the ASCII codes for 'a'-'z' and 'A'-'Z' are consecutive, the difference between any lowercase letter and 'a' is the same as the difference between its corresponding uppercase letter and 'A'. The formula `lower - 'a' + 'A'` calculates the uppercase equivalent. The space in `scanf(" %c", ...)` is important; it tells `scanf` to skip any whitespace characters (like the Enter key pressed from a previous input) before reading the character.