C language pointer: in-depth understanding and application

C language pointer: in-depth understanding and application

As one of the core concepts of C language, pointer is of great significance to programmers who learn C language. This article will introduce in detail the basic concepts of C language pointers, operators, the relationship between pointers and arrays, function pointers, and common application scenarios of pointers. By reading this article, you will have a deeper understanding of C language pointers and be able to flexibly apply them in actual programming.
insert image description here

1. Basic concepts of pointers

A pointer is a variable that is used to store the memory address of another variable. We all know that computer memory is organized in bytes, and each byte has a unique address. When we declare a variable, the system will allocate a memory space for this variable and give the address of this space. Through the pointer, we can directly access this address, so as to realize the operation on the variable value.

1.1 Declaration of pointers

In C language, we use *symbols to declare a pointer variable. The declaration format of a pointer variable is as follows:

type *pointer_name;

Wherein, typeindicates the data type of the variable pointed to by the pointer, and pointer_nameindicates the name of the pointer variable. For example, the following code declares a pointer to an integer variable:

int *p;

It should be noted that the data type of the pointer variable is closely related to the data type of the pointed variable. The data type of the pointer variable determines the step size required for the pointer operation and the return value type of the dereference operation. Therefore, when declaring a pointer variable, ensure that the data type of the pointer matches the data type of the variable it points to.

1.2 Pointer initialization

After the pointer variable is declared, it needs to be initialized, that is, to assign a valid memory address to the pointer variable. Pointer initialization can be done in the following three ways:

  • &Obtain the address of the variable through the address operator and assign it to the pointer;
  • Assign a value to a new pointer variable through an existing pointer variable;
  • Allocate memory space for pointers through dynamic memory allocation functions (such as malloc, etc.).calloc

The following code example demonstrates how to initialize pointers:

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

int main()
{
    
    
    int a = 10;
    int *p1 = &a; // 通过取址操作符获取变量a的地址并赋值给指针p1
    int *p2 = p1; // 通过已有指针变量p1对新指针变量p2进行赋值

    int *p3 = (int *)malloc(sizeof(int)); // 通过动态内存分配函数为指针p3分配内存空间
    *p3 = 20;
    printf("%d\n", *p3);
    free(p3); // 释放动态分配的内存空间

    return 0;
}

1.3 Null pointers and wild pointers

  • Null pointer (NULL Pointer): If a pointer variable is not initialized, or is explicitly assigned NULL, then this pointer is called a "null pointer". A null pointer does not point to any valid memory address, and dereferencing a null pointer results in undefined behavior. In actual programming, we should try to avoid using uninitialized pointers, so as not to cause program errors.
int *p = NULL;
  • Wild Pointer (Wild Pointer): If a pointer variable points to a memory address that has been released, or points to an invalid memory address, then this pointer is called a "wild pointer". Wild pointers also have risks such as accessing out of bounds and destroying memory. In actual programming, we should pay attention to assigning pointers that are no longer used in time NULLto avoid wild pointers.

2. Pointer operators

C language provides two pointer operators: address operator (&) and dereference operator (*).

2.1 The address operator (&)

The address-of operator &is used to obtain the memory address of a variable. For example:

int a = 10;
int *p = &a;

In this example, we use the address-of operator &to get athe address of a variable and assign it to a pointer variable p.

2.2 Dereference operator (*)

The dereference operator *is used to obtain the value stored in the memory address pointed to by the pointer. For example:

int a = 10;
int *p = &a;
int b = *p;

In this example, we use the dereference operator *to get pthe value stored in the memory address pointed to by the pointer variable (i.e. athe value of the variable) and assign it to the variable b.

It should be noted that the dereference operation can only be performed on the pointer that has been initialized, otherwise it may cause undefined behavior.

3. Pointers and arrays

There is a close relationship between pointers and arrays. In C language, the array name is actually a pointer constant, which represents the address of the first element of the array. Therefore, we can use pointers to manipulate elements in the array.

3.1 Using pointers to access array elements

Suppose we have an array of integers arr, and each element in the array can be accessed through a pointer. The following code example demonstrates how to use pointers to access array elements:

#include<stdio.h>

int main()
{
    
    
    int arr[] = {
    
    1, 2, 3, 4, 5};
    int *p = arr; // 数组名表示数组首元素的地址

    for(int i = 0; i < 5; i++)
    {
    
    
        printf("%d ", *(p + i));
    }
    printf("\n");

    return 0;
}

In this example, we arrassign the address of the first element of the array to the pointer variable p. *(p + i)Each element in the array is then accessed through an expression . It should be noted that the addition operation here is based on the pointer addition operation, which p + imeans that the pointer pmoves backward by ithe position of the integer element. Therefore, the th element *(p + i)in the array can be accessed correctly .i

3.2 Pointers represent two-dimensional arrays

For two-dimensional arrays, we can use pointers of pointers to represent them. The following code example demonstrates how to represent a two-dimensional array using a pointer of pointers:

#include<stdio.h>

