W2 - Shorts 📚🔍- Compiling, Debugging, Arrays, Command Line Arguments and Exit Statuses in C

Read more here
CS50 IDE: https://cs50.dev/ (Online VSCode)
CS50 Library Documentation: https://manual.cs50.io/#cs50.h

#CS50x #C #Computer_Science #VisualStudioCode

🔙 Previous Part | Next Part 🔜

↩️ Go Back

Table of Contents:

🔙 Previous Part | Next Part 🔜

↩️ Go Back


A) Introduction to Functions: Writing, Declaring, and Using Functions in C 🎦

Functions are essential tools for writing efficient, modular, and maintainable code.

This guide introduces the concept of functions in C, their purpose, and how to implement and use them effectively, culminating in a practice problem about validating triangles.

A.1) What Are Functions?

A function is a self-contained block of code designed to perform a specific task. Functions:

Functions abstract complex tasks into manageable black boxes: you only need to know what the function does, not how it does it.

A.2) Why Use Functions?

Functions provide the following benefits:

  1. Modularity: Break down large programs into smaller, manageable parts.
  2. Reusability: Write a function once and reuse it in different parts of your code or across projects.
  3. Debugging: Debug smaller chunks of code instead of searching through thousands of lines.
  4. Clarity: Make code more readable by assigning meaningful names to logical blocks.

A.3) STEP1 - Declaring a Function

Every function declaration in C has three main parts:

  1. Return Type: Specifies the type of value the function will return.
  2. Name: Describes the purpose of the function.
  3. Argument List: Lists the inputs the function will take, including their types.

Parts of a Function Declaration:

Example:

int addTwoInts(int a, int b);

Note: place the function prototype at the top of the main to tell the compiler that you will use a function.


A.4) STEP2 - Defining a Function (logic and return output)

After declaring a function, define its behavior in the function body. The body includes:

Example:

int addTwoInts(int a, int b) {
    return a + b;
}

A.5) STEP3 - Calling a Function

To use a function, pass appropriate arguments matching the types in its declaration. The function will return a value (if specified), which can be stored or used directly.

Example:

int x = 5, y = 10;
int sum = addTwoInts(x, y);
printf("The sum is %d\n", sum);  // Output: The sum is 15

A.6) Note: Functions with No Inputs or Outputs (void)

  1. No Inputs: Use void in the argument list.
    void sayHello() {
        printf("Hello, World!\n");
    }
    
  2. No Outputs: Use void as the return type.
    void printSum(int a, int b) {
        printf("The sum is %d\n", a + b);
    }
    

A.7) Practice Problem: Validating a Triangle

Write a function validTriangle that:

Rules for Valid Triangles

  1. All sides must be positive.
  2. The sum of any two sides must be greater than the third side.

Function Declaration

bool validTriangle(float x, float y, float z);

Function Definition

bool validTriangle(float x, float y, float z) {
    if (x <= 0 || y <= 0 || z <= 0) {
        return false;  // Sides must be positive
    }
    if (x + y <= z || x + z <= y || y + z <= x) {
        return false;  // Triangle inequality rule
    }
    return true;  // Valid triangle
}

Using the validTriangle Function - Example Program:

#include <cs50.h>
#include <stdio.h>
#include <stdbool.h>

bool validTriangle(float x, float y, float z);

int main(void) {
    float a = get_float("Enter side a: ");
    float b = get_float("Enter side b: ");
    float c = get_float("Enter side c: ");
    
    if (validTriangle(a, b, c)) {
        printf("The sides form a valid triangle.\n");
    } else {
        printf("The sides do not form a valid triangle.\n");
    }
}

bool validTriangle(float x, float y, float z) {
    if (x <= 0 || y <= 0 || z <= 0) {
        return false;
    }
    if (x + y <= z || x + z <= y || y + z <= x) {
        return false;
    }
    return true;
}

A.8) Key Takeaways about Function

  1. Functions Improve Modularity: Break down complex tasks into reusable units.
  2. Structure Matters: Use clear names and organize your declarations, definitions, and calls for readability.
  3. Practice Writing Functions: Start with simple functions and build up to more complex ones.

This approach will help you tackle real-world problems systematically while keeping your code clean and maintainable.


B) Understanding Variable Scope in C 🎦

Key Concepts of Variable Scope:

  1. Scope: Defines where a variable can be accessed in a program.
  2. Types of Scope:
    • [[Local Variables]]: Can only be accessed within the function they are declared in.
    • [[Global Variables]]: Declared outside all functions and can be accessed by any function.

B.1) Local Variables Example

Consider the following example:

#include <stdio.h>

int triple(int x) {
    return x * 3;  // `x` is local to `triple`.
}

int main() {
    int result = triple(5);  // `result` is local to `main`.
    printf("%d\n", result); // Prints 15
    return 0;
}

Scope explained:


B.2) Global Variables Example

Consider the following example:

#include <stdio.h>

float global = 0.5050; // Global variable

void triple_global() {
    global *= 3;  // Modifies the global variable
}

int main() {
    triple_global();
    printf("%.2f\n", global); // Prints 1.515
    return 0;
}

Scope explained:


B.3) Local vs Global Scope: Why It Matters

  1. Local Variables:
    • [[Passed by value]]: A copy of the variable is sent to the function.
    • Changes in the callee (function receiving the variable) do not affect the caller's variable unless explicitly returned and reassigned.

Example: no effect on foo

int triple(int x) {
    return x * 3;
}
int main(void) {
    int foo = 4;  
    triple(foo); // foo is not multiplied, 
 		        //we are passing the value of foo to a copy called x
    printf("%d\n", foo); // Prints 4
    return 0;
}

Example: overwrite foo

int triple(int x) {
    return x * 3;
}
int main(void) {
    int foo = 4;
    foo = triple(foo);  // Updates `foo` with the returned value 
    printf("%d\n", foo); // Prints 12
    return 0;
}
  1. Global Variables:
    • Changes persist across all functions that access it, which can lead to unintended consequences.

B.4) Exercise: Troubleshooting Variable Scope (Step by Step)

Consider the following program,

Example with conflicting x name:

#include <stdio.h>

int increment(int x) {
    x++;  // Modifies a local copy of `x` (think of it as x_incre)
    return x;
}

int main(void) {
    int x = 5; // Local to main (think of it as x_main)
    int y = increment(x); // Passes a copy of `x_main` to `increment`
    printf("x: %d, y: %d\n", x, y);
    return 0;
}

In this example:

Step-by-Step Execution:

  1. main declares x and assigns it 5.
  2. main calls increment(x), passing a copy of x to increment.
  3. increment:
    • Increments its local copy of x to 6.
    • Returns 6 to main.
  4. main assigns the returned value (6) to y.
  5. Final output: x: 5, y: 6. <----------

B.5) Key Takeaways about Variable Scope


C) Introduction to Arrays in C 🎦

C.1) What Are Arrays?

Arrays are a fundamental [[data structure]] that allow you to store multiple variables of the same data type in contiguous memory locations.

Instead of creating individual variables for each data point, arrays let you group and work with these data points efficiently.


C.2) Key Concepts of Arrays (analogy)

  1. Structure:

    • Arrays consist of elements of the same data type (e.g., int, char, float).
    • Each element is stored at a contiguous memory location.
    • Elements are accessed by their index, starting from 0 in C.
  2. Analogy: Arrays are like a Mail Bank

    • Imagine a post office wall filled with identical-sized mailboxes.
    • Each mailbox (element) holds mail (data).
    • You can access a specific mailbox using its number (index).

