Pointers
TN
Concept of memory address
• Pointers:
Understanding Memory Addresses - The Basics of C ...A memory address is
a unique identifier for a specific location in a computer's memory where data
is stored. It's like a street address for data, allowing the CPU to find and
access specific pieces of information. These addresses are typically
represented as numerical values, often in hexadecimal format.
Here's a more detailed explanation:
Purpose:
Memory addresses enable the CPU to efficiently store and retrieve data by
providing a way to locate specific memory locations.
Representation:
Memory addresses are usually represented as binary numbers, but they are
often displayed in a more human-readable format, such as hexadecimal (base-
16).
Continue..
• Data Storage:
• Each memory address corresponds to a specific storage location (e.g.,
a byte) in the computer's RAM (Random Access Memory).
• Addressing:
• When the CPU needs to access data, it sends the corresponding
memory address to the memory controller, which then retrieves the
data from that location.
• Example:
• If a variable is stored at memory address 0x1000, the CPU can use this
address to retrieve the value associated with that variable.
• Importance:
• Memory addresses are crucial for the proper functioning of a
computer, enabling the CPU to manage and manipulate data
effectively.
Declaring and using pointers
• Declaring Pointers
• Pointers are variables that store memory addresses of other variables. To
declare a pointer, the syntax is:
• data_type *pointer_name;
• Here, data_type specifies the type of data the pointer will point to (e.g., int,
float, char, or a custom struct). The asterisk * signifies that the variable
being declared is a pointer.
• Examples:
• int *ptr_int; // Declares a pointer to an integer
• float *ptr_float; // Declares a pointer to a float
• char *ptr_char; // Declares a pointer to a character
Continue..
• Using Pointers
• 1. Initializing Pointers:
• To make a pointer point to a specific variable, its address must be assigned to the pointer using the
address-of operator (&).
• int num = 10;
• int *ptr_num = # // ptr_num now holds the memory address of num
• 2. Dereferencing Pointers:
• To access the value stored at the memory address pointed to by a pointer, the dereference operator (*) is
used.
• int value_at_address = *ptr_num; // value_at_address will be 10
• 3. Modifying Values through Pointers:
• The value of the variable pointed to can be changed by using the dereference operator on the left side of
an assignment.
• *ptr_num = 20; // The value of 'num' is now 20
Example:
& and * operators
• In C programming, the & (ampersand) and * (asterisk) operators are
fundamental to working with pointers and memory addresses. They
serve distinct, complementary purposes:
• & (Address-of Operator):
• This is a unary operator that returns the memory address of its
operand.
• When applied to a variable, it provides the location in memory where
that variable's value is stored.
• Example: int x = 10; int *ptr = &x; Here, &x gives the memory
address of x, and this address is then stored in the pointer variable ptr.
Continue..
• * (Dereference Operator / Value-at-Address Operator):
• This is also a unary operator, but it operates on a pointer variable.
• It retrieves the value stored at the memory address pointed to by the pointer.
• Example: int x = 10; int *ptr = &x; int value = *ptr; Here, *ptr accesses the
value at the address stored in ptr (which is the address of x), and that value
(10) is then assigned to value.
• In summary:
• & is used to get the address of a variable.
• * is used to access the value at a given memory address (pointed to by a
pointer).
• Note: The * symbol also serves as the multiplication operator when used as
a binary operator (e.g., a * b). However, its meaning as a pointer operator is
determined by its context as a unary operator applied to a pointer.
Call by value vs Call by Reference
• Functions can be invoked in two ways: Call by Value or Call by
Reference. These two ways are generally differentiated by the type of
values passed to them as parameters.
• Call By Value in C
• In call by value method of parameter passing, the values of actual
parameters are copied to the function’s formal parameters.
• There are two copies of parameters stored in different memory
locations.
• One is the original copy and the other is the function copy.
• Any changes made inside functions are not reflected in the actual
parameters of the caller.
Example:
Continue..
• Call by Reference in C
• In call by reference method of parameter passing, the address of the
actual parameters is passed to the function as the formal parameters. In
C, we use pointers to achieve call-by-reference.
• Both the actual and formal parameters refer to the same locations.
• Any changes made inside the function are actually reflected in the
actual parameters of the caller.
Example:
Pointers and arrays
• Relationship and Key Differences:
• Nature:
• An array is a data structure holding multiple values, while a pointer is a variable holding a single
memory address.
• Memory Allocation:
• Arrays are typically allocated at compile time, while pointers can be used for dynamic memory
allocation at runtime.
• Mutability:
• The size of an array is fixed, but pointers can be made to point to different memory locations.
• Indexing vs. Dereferencing:
• Array elements are accessed using indexing (e.g., arr[i]), while pointer-pointed values are accessed
using dereferencing (e.g., *ptr).
• Array Name as Pointer:
• In many contexts (like function arguments), an array name can decay into a pointer to its first
element. This allows pointer arithmetic to be used with arrays. For example, arr and &arr[0] are
equivalent in C, and *(arr + i) can be used to access arr[i].
Continue..
• Arrays of Pointers:
• It is possible to create an array where each element is a pointer,
allowing the array to hold addresses of different variables or data
structures.
• In essence, while arrays provide a structured way to store
homogeneous data, pointers offer a powerful mechanism for direct
memory manipulation and dynamic memory management, often
working in conjunction with arrays to achieve more flexible and
efficient data handling.
Continue..
• A pointer to an array is a pointer that points to the whole array instead
of the first element of the array. It considers the whole array as a single
unit instead of it being a collection of given elements.
In the program, we have a
pointer ptr that points to
the 0th element of the
array. Similarly, we can
also declare a pointer that
can point to whole array
instead of only one
element of the array. This
pointer is useful when
talking about
multidimensional arrays.
Access Array Using Array Pointer
• Syntax of Array Pointer:
• type(*ptr)[size];
• where,
• type: Type of data that the array holds.
• ptr: Name of the pointer variable.
• size: Size of the array to which the pointer will point.
Example:
Find the Size of Array Passed to a Function
• Normally, it is impossible to find the size of array inside a function,
but if we pass the pointer to an array, the it is possible.
Pointers with strings
• Pointers are frequently used with strings in C/C++ to manage and
manipulate character sequences efficiently. A string in C/C++ is
essentially a null-terminated array of characters. Pointers provide a
flexible way to interact with these character arrays.
• 1. Representing Strings with Pointers:
• A char pointer can point to the first character of a string. For example:
• char *str_ptr = "Hello";
• Here, str_ptr stores the memory address of the first character ('H') of
the string literal "Hello". This string literal is typically stored in a read-
only memory segment.
Continue..
• 2. Accessing Characters:
• Once a pointer points to a string, individual characters can be accessed using
pointer arithmetic or array-like indexing:
• char *str_ptr = "World";
• printf("%c\n", *str_ptr); // Prints 'W'
• printf("%c\n", *(str_ptr + 1)); // Prints 'o'
• printf("%c\n", str_ptr[2]); // Prints 'r'
• 3. Arrays of Pointers to Strings:
• This is a common and efficient way to store multiple strings of varying lengths.
Instead of a 2D character array (which can waste memory if strings are not
uniform in length), an array of char pointers can be used:
• char *names[] = {"Alice", "Bob", "Charlie"};
• Here, names[0] points to "Alice", names[1] points to "Bob", and so on. Each
pointer in the array stores the starting address of a different string literal.
Continue..
• 4. String Manipulation with Pointers:
• Pointers are fundamental to many string manipulation functions in C's
standard library (e.g., strcpy, strlen, strcat). These functions often take char
pointers as arguments to operate directly on the memory locations of the
strings.
• Important Considerations:
• Modifying String Literals:
• When a char pointer points to a string literal (e.g., char *str = "literal";),
attempting to modify the characters through the pointer results in undefined
behavior because string literals are typically stored in read-only memory.
• Modifying Character Arrays:
• If a char pointer points to a modifiable character array (e.g., char arr[] =
"mutable";), then the characters can be safely modified through the pointer.
• Null Termination:
• Strings in C/C++ are terminated by a null character (\0). Pointers and string
functions rely on this null terminator to identify the end of the string.
Example..
Pointers to pointers
• A "pointer to a pointer," also known as a "double pointer" or "multiple
indirection," is a variable that stores the memory address of another
pointer. This second pointer, in turn, stores the memory address of a
variable containing the actual data.
• How it works:
• Variable: An ordinary variable holds a value (e.g., int var = 10;).
• Pointer: A pointer variable holds the memory address of an ordinary
variable (e.g., int *ptr_to_var = &var;).
• Pointer to a Pointer: A pointer to a pointer variable holds the memory
address of another pointer variable (e.g., int **ptr_to_ptr =
&ptr_to_var;).
Continue..
Dynamic memory allocation
• Dynamic memory allocation in C is the process of managing memory
during the program's execution (runtime) rather than at compile time. This
allows for greater flexibility in handling data structures and variables whose
size or lifetime is not known beforehand.
• Key characteristics of dynamic memory allocation in C:
• Heap-based:
• Dynamically allocated memory resides in a region of memory called the
"heap," which is a flexible pool of available memory that can expand or
shrink as needed.
• Runtime allocation and deallocation:
• Memory is requested and released by the program as it runs, unlike static
memory allocation where variable sizes are fixed at compile time.
• Programmer control:
• The programmer explicitly manages the allocation and deallocation of
memory using specific library functions.
Continue..
• Functions for dynamic memory allocation in C (found in <stdlib.h>):
• malloc():
• Allocates a block of memory of a specified size in bytes and returns a pointer to
the first byte of the allocated block. The allocated memory is not initialized and
contains garbage values.
• calloc():
• Allocates a block of memory for an array of elements, initializing all allocated
bytes to zero. It takes the number of elements and the size of each element as
arguments.
• realloc():
• Resizes a previously allocated memory block. It can either expand or shrink the
block and returns a pointer to the new block. If the original block cannot be
resized in place, a new block is allocated, and the contents are copied.
• free():
• Deallocates a previously allocated memory block, returning it to the system for
reuse. Failing to free() allocated memory can lead to memory leaks.
Advantages of dynamic memory allocation:
• Flexibility:
• Allows for creation of data structures and variables whose size can
vary during program execution.
• Efficient memory usage:
• Memory is allocated only when needed and can be released when no
longer required, optimizing memory consumption.
• Handling of large data:
• Enables programs to work with large datasets that might exceed the
limits of stack memory.
Malloc() Example
• Assume that we want to create an array to store 5 integers. Since the
size of int is 4 bytes, we need 5 * 4 bytes = 20 bytes of memory. This
can be done as shown:
Calloc() Example
• We can take the example of malloc() and try to do it with calloc()
function.
free() Example:
realloc() Example:
• Suppose we initially allocate memory for 5 integers but later need to
expand the array to hold 10 integers. We can use realloc() to resize the
memory block:
Command-line arguments
• Command-line arguments in C provide a mechanism to pass information to a program at
the time of its execution via the command line interface. This allows for dynamic input
and control of program behavior without requiring modifications to the source code or
interactive input during runtime.
• Mechanism:
• C programs handle command-line arguments through the main() function, which can be
defined with two specific parameters:
• int main(int argc, char *argv[])
• argc (Argument Count):
• This integer variable stores the total number of command-line arguments, including the
program's name itself.
• argv (Argument Vector):
• This is an array of character pointers (char *argv[]). Each element of this array points to a
string representing one of the command-line arguments.
• argv[0] always points to the name of the executable program.
• argv[1] points to the first argument provided after the program name.
• Subsequent elements (argv[2], argv[3], etc.) point to the subsequent arguments.
Continue..
• Syntax
• int main(int argc, char *argv[]) { /* ... */ }
• or
• int main(int argc, char **argv) { /* ... */ }
Example: