← Back to Index
Research & Engineering Archive

LPC 6. Pointers

By Jingnan Huang · February 20, 2025 · 4024 Words

Last Edit: 2/20/25

上一章中提到的所有有关于 Function 的内容都是关于一个函数的输入以及输出的,本章将讨论如何在不同函数间访问 Variables

6.1 Why Pointers ?
#

6.1.1 Communicate using return
#

bool isPerfectSquare(int x) {
  if ((int)sqrt(x) != sqrt(x)) {
    return false;
  } else {
    return true;
  }
}
bool isPerfectSquare(int x) {
    return ((int)sqrt(x) == sqrt(x));
}

Calling by Value
#

#include <stdio.h>
void simple(int);
int main(void) {
  int p = 12;
  simple(p);
  printf("The value of p is %d.\n", p);
  return 0;
}
void simple(int p) { 
  p = p / 2; 
}
-> The value of p is 12.
#include <stdio.h>
int simple(int);
int main(void) {
  int p = 12;
  p = simple(p); //传入数值
  printf("The value of p is %d.\n", p);
  return 0;
}
int simple(int p) { 
  p = p / 2; 
  return p; //函数主动返回数值
}

6.1.2. Limitation of return
#

#include <stdio.h>
void swap(int, int);
int main(void) {
  int a = 9, b = 13;
  printf("Before swapping\nValue of a: %d\nValue 
of b: %d\n", a, b);
  swap(a, b);
  printf("After swapping\nValue of a: %d\nValue 
of b: %d\n", a, b);
  return 0;
}
void swap(int x, int y) {
  int temp = x;
  x = y;
  y = temp;
}

6.2 What are Pointers ?
#

Pointers 指针是存储变量地址的变量

#include <stdio.h>
int main(void) {
    int x = 7;   // x 是一个 int 变量
    int *p;      // p 是一个指向 int 的指针变量
    return 0;
}
#include <stdio.h>
int main(void) {
    int x = 7;      // 声明一个整型变量 x 并初始化为 7
    int *p;         // 声明一个整型指针 p
    p = &x;         // 将 x 的地址赋给指针 p
    int y;          // 声明一个整型变量 y
    y = *p;         // 将指针 p 指向的地址(x 的地址)中的值赋给 y
    return 0;       // 函数返回 0
}

需要注意的是赋值之后 x 的值的改变将不再影响到 y

#include <stdio.h>
int main(void) {
  int x = 7;
  int *p;
  p = &x;
  int y;
  y = *p;
  printf("Address of x: %p\n Value of x: %d\n", 
&x, x);
  printf("Address of p: %p\n Value of p: %p\n", 
&p, p);
  printf("Address of y: %p\n Value of y: %d\n", 
&y, y);
  printf("Value stored in address %p is %d\n", p
, *p);
  return 0;
}
Address of x: 0x30e2af178
Value of x: 7
Address of p: 0x30e2af170
Value of p: 0x30e2af178
Address of y: 0x30e2af16c
Value of y: 7
Value stored in address 0x30e2af178 is 7

6.3 Use Pointers to Communicate
#

#include <stdio.h>
void swap(int*, int*);
int main(void) {
  int a = 9, b = 13;
  printf("Before swapping\nValue of a: %d\nValue of b: %d\n", a, b);
  swap(&a, &b);
  printf("After swapping\nValue of a: %d\nValue of b: %d\n", a, b);
  return 0;
}
void swap(int* x, int* y) {
  int temp = *x;
  *x = *y;
  *y = temp;
}

6.3.1 Size of pointer Variable
#

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

int main(void) {
  printf("Size of pointer (int*) is %d.\n", sizeof(int*));
  printf("Size of pointer (double*) is %d.\n", sizeof(double*));
  printf("Size of pointer (bool*) is %d.\n", sizeof(bool*));
  printf("Size of pointer (char*) is %d.\n", sizeof(char*));
  return 0;
}

6.3.2 Can a pointer hold address of another pointer ?
#

变量 存储的地址 存储的值
i 45 10(整数值)
pi 46 45(即 i 的地址)
ppi 47 46(即 pi 的地址)

6.3.3. Can a function return a pointer?
#

#include <stdio.h>
double* largestValLoc(double*, double*);
double* largestValLoc(double* a, double* b) {
  double* temp;
  if (*a > *b) {
    temp = a;  // temp is double* and a is double*, so temp = a is permissible
  } else {
    temp = b;
  }
  return temp;  // temp is double*, and return type is double*
}
int main(void) {
  double x = 2.6, y = 7.3;
  double* p =
      largestValLoc(&x, &y);  // pass address of x to a, and address of y to b
  // p is (double*) and largestValLoc returns 
(double*)
  printf("Address of x: %p having value %.1lf.\n", &x, x);
  printf("Address of y: %p having value %.1lf.\n", &y, y);
  printf("Address of larger variable: %p.\n", p);
  return 0;
}

6.3.4. Initialization Vs. Declaration of a pointer variable
#

Declaration 声明
#

int x;       // 仅声明 x,x 里面的值是不确定的(垃圾值)
int *p;      // 仅声明指针 p,但 p 没有指向任何有效地址(垃圾指针)
#include <stdio.h>
int main() {
    int* p;  // 仅声明指针 p,但未初始化
    *p = 5;  // 试图通过 p 访问地址并赋值
    return 0;
}
-> warning: variable 'p' is uninitialized when used here [-Wuninitialized]
    *p = 5;
     ^

Initialization 初始化
#

int x = 5;      // 声明并初始化 x,x 现在存储 5
int *p = &x;    // 声明并初始化指针 p,使其指向 x

Null
#

int *p;  // ❌ 未初始化的指针
*p = 5;  // 可能会崩溃(指向垃圾地址)
int *p = NULL;  // ✅ 初始化为 NULL
if (p != NULL) {
    *p = 5;  // 只有当 p 指向有效地址时才执行
}

ex.
#

#include <stdio.h>
int *confuse(int *x, int *y) {
  (*y)++;
  y = x;
  *y = 10;
  return (y);
}
int main(void) {
  int a = 6, b = 7;
  int *f = &b;
  f = confuse(&a, &b);
  (*f)++;
  printf("a = %d and b = %d\n", a, b);
  return 0;
}
步骤 变量 a 变量 b 指针 f
初始化 6 7 &b
(*y)++ (b++) 6 8 &b
y = x(y 指向 a 6 8 &b
*y = 10(修改 a 10 8 &b
return y;(返回 &a,即 f = &a 10 8 &a
(*f)++a++ 11 8 &a

6.4. Rules defining scope of variables
#

6.4.1. Variables can only be used after they are declared
#

int main() {
  i = 0;
  int i;
  return 0;
}

Local Variables
#

6.4.2. Use a variable declared in a compound statement
#

#include <stdio.h>
int main() {
    int i = 0;  // 变量 i 在 main() 作用域内有效
    {  // 复合语句(新的作用域)
        int x = 5;  
        printf("Inside compound statement: x = %d.\n", x);  // ✅ 正确,x 在作用域内
    }
    // ❌ 错误:x 作用域结束,无法访问
    printf("Outside compound statement: x = %d.\n", x);  

    return 0;
}
#include <stdio.h>
int main() {
    int i = 0;
    int x;  // 声明 x 在整个 main() 内有效
    { 
        x = 5;  
        printf("Inside compound statement: x = %d.\n", x);
    }
    printf("Outside compound statement: x = %d.\n", x);  // ✅ 正确
    return 0;
}

6.4.3. External identifiers/global variables
#

#include <stdio.h>
int i = 0;  // ✅ 全局变量 i,所有函数都可以访问
void func();  // 函数声明
int main(void) {
    printf("In main: Global variable i = %d.\n", i);  // 输出 i = 0
    func();  // 调用 func()
    printf("In main after calling func: Global variable i = %d.\n", i);  // 输出 i = 5
    return 0;
}
void func() {
    printf("In func: Global variable i = %d.\n", i);  // 输出 i = 0
    i = 5;  // ✅ 修改全局变量 i
}

6.4.4. Overlapping scope
#

#include <stdio.h>
int main(void) {
    int i = 1;  // ✅ 作用域:整个 main() 函数
    printf("Outer i = %d.\n", i); // 输出 1
    {
        int i = 2;  // ✅ 作用域:仅限于这个 `{}` 块
        printf("Inner i = %d.\n", i); // 输出 2
    }
    printf("Outer i = %d.\n", i); // 输出 1
    return 0;
}

可以发现,Variable 是否会被修改取决于是否出现了多个 Declarations,对于 6.4.3 中的代码来说,全局只有一个 Declaration,即 int i = 0 ,而在 6.4.4 中存在两个 Declarations,int i = 1int i = 2,这就导致了 Cpmpound Statement 内部的修改不会影响到外部

6.5. Goldbach conjecture
#

6.5.1 Problem Statement
#

6.5.2 Divide Problem into sub-problems
#

6.5.2.1. Take input from the user
#

void getUserInput(int *number) {
  // Get user input from the keyboard
  // and validates it is even and greater than 2
  do {
    printf("Enter a number to test the Goldbach conjecture: ");
    scanf("%d", number);
  } while (*number <= 2 || *number % 2 != 0);
}
#include <stdbool.h>
#include <stdio.h>

void getUserInput(int*);

int main(void) {
    int num;
    getUserInput(&num);
    return 0;
}

void getUserInput(int *number) {
    // 获取用户输入,并验证其是否为大于 2 的偶数
    bool firstEntry = true;  // 标记是否是第一次输入

    do {
        if (firstEntry) {
            printf("Enter a number to test the Goldbach conjecture: ");
            firstEntry = false;
        } else {
            printf("Your input was invalid, please enter another even number > 2: ");
        }
        scanf("%d", number);
    } while (*number <= 2 || *number % 2 != 0);
}

6.5.2.2. Test the Goldbach
#

bool testGoldbach(int N) {
    // 测试哥德巴赫猜想
    // 如果验证成功返回 true,否则返回 false
    int x = 2, y;
    bool rejected = false;
    bool verified = false;

    while (!rejected && !verified) {
        y = N - x;

        if (isPrime(y)) {
            verified = true;  // 找到了 x + y = N 的质数对
        } else if (y < x) {
            rejected = true;  // 当 x > y 时,仍未找到符合条件的 x, y
        } else {
            nextPrimeNumber(&x);  // 递增 x 到下一个质数
        }
    }

    return verified;  // 如果找到了两个质数,则返回 true,否则返回 false
}

6.5.2.3. Get the Next Prime Number
#

void nextPrimeNumber(int *px) {
  // We will look for the numbers after *pFrist one by one 
  // until we find the next prime number
  int value = *px + 1;
  while (!isPrime(value)) {
    value += 1;
  }
  *px = value;
}

6.5.2.4. Find If a Number Is Prime or Not
#

bool isPrime(int num) {
  // check if num is prime, by checking the remainder of num / all numbers from
  // 2 to num - 1
  bool prime = true;
  if (num < 2) {
    prime = false;
  } else {
    for (int denom = 2; denom <= num - 1 && prime; denom++) {
      if (num % denom == 0) {
        prime = false;
      }
    }
  }
  return prime;
}

6.5.2.5. Print If the Conjecture Is Verified
#

完全不需要这个

void printConjResult(int number){
    //Call a function to verify the conjecture and prints the result
    bool verified = testGoldbach(number);
    if(verified){
        printf("Goldbach conjecture is verified.\n");
    }
    else{
        printf("Goldbach conjecture not verified.\n");
    }
}

6.5.3. Integrate all pieces/functions
#

int main(void){
    int number;
    getUserInput(&number);
    printConjResult(number);
    return 0;
}
-> Enter a number to test the Goldbach conjecture: **9**
Your input was invalid, please enter another number > 2: **8**
Goldbach conjecture is verified.