C.3) Examples: Declaring and Initializing Arrays

  1. Declaration Syntax:

    • Type: Data type of array elements.
    • Name: Identifier for the array.
    • Size: Number of elements the array will hold.
  2. Examples:

    • An array of integers for student grades:

      int student_grades[40];
      
    • An array of doubles for menu prices:

      double menu_prices[8];
      
  3. Initialization:
    Arrays can be initialized at the time of declaration:

    int numbers[3] = {1, 2, 3};
    

    If the size is omitted, the compiler infers it from the number of values provided:

    int numbers[] = {1, 2, 3}; // Size is 3
    

the instantiation syntax, help us avoid the individual element syntax (since copy and pasting variable names is what we want to avoid),


C.4) Examples: Accessing Array Elements

  1. Indexing:

    • Access elements using their index:
      student_grades[0] = 95; // Assign 95 to the first element
      
    • Use indices in loops for iteration:
      for (int i = 0; i < 40; i++) {
          printf("%d\n", student_grades[i]);
      }
      
  2. Danger of Out-of-Bounds Access:

    • Accessing an element outside the array's declared size can cause undefined behavior or segmentation faults:
      int arr[5];
      arr[10] = 42; // Undefined behavior
      

C.5) Example: Working with Multidimensional Arrays

  1. Syntax:
    type array_name[size1][size2];
    
    • Example for a 10x10 Battleship board:
      bool battleship[10][10];
      

Example: string words[2]


C.6) Example: Operations on Arrays (similar to variables, but not the same)

Assigning Values:

BUT.....

INSTEAD....


C.7) Passing Arrays to Functions (Passing by Reference - Pointers)

  1. Passing by Reference:

    • Unlike other variables, arrays are [[passed by reference]] to functions.
    • So, changes to the array in the function affect the original array:
      void modify_array(int arr[], int size) {
          for (int i = 0; i < size; i++) {
              arr[i] *= 2;
          }
      }
      
      int main() {
          int nums[3] = {1, 2, 3};
          modify_array(nums, 3);
          // nums is now {2, 4, 6}
          return 0;
      }
      
  2. Passing by Value (How Other Variables Work):

    • Non-array variables are [[passed by value]] (a copy is passed to the function).

C.7.1) Comparing: Passing Arrays to Function - int Arrays, char Arrays, and Strings

In C, passing an array to a function is mostly similar regardless of whether it's an array of int, char, or a "string" (a character array). Here’s a breakdown of how to pass each type:

1. Passing an int Array

When you pass an int array to a function, you generally do so by specifying the array as a pointer (since arrays decay to pointers when passed to functions). You also usually pass the size of the array separately since C functions do not have a way to know the size of an array just by looking at the pointer.

Example

#include <stdio.h>

void printIntArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    int size = sizeof(numbers) / sizeof(numbers[0]);
    printIntArray(numbers, size);  // Pass array and its size
    return 0;
}

In printIntArray, arr is treated as a pointer to the first element of the array numbers.

2. Passing a char Array (Character Array)

A char array can be used for storing strings (sequences of characters terminated by a null character '\0'). When you pass a char array, it’s often used as a "string" if it’s null-terminated. Here’s how you pass a char array:

Example

#include <stdio.h>

void printCharArray(char arr[]) {
    printf("%s\n", arr);  // Assume arr is a null-terminated string
}

int main() {
    char name[] = "Hello, World!";
    printCharArray(name);  // Pass the character array
    return 0;
}

In this example, printCharArray assumes arr is null-terminated (a "string" in C terms). Note that you don’t need to pass the size for null-terminated strings because printf with %s will stop printing at the '\0'.

3. Passing a "String" (Character Array) Using <string.h>

If you’re working with a string (character array) and need to manipulate or process it, you can use functions from <string.h>. The function declarations don’t change; you still pass the character array as char arr[] or char *arr.

Here’s an example of passing a string to a function and using functions from <string.h>:

#include <stdio.h>
#include <string.h>

void printStringLength(char str[]) {
    int length = strlen(str);  // Use strlen from string.h
    printf("Length of string: %d\n", length);
}

