Understanding Pointers in C Language Correctly

✍🏼 Written on Sep 16, 2019   
❗️ Note: it has been days since this article was written, please be aware of its timeliness
🖥  Note:This post is a blog I wrote when first learning the C programming language, recovered from my old WordPress blog.

Preface

Beginners often feel confused about pointers when learning C. Below, I’ll share my understanding of them.

Clarifying a Few Questions First

The Essence of Variables

The essence of a variable is a name representing a memory address. In compiled object code, variable names don’t exist. During compilation, the compiler creates a mapping table linking variable names to their corresponding memory addresses, recording the variable’s type, name, and address.

When declaring a variable, you’re essentially requesting a segment of memory from the operating system. Assigning a value means writing data to that address.

The Nature of Variable Assignment

Declare a variable x with address 0x0001, storing the value 1. Assigning 2 to x involves the following steps:

  1. Look up variable x’s address in the mapping table, obtaining 0x0001.
  2. Store the value 2 at that address. Assignment is complete.

Pointer assignment follows the same principle.

The Three Meanings of *

  1. When declaring a function prototype, such as:
    1
    void fn(int *a)
    The *a here indicates that the function fn accepts a pointer variable (i.e., a memory address) as a parameter, with the parameter being a.
  2. In the function body, when *a appears on the left side of an equals sign, it means storing the value on the right into the memory address represented by pointer a, e.g.:
    1
    2
    3
    void fn(int *a) {
    *a = 3;
    }
  3. In the function body, when *a appears on the right side of an equals sign, it means retrieving the value stored at the memory address represented by pointer a:
    1
    2
    3
    void fn(int *a) {
    int tmp = *a;
    }

Example: A Function to Swap Two Variables’ Values

1
2
3
4
5
6
7
8
9
10
11
12
13
void swap(int *a, int *b);

int main (void) {
int x = 1;
int y = 2;
swap(&x, &y);
}

void swap(int *a, int *b) {
int tmp = *a; // 也可以写作 int * tmp = *a; 只是说明 tmp 是一个指针变量, 即存储着指针的变量;
*a = *b;
*b = tmp;
}

Explanation of the example:

  1. In main, two variables x and y are declared. Their addresses are &x and &y, storing the values 1 and 2, respectively.
  2. When encountering the swap function, note that:
    1. It declares two pointers as parameters. int *a or int *b as formal parameters indicates that they can point to values of type int, meaning the function expects two addresses pointing to int values as arguments. Here, * signifies accepting pointer variables.
  3. Executing the swap function:
    1. The formal parameter a is assigned &x, the memory address of x. Thus, the local variable a’s memory address stores x’s memory address. Similarly, formal parameter b is assigned &y, the memory address of y. (Adding * to formal parameters simply indicates they are pointer types.)
    2. Declare a local integer variable tmp. *a means:
      1. Step 1: Locate a’s memory address.
      2. Step 2: Read the value stored at a’s memory address, which is also a memory address—the address of variable x.
      3. Step 3: Return the value at a’s address, i.e., the value stored at x’s address, which is 1.
    3. _b means retrieving the value stored at the memory address held by variable b (a memory address), i.e., the value at &y, which is 2. This is then assigned to *a, meaning the value at the memory address &x (since a = &x), i.e., x’s value, which is 1. Note that within swap, the value at x’s memory address in main is modified.
    4. In the last line, tmp holds the value 1, which is assigned to *b, meaning the value at b’s memory address (originally 2) is overwritten with 1. Here, swap also modifies the value at y’s memory address in main via the pointer.

For better understanding, here’s an illustration:

交换值函数

交换值函数

- EOF -
Originally published at: Understanding Pointers in C Language Correctly - Xheldon Blog