# Week 6: Pointer (1)

A pointer in C is a type of variable that stores the memory address of another variable. Unlike regular variables that hold a specific value like an integer or a character, pointers hold addresses where these values are stored.

<figure><img src="/files/uGgBgZAvtkkMD7Id0XP4" alt="" width="563"><figcaption></figcaption></figure>

### <mark style="color:green;">Why Do We Use Pointers?</mark>

1. **Efficiency in Handling Arrays and Strings:**
   * Pointers provide a more efficient way to handle arrays and strings. Since they directly access memory locations, operations like traversing an array or string can be done more quickly.
2. **Dynamic Memory Allocation:**
   * Pointers are essential for dynamic memory allocation in C. This allows programs to allocate memory while running, which is crucial for applications where the size of memory needed isn't known in advance.
3. **Building Complex Data Structures:**
   * They are key in constructing complex data structures such as linked lists, trees, and graphs. These structures require dynamic memory allocation and pointers provide the flexibility to efficiently manage memory.
4. **Functionality and Flexibility in Functions:**
   * Pointers enable passing large structures or arrays to functions with efficiency and ease. They also allow returning multiple values from a function through pointer arguments.
5. **Direct Memory Access:**
   * They offer a way to directly read and write in memory, which can lead to highly efficient code in system-level programming.
6. **Compatibility with Low-level System Hardware:**
   * Pointers are crucial in systems programming for interacting directly with memory, which is essential for hardware-level operations.

Defining a pointer in C involves specifying the type of data the pointer will reference and then using a specific syntax to declare the pointer variable. Here's a step-by-step guide on how to define a pointer in C:

## <mark style="color:yellow;">Pointer Variable Definitions and Initialization</mark>

The general syntax for declaring a pointer in C is as follows:

```c
type *pointerName;
```

* **`type`**: The data type of the variable that the pointer will point to. This could be any of C's fundamental data types (e.g., `int`, `float`, `char`) or derived types like structures.
* **`*`**: The asterisk (\*) is the <mark style="color:orange;">dereference operator</mark> and is used in the declaration to indicate that this is a pointer variable.
* **`pointerName`**: The name of the pointer variable. Like any variable name, it should be descriptive and follow C naming conventions.

Here are a few examples of pointer declarations in C:

```c
int *ptr;      // Pointer to an integer
char *cptr;    // Pointer to a character
float *fptr;   // Pointer to a float
void *vptr;    // Pointer to an object of any type (generic pointer)
```

A pointer is usually initialized to the address of a variable using the address-of operator (`&`). Here's an example:

```c
int y = 5;
int *yPtr = &y;  // The pointer ptr now holds the address of var
```

* `&y` gives the address of the variable `y`, and `yPtr` is initialized with this address. Now, `yPtr` points to `y`.

<figure><img src="/files/wN1L555AmtbP5Ly1Tbq8" alt="" width="563"><figcaption><p>Pointer representation in the memory</p></figcaption></figure>

To use the pointer:

* **Dereferencing**: To access the value at the address a pointer is holding, you use the dereference operator (`*`) again, but this time in an expression:

```c
int data = *yPtr;  // Dereferencing yPtr gives the value of y, which is 5
```

* **Assignment**: You can change the value of the variable pointed to by a pointer by dereferencing the pointer on the left-hand side of an assignment:

```c
*yPtr = 20;  // This changes the value of y to 20
```

#### <mark style="color:orange;">Example</mark>

The example demonstrates the pointer operators `&` and `*`. The `printf` conversion spec- ification `%p` outputs a memory location as a hexadecimal integer on most platforms. The output shows that the address of `a` and the value of `aPtr` are identical, confirming that `a`’s address was indeed assigned to the pointer variable `aPtr`. The `&` and `*` operators are complements of one another. Applying both consecutively to aPtr in either order produces the same result. The addresses in the output will vary across systems that use different processor architectures, different compilers and even different compiler settings.

```c
#include <stdio.h>

int main()
{
    int a = 7;
    int *aPtr = &a;

    printf("Address of a is %p\nValue of aPtr is %p\n\n", &a, aPtr);
    printf("Value of a is %d\nValue of *aPtr is %d\n\n", a, *aPtr);
    printf("Showing that * and & are complements of each other\n");
    printf("&*aPtr = %p\n*&aPtr = %p\n", &*aPtr, *&aPtr);

    return 0;
}
```

Output will look like

```
Address of a is 0x7ffcf31c6d1c
Value of aPtr is 0x7ffcf31c6d1c

Value of a is 7
Value of *aPtr is 7

Showing that * and & are complements of each other
&*aPtr = 0x7ffcf31c6d1c
*&aPtr = 0x7ffcf31c6d1c
```

## <mark style="color:yellow;">Passing Arguments to Functions by Reference</mark>

Function arguments in C can be passed in two ways: <mark style="color:orange;">**pass-by-value**</mark> and <mark style="color:orange;">**pass-by-reference**</mark>. Generally, arguments are passed by value, with the exception of arrays, which are passed by reference. This method allows functions to alter variables in the calling function and handle pointers to large data objects without incurring the overhead associated with copying these objects, as is the case with pass-by-value. While a return statement in a function is limited to returning a single value to the caller, passing arguments by reference provides a means for a function to effectively 'return' multiple values by modifying the variables of the caller.