int main()
{
    
    
    int arr[][3] = {
    
    {
    
    1, 2, 3}, {
    
    4, 5, 6}, {
    
    7, 8, 9}};
    int (*p)[3] = arr; // 指向整型一维数组的指针

    for(int i = 0; i < 3; i++)
    {
    
    
        for(int j = 0; j < 3; j++)
        {
    
    
            printf("%d ", *(*(p + i) + j));
        }
        printf("\n");
    }

    return 0}

In this example, we declare a two-dimensional array arrand assign the address of its first element to a pointer variable p. The type of the pointer variable here pis int (*)[3], indicating that it is a pointer to an integer one-dimensional array. We can *(*(p + i) + j)access each element in a two-dimensional array through expressions.

It should be noted that the addition operation here is also a pointer-based addition operation. p + iIndicates that the pointer pis moved backward by ithe position of the integer one-dimensional array, *(p + i)indicating that it points to ithe first element of the first integer one-dimensional array. Therefore, the element at row and column in *(*(p + i) + j)the two-dimensional array can be accessed correctly .ij

4. Function pointers

A function pointer is a special pointer that is used to store the address of a function. Through function pointers, we can implement indirect calls to functions, thereby improving the flexibility and scalability of the program.

4.1 Declaring function pointers

In C language, we use the following format to declare a function pointer:

return_type (*pointer_name)(parameter_types);

Wherein, return_typeindicates the type of the function return value, pointer_nameindicates the name of the function pointer, and parameter_typesindicates the type of the function parameter. For example, the following code declares a pointer intto inta function that returns two types:

int (*func_ptr)(int, int);

4.2 Initialize function pointer

The method of initializing the function pointer is very simple, you only need to assign the address of a function to the function pointer. For example, the following code addassigns the address of a function to a function pointer func_ptr:

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

int main()
{
    
    
    int (*func_ptr)(int, int) = add;
    return 0;
}

It should be noted that when assigning a function address, there is no need to use the address operator &, and the function address can be expressed directly by using the function name.

4.3 Calling a function using a function pointer

Through function pointers, we can implement indirect calls to functions. The following code example demonstrates how to call a function using a function pointer:

#include<stdio.h>

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

int main()
{
    
    
    int (*func_ptr)(int, int) = add;
    int result = func_ptr(1, 2); // 间接调用add函数
    printf("1 + 2 = %d\n", result);

    return 0;
}

In this example, we func_ptr(1, 2)implemented addan indirect call to a function through an expression, resulting in the sum of two integers.

5. Common application scenarios of pointers

Pointers have many application scenarios in C language programming. Here are a few common application scenarios:

  1. Dynamic memory allocation: Through functions such as malloc, callocand so on, we can dynamically allocate memory space for pointers, thereby realizing the dynamic construction and modification of data structures (such as linked lists, trees, etc.).

  2. Function parameter transfer: Through pointers, we can realize the address transfer of variables, so as to realize the direct modification of external variables in the function.

  3. String handling: In the C language, a string is actually an array of characters. Through pointers, we can easily traverse and manipulate strings.

  4. Advanced functional programming: Through function pointers, we can implement indirect calls to functions, thereby improving the flexibility and scalability of the program. For example, in a sorting algorithm, we can use a function pointer as a parameter of a comparison function to sort different types of data.

  5. The relationship between arrays and pointers: In C language, the array name is actually a pointer to the first element of the array. Through pointers, we can easily traverse and manipulate arrays. For example, the following code iterates over an array of integers using pointers:

#include <stdio.h>

int main()
{
    
    
    int arr[] = {
    
    1, 2, 3, 4, 5};
    int *p = arr; // 数组名是指向首元素的指针

    for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
    {
    
    
        printf("%d ", *(p + i)); // 通过指针访问数组元素
    }
    printf("\n");

    return 0;
}
  1. Structures and pointers: Pointers can also point to data of structure type. Through the structure pointer, we can easily access and modify the structure members. The following code shows how to use a struct pointer to access struct members:
#include <stdio.h>

typedef struct
{
    
    
    int x;
    int y;
} Point;

int main()
{
    
    
    Point pt = {
    
    1, 2};
    Point *p = &pt; // 指向结构体的指针

    printf("x = %d, y = %d\n", p->x, p->y); // 使用->运算符访问结构体成员

    return 0;
}
  1. Array of pointers: An array of pointers is an array in which each element is a pointer. An array of pointers can be used to store multiple pointers to achieve indirect access to multiple data. The following code shows how to use an array of pointers:
#include <stdio.h>

int main()
{
    
    
    int a = 1, b = 2, c = 3;
    int *arr[3] = {
    
    &a, &b, &c}; // 指针数组

    for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
    {
    
    
        printf("%d ", *arr[i]); // 通过指针数组访问数据
    }
    printf("\n");

    return 0;
}
  1. Pointer to Pointer: In C, a pointer can also point to another pointer. Pointers to pointers can be used to implement multiple levels of indirection. The following code shows how to use pointers to pointers:
#include <stdio.h>