int main() {
    char greeting[] = "Hello!";
    printStringLength(greeting);  // Pass the string
    return 0;
}

In this example, printStringLength calculates the length of str using strlen, a function from <string.h>, which works on null-terminated strings.

> Summary of Differences

In all cases, the array is passed as a pointer to the first element, but you may need to handle it differently based on its type and intended use.


C.7.2) Practice Problem: Understanding Passing Mechanisms

Analyze the following code:

#include <stdio.h>

void set_array(int arr[4]) {
    arr[0] = 42; // Modifies the original array
}

void set_int(int x) {
    x = 42; // Modifies only the local copy of x
}

int main() {
    int a = 10;
    int b[4] = {0, 1, 2, 3};

    set_int(a);
    set_array(b);

    printf("%d %d\n", a, b[0]); // Output?
    return 0;
}

Solution:

  1. set_int:

    • Modifies a local copy of a, so a remains unchanged.
  2. set_array:

    • Modifies the original array b since arrays are passed by reference.

Output:

10 42
Note: %i vs%d

Both %d and %i can be used with printf to print integers, but there are some subtle differences in how they behave in certain contexts:

  • %d is specifically for decimal integers. (base 10 only)
  • It ensures proper formatting and type matching during output.
  • If a non-integer is passed for %d, behavior is undefined (may result in errors or incorrect output).

EXAMPLE:


C.8) Summary: Arrays in C


D) Using Command Line Arguments in C 🎦

[[Command-line arguments]] allow users to provide inputs to a program directly when executing it from the terminal.

This differs from in-program prompts where inputs are collected during runtime.

Here's an explanation of how command-line arguments work in C...

D.1) Declaring main with Command-Line Arguments

To handle command-line arguments, modify the main function declaration as follows:

int main(int argc, string argv[])

D.1.2) Key Concepts of argc and argv

  1. argc - Argument Count:

    • Counts the number of arguments, including the program's name.
      For example:
      ./greedy 1024 CS50
      
      Here, argc = 3 because:
      • argv[0] is ./greedy (program name).
      • argv[1] is "1024".
      • argv[2] is "CS50".
  2. argv - Argument Vector:

    • Stores the arguments as an array of strings:
      argv[0] = "./greedy"; 
      argv[1] = "1024"; 
      argv[2] = "CS50";
      
    • Indexes:
      • The first element (argv[0]) is always the program name.
      • The last element is at argv[argc - 1].
    • Data Type:
      All elements in argv are strings, even if they look like numbers. For example, "1024" in argv[1] is stored as the string "1024", not the integer 1024.


D.2) Example: Converting Input Strings to Usable Integers (atoi())

Example: Understanding Input - stringvs int

If a program is executed with the following command:

./program hello 42

If you want to work with numeric values in argv:


D.3) Common Problems when using Command Line Arguments

  1. Accessing Out-of-Bounds Elements:

    • If argc = 3:
      • Valid indexes: argv[0] to argv[2].
      • Accessing argv[3] leads to undefined behavior or a [[segmentation fault]].
    • Always ensure your loops and conditionals check argc to avoid accessing invalid indexes.
  2. String vs. Numeric Data:

    • Remember that arguments in argv are strings. Operations like subtraction or addition require conversion to numeric types. Use atoi()

D.4) Examples: Practical Usage of CL Arguments

  1. Single Argument Validation Example:

    #include <stdio.h>
    
    int main(int argc, string argv[]) {
        if (argc != 2) {
            printf("Usage: ./program <argument>\n"); //This is the string that `printf` will display. It tells the user they should run the program with a specific format.
            return 1;
        }
        printf("Argument: %s\n", argv[1]);
        return 0;
    }
    
    • This program checks if exactly one argument (besides the program name) was provided.
  2. Multiple Arguments Example:

    #include <stdio.h>
    
    int main(int argc, string argv[]) {
        for (int i = 0; i < argc; i++) {
            printf("argv[%d]: %s\n", i, argv[i]);
        }
        return 0;
    }
    
    • This program prints all arguments provided at the command-line.

D.4.1) Benefits of Command-Line Arguments

  1. Allow users to configure program behavior at the time of execution.
  2. Enable automation and script integration by passing parameters directly.
  3. Simplify user interaction by reducing in-program prompts.

Command-line arguments are a foundational concept in C programming, offering flexibility and efficiency in how programs handle input.


🔙 Previous Part | Next Part 🔜

↩️ Go Back


Z) 🗃️ Glossary

File Definition
Uncreated files Origin Note
Command-line arguments W2 - Shorts 📚🔍- Compiling, Debugging, Arrays, Command Line Arguments and Exit Statuses in C
data structure W2 - Shorts 📚🔍- Compiling, Debugging, Arrays, Command Line Arguments and Exit Statuses in C
Global Variables W2 - Shorts 📚🔍- Compiling, Debugging, Arrays, Command Line Arguments and Exit Statuses in C
Local Variables W2 - Shorts 📚🔍- Compiling, Debugging, Arrays, Command Line Arguments and Exit Statuses in C
passed by reference W2 - Shorts 📚🔍- Compiling, Debugging, Arrays, Command Line Arguments and Exit Statuses in C
passed by value W2 - Shorts 📚🔍- Compiling, Debugging, Arrays, Command Line Arguments and Exit Statuses in C
Passed by value W2 - Shorts 📚🔍- Compiling, Debugging, Arrays, Command Line Arguments and Exit Statuses in C
segmentation fault W2 - Shorts 📚🔍- Compiling, Debugging, Arrays, Command Line Arguments and Exit Statuses in C
On this page
  • A) Introduction to Functions: Writing, Declaring, and Using Functions in C 🎦
    1. A.1) What Are Functions?
    2. A.2) Why Use Functions?
    3. A.3) STEP1 - Declaring a Function
    4. A.4) STEP2 - Defining a Function (logic and return output)
    5. A.5) STEP3 - Calling a Function
    6. A.6) Note: Functions with No Inputs or Outputs (void)
    7. A.7) Practice Problem: Validating a Triangle
    8. A.8) Key Takeaways about Function
  • B) Understanding Variable Scope in C 🎦
    1. B.1) Local Variables Example
    2. B.2) Global Variables Example
    3. B.3) Local vs Global Scope: Why It Matters
    4. B.4) Exercise: Troubleshooting Variable Scope (Step by Step)
    5. B.5) Key Takeaways about Variable Scope
  • C) Introduction to Arrays in C 🎦
  • C.1) What Are Arrays?
  • C.2) Key Concepts of Arrays (analogy)
  • C.3) Examples: Declaring and Initializing Arrays
  • C.4) Examples: Accessing Array Elements
  • C.5) Example: Working with Multidimensional Arrays
  • C.6) Example: Operations on Arrays (similar to variables, but not the same)
  • C.7) Passing Arrays to Functions (Passing by Reference - Pointers) C.7.1) Comparing: Passing Arrays to Function - int Arrays, char Arrays, and Strings
  • 1. Passing an int Array
  • 2. Passing a char Array (Character Array)
  • 3. Passing a "String" (Character Array) Using
  • > Summary of Differences
  • C.7.2) Practice Problem: Understanding Passing Mechanisms
  • C.8) Summary: Arrays in C
  • D) Using Command Line Arguments in C 🎦
    1. D.1) Declaring main with Command-Line Arguments
      1. D.1.2) Key Concepts of argc and argv
    2. D.2) Example: Converting Input Strings to Usable Integers (atoi())
    3. D.3) Common Problems when using Command Line Arguments
    4. D.4) Examples: Practical Usage of CL Arguments
      1. D.4.1) Benefits of Command-Line Arguments
  • Z) 🗃️ Glossary