### <mark style="color:green;">Pass-by-Value</mark>

Passing by value means that the function receives a copy of the argument, not the original variable itself. Changes made to the parameter inside the function do not affect the original argument.

```c
void modify(int val) {
    val = 10;  // Modifying the copy of the variable
}

int main() {
    int x = 5;
    
    modify(x);  // Passing the value of x
    // x is still 5, as only the copy was modified in the function
    
    x = modify(x);
    // Value of x is modified to 10
    return 0;
}
```

### <mark style="color:green;">Pass-by-Reference</mark>

In C, passing by reference means passing the address of a variable (usually using pointers) to a function so that the function can directly modify the variable's value.

```c
void modify(int *ptr) {
    *ptr = 10;  // Modifying the value at the address pointed to by ptr
}

int main() {
    int x = 5;
    modify(&x);  // Passing the address of x
    // x is now 10
    return 0;
}
```

### <mark style="color:green;">Comparison between Pass-by-Value and Pass-by-Reference</mark>

* **Pass by Value**: The original variable is not affected by what happens inside the function. It's a safe way to ensure that the original data cannot be accidentally modified. However, it can be less efficient for large data structures since it involves creating copies.
* **Pass by Reference**: The function has direct access to and can modify the original variable. This approach is more efficient for large data structures but requires careful management to avoid unintended side-effects.

### <mark style="color:green;">**Something Important to Consider for Pass-by-Reference**</mark>

* <mark style="color:orange;">**Null Pointers**</mark>: Always check if pointers are `NULL` before dereferencing to avoid segmentation faults.
* <mark style="color:orange;">**Scope**</mark>: Variables should have a scope beyond the function call (e.g., not local to another function) to ensure they exist throughout the function execution.
* <mark style="color:orange;">**Const Correctness**</mark>: If a function should not modify the data pointed to by the pointer, use `const` keyword to enforce this.

## <mark style="color:yellow;">`NULL`</mark> <mark style="color:yellow;"></mark><mark style="color:yellow;">Pointers</mark>

The concept of a `NULL` pointer is an important aspect of pointer usage in C programming. A `NULL` pointer is a special pointer that points to nothing or no valid memory location. It is used as a sentinel value to indicate that the pointer is not intended to point to an accessible memory location.

### <mark style="color:green;">Why Use</mark> <mark style="color:green;"></mark><mark style="color:green;">`NULL`</mark> <mark style="color:green;"></mark><mark style="color:green;">Pointers?</mark>

1. **Safety**: Prevents accidental use of uninitialized pointers, which can lead to undefined behavior or program crashes.
2. **Error Handling**: Indicates that a function that returns a pointer failed to perform its intended task.
3. **End of Structures**: Marks the end of a data structure, like linked lists or trees.

### <mark style="color:green;">Initializing a</mark> <mark style="color:green;"></mark><mark style="color:green;">`NULL`</mark> <mark style="color:green;"></mark><mark style="color:green;">Pointer</mark>

In C, you can define a `NULL` pointer by initializing a pointer variable with the `NULL` macro, which is defined in several standard headers like `<stdio.h>`, `<stdlib.h>`, and `<stddef.h>`.

```c
#include <stdio.h>

int main() {
    int *ptr = NULL;  // A NULL pointer

    if (ptr == NULL) {
        printf("The pointer is NULL and does not point to any valid memory location.\n");
    } else {
        printf("The pointer is pointing to the value: %d\n", *ptr);
    }

    return 0;
}
```

#### <mark style="color:orange;">Caution</mark>

* **Dereferencing a `NULL` Pointer**: Attempting to dereference (access the value pointed by) a `NULL` pointer will lead to undefined behavior, often resulting in a segmentation fault or program crash.
* **Checking for `NULL`**: Always check if a pointer is `NULL` before dereferencing it, especially if there is a possibility that it might not point to a valid memory location.

#### <mark style="color:orange;">Example</mark>

Suppose we have a function that dynamically allocates memory and returns a pointer to it. Using a `NULL` pointer is a good practice to handle situations where memory allocation might fail.

```c
#include <stdio.h>
#include <stdlib.h>

int* allocateArray(int size) {
    int* arr = (int*) malloc(size * sizeof(int));

    if (arr == NULL) {
        printf("Memory allocation failed.\n");
        return NULL;
    }

    // Initialize array elements for the sake of this example
    for (int i = 0; i < size; ++i) {
        arr[i] = i;
    }

    return arr;
}

int main() {
    int size = 10;
    int *myArray = allocateArray(size);

    if (myArray != NULL) {
        printf("Array elements: ");
        for (int i = 0; i < size; ++i) {
            printf("%d ", myArray[i]);
        }
        printf("\n");
    } else {
        printf("Failed to allocate memory for the array.\n");
    }

    // Free the allocated memory
    free(myArray);

    return 0;
}
```

In the above example,&#x20;

* The `malloc` function is used for dynamic memory allocation. If `malloc` fails (e.g., due to insufficient memory), it returns `NULL`. The function checks if `arr` is `NULL` to determine if memory allocation was successful. If not, it prints an error message and returns `NULL`.&#x20;
* Checking for a `NULL` pointer after calling `malloc` (or similar functions like `calloc` and `realloc`) is crucial for robust error handling in dynamic memory allocation.
* Always free dynamically allocated memory to prevent memory leaks.
* The check for `NULL` before using the returned pointer in `main` ensures that the program does not attempt to dereference a `NULL` pointer, which would lead to undefined behavior.

## <mark style="color:yellow;">Pointer Arithmetic</mark>

Pointer arithmetic in C involves operations on pointer values. Unlike regular arithmetic, pointer arithmetic is performed with respect to the data type to which the pointer points. Here's a brief summary:

### <mark style="color:green;">Basic Concepts</mark>

1. **Type-Specific Scaling**:
   * When you increment or decrement a pointer, it moves by the number of bytes of its data type. For example, <mark style="color:orange;">an</mark> <mark style="color:orange;"></mark><mark style="color:orange;">`int *`</mark> <mark style="color:orange;"></mark><mark style="color:orange;">moves by</mark> <mark style="color:orange;"></mark><mark style="color:orange;">`sizeof(int)`</mark> <mark style="color:orange;"></mark><mark style="color:orange;">bytes with each increment</mark>.
2. **Pointer Increment and Decrement**:
   * `ptr++` or `++ptr`: Moves the pointer to the next memory location for its type.
   * `ptr--` or `--ptr`: Moves the pointer to the previous memory location for its type.
3. **Pointer Addition and Subtraction**:
   * `ptr + n`: Moves the pointer forward by `n` elements.
   * `ptr - n`: Moves the pointer backward by `n` elements.
4. **Difference Between Two Pointers**:
   * `ptr2 - ptr1`: Computes the number of elements between two pointers (of the same type).

#### <mark style="color:orange;">Example</mark>

An example demonstrating pointer arithmetic in C. This example will use an array of integers and a pointer to traverse (ravel across or through) the array.

```c
#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50}; // An array of integers
    int *ptr; // Pointer to an integer

    ptr = arr; // Point to the first element of the array

    printf("Using pointer arithmetic:\n");

    // Print each element of the array using pointer arithmetic
    for(int i = 0; i < 5; i++) {
        printf("Element %d: %d\n", i, *(ptr + i));
    }

    // Example of pointer increment
    ptr++; // Now ptr points to arr[1]
    printf("\nAfter ptr++: *ptr = %d\n", *ptr);

    // Example of pointer addition
    int *ptr2 = ptr + 3; // Pointing to ptr[4], which is arr[1+3]
    printf("After ptr + 3: *ptr2 = %d\n", *ptr2);

    // Example of pointer difference
    printf("Difference between ptr2 and ptr: %ld\n", ptr2 - ptr);
    
    printf("%p, %p\n",ptr,ptr+2);

    return 0;
}
```

Example of output

```
Using pointer arithmetic:
Element 0: 10
Element 1: 20
Element 2: 30
Element 3: 40
Element 4: 50

After ptr++: *ptr = 20
After ptr + 3: *ptr2 = 50
Difference between ptr2 and ptr: 3
0x7ffc405d9474, 0x7ffc405d947c
```

Reminder: Hexadecimal number system is a type of number system, that has a base value equal to 16. Hexadecimal numbers are represented by only 16 symbols. These symbols or values are 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E and F.

<figure><img src="/files/jnulKImrZv5INrvR27FC" alt=""><figcaption><p>Martian hexadecimal scene.</p></figcaption></figure>

## <mark style="color:yellow;">Classwork - Week 6</mark>

### <mark style="color:green;">Part 1: Pointers and Pass-by-Reference</mark>

<mark style="color:orange;">**Swapping Two Numbers**</mark>

* Write a function `void swap(int *x, int *y)` that swaps the values of two integers.
* In your `main` function, declare two integers, initialize them, and call `swap` using their addresses.
* Print the values before and after the swap to verify the function works.

***

### <mark style="color:green;">Part 2: Arrays and Pointer Arithmetic</mark>

<mark style="color:orange;">**Array Sum Using Pointers**</mark>

* Create an `int` array and initialize it with some values.
* Write a function `int arraySum(int *arr, int size)` that returns the sum of the array elements. <mark style="color:orange;">Use pointer arithmetic to navigate the array</mark>.
* In `main`, call this function and print the result.

***

### <mark style="color:green;">Part 3: Null Pointers</mark>

<mark style="color:orange;">**Null Pointer Check**</mark>

* Write a function `void printValue(int *ptr)` that prints the value pointed to by `ptr`. The function should first check if `ptr` is not a null pointer before attempting to print.
* In `main`, create an `int` pointer, initialize it to `NULL`, and then call `printValue` with it.
* Afterward, assign a valid address to the pointer and call `printValue` again.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://comphyslab-ay2023.phys.sc.chula.ac.th/week-6-pointer-1.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