int main()
{
    
    
    int a = 1;
    int *p1 = &a;   // 指向整型变量的指针
    int **p2 = &p1; // 指向指针的指针

    printf("%d\n", **p2); // 通过指向指针的指针访问数据

    return 0;
}
  1. Dynamic memory allocation: In C language, we can use pointers and memory allocation functions (such as malloc, calloc, and realloc) to dynamically allocate or adjust memory space. Dynamic memory allocation allows us to apply for an appropriate size of memory space as needed when the program is running, rather than fixing it at compile time. The following code shows how to use dynamic memory allocation:
#include <stdio.h>
#include <stdlib.h>

int main()
{
    
    
    int n = 5;
    int *arr = (int *)malloc(n * sizeof(int)); // 动态分配内存

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

    for (int i = 0; i < n; i++)
    {
    
    
        arr[i] = i + 1; // 初始化数组
    }

    for (int i = 0; i < n; i++)
    {
    
    
        printf("%d ", arr[i]); // 输出数组
    }
    printf("\n");

    free(arr); // 释放内存

    return 0;
}
  1. Function pointer: In C language, a pointer can also point to a function. Function pointers can be used to implement functions such as callback functions and function tables. The following code shows how to use function pointers:
#include <stdio.h>

int add(int a, int b) {
    
     return a + b; }
int sub(int a, int b) {
    
     return a - b; }
int mul(int a, int b) {
    
     return a * b; }

int main()
{
    
    
    int (*func_ptr[3])(int, int) = {
    
    add, sub, mul}; // 函数指针数组

    int a = 5, b = 3;
    for (int i = 0; i < sizeof(func_ptr) / sizeof(func_ptr[0]); i++)
    {
    
    
        printf("%d\n", func_ptr[i](a, b)); // 通过函数指针调用函数
    }

    return 0;
}
  1. Pointers and Multidimensional Arrays: Pointers can be used to access multidimensional arrays. It should be noted that for multi-dimensional arrays, you need to use pointer arrays or multi-level pointers to achieve indirect access. The following code shows how to access a two-dimensional array using pointers:
#include <stdio.h>

int main()
{
    
    
    int arr[][3] = {
    
    {
    
    1, 2, 3}, {
    
    4, 5, 6}};
    int (*p)[3] = arr; // 指向二维数组的指针

    for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
    {
    
    
        for (int j = 0; j < sizeof(arr[0]) / sizeof(arr[0][0]); j++)
        {
    
    
            printf("%d ", *(*(p + i) + j)); // 通过指针访问二维数组元素
        }
    }
    printf("\n");

    return 0;
}
  1. Pointers and Strings: Strings in C language are actually arrays of characters, so we can use pointers to manipulate strings. The following code shows how to use pointers to handle strings:
#include <stdio.h>

int main()
{
    
    
    char str[] = "Hello, world!";
    char *p = str; // 指向字符串的指针

    // 使用指针遍历字符串
    while (*p != '\0')
    {
    
    
        printf("%c", *p);
        p++;
    }
    printf("\n");

    return 0;
}
  1. Function returns pointer: Functions in C language can return pointers, but be careful not to return pointers to local variables, because local variables will be destroyed after the function returns, and such pointers are dangling pointers. The following code shows an example of a function returning a pointer:
#include <stdio.h>
#include <stdlib.h>

int *create_array(int n)
{
    
    
    int *arr = (int *)malloc(n * sizeof(int));
    if (arr == NULL)
    {
    
    
        printf("Memory allocation failed!\n");
        return NULL;
    }

    for (int i = 0; i < n; i++)
    {
    
    
        arr[i] = i + 1;
    }

    return arr;
}

int main()
{
    
    
    int n = 5;
    int *arr = create_array(n);

    if (arr != NULL)
    {
    
    
        for (int i = 0; i < n; i++)
        {
    
    
            printf("%d ", arr[i]);
        }
        printf("\n");

        free(arr); // 释放内存
    }

    return 0;
}
  1. Pointer as a function parameter: A pointer can be used as a parameter of a function, so that we can modify the data pointed to by the pointer inside the function. This approach is very useful when working with arrays, strings, and other data structures. The following code shows an example using pointers as parameters:
#include <stdio.h>

void swap(int *a, int *b)
{
    
    
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main()
{
    
    
    int x = 1, y = 2;
    printf("Before swap: x = %d, y = %d\n", x, y);

    swap(&x, &y);
    printf("After swap: x = %d, y = %d\n", x, y);

    return 0;
}
  1. Pointers and structures: Pointers can point to structures, so that we can easily access and modify structure members. The following code shows how to use pointers to manipulate structures:
#include <stdio.h>

typedef struct
{
    
    
    int x;
    int y;
} Point;

void move(Point *p, int dx, int dy)
{
    
    
    p->x += dx;
    p->y += dy;
}

int main()
{
    
    
    Point pt = {
    
    1, 2};
    printf("Before move: (%d, %d)\n", pt.x, pt.y);

    move(&pt, 3, 4);
    printf("After move: (%d, %d)\n", pt.x, pt.y);

    return 0;
}

By understanding and mastering the application of pointers in these scenarios, we can write more efficient and flexible programs, and deepen our understanding of memory management, data structures, and algorithms. In the actual programming process, proficient use of pointers is a very important skill.

Guess you like

Origin blog.csdn.net/kunhe0512/article/details/131002555