指针专题
在 C 中,指针概念一直处于不佳而或缺的地位,本文就指针这一主题,记录下C语言在指针编程中的小细节。
文章目录
- 指针专题
- 场景一
- 解
- 场景二
- 解
- 场景三
- 解
- 场景四
- 解
- 场景五
- 解
- 场景六
- 解
- 场景七
- 解
场景一
∗ p + + *p++ ∗p++ 自增的是 p p p 还是 p p p 所指的变量?
解
后缀 ++ 和 – 操作符优先于前缀单目操作符,故而 ∗ p + + *p++ ∗p++ 和 ∗ ( p + + ) *(p++) ∗(p++) 等价,表示自增 p p p 并返回自增前所指向的值。
与之对应,要自增 p p p 所指的值,则使用括号调整先后,即: ( ∗ p ) + + (*p)++ (∗p)++ 。
若赋值和自增顺序没有严格要求,也可使用 + + ∗ p ++*p ++∗p 。
场景二
现有一个函数,其功能是初始化一个整型指针:
void f(int* t) {
static int d = 5;
t = &d;
}
但当进行如下的调用时,指针并没有指向目标地址,即变量 d d d 所在地址:
int main() {
int* ip;
f(ip);
printf("%d\n", *ip);
return 0;
}
解
在 C 中,参数是通过值传递的,函数仅修改了传入的指针副本。可以通过传入指针的地址,或是由函数返回指针副本。
// 参数传入的是一个指针副本 —— 一份隐性的同名指针拷贝
// 方法一 —— 返回指针副本
int* f(int* ip) {
static int dum = 5;
ip = &dum;
printf("%d\n", *ip);
return ip;
}
int main() {
int* ip;
f(ip);
printf("%d\n", *ip); // 原地址存储值
printf("%d\n", *f(ip)); // 返回新地址的目标值
return 0;
}
// 方法二 —— 传入指针的地址
void f(int** ip) {
static int dum = 5;
*ip = &dum;
}
int main() {
int* ip;
f(&ip);
printf("%d\n", *ip);
return 0;
}
场景三
能否使用 void** 指针作为参数,使得函数按引用接收“一般指针”?
解
C 中没有像其他高级语言那样真正意义上的泛型,也即是没有一般指针的类型。
虽然,void* 和其他类型相互赋值时,可以自动转换成其他类型,因此可以用作一般指针,但这种转换在 void** 上是不起作用的。
场景四
一个函数接收整型指针类型的参数,那么怎样用引用的方式传入一个常数?
解
至少没办法使用 f ( & 2 ) ; f(\&2); f(&2); 这样的方式,但在C99中,可以使用以下方式:
- “复合常量”:
- f ( ( i n t [ ] ) 5 ) ; f((int []){5}); f((int[])5);
- 定义一个临时变量,再将其地址传入函数:
- i n t t = 2 ; f ( & t ) ; int\;t = 2; f(\&t); intt=2;f(&t);
场景五
C 是否有“按引用传递”这一概念?
解
严格来说,C 总是按值传递。即使是将数组传入参数,也是一种模拟按引用传递的过程,然而 C 并无真正等同的按引用传递或 C++ 的引用参数这样的概念。
另一方面,预处理宏提供了一种 “按名称传递” 的方式。
场景六
指针调用函数在 C 中出现了不同的语法方式
解
函数总是通过指针进行调用的,即使我们以往正常定义的函数也总是隐式地退化为指针,因此:
- 函数指针名作为新的函数名
- 解析函数指针
这两种方式对于 C 都是可接受的,例如:
int add(int a, int b) { return a + b; } int main() { int (*fp)() = add; // 直接作为函数名 printf("%d\n", fp(1, 2)); // 作为函数的指针 printf("%d\n", (*fp)(1, 2)); return 0; }
场景七
如何将一个 int 类型变量转为 char* 类型?
解
这样的行为往往有三种动机:
整型转为字符串
#include <stdio.h> // sprintf() 所在头文件 int main() { char* s = (char*)malloc(sizeof(char) * 11); sprintf(s, "%d", 2233); printf("%s\n", s); return 0; }
一位整型转为字符
char ch = '9'; int ch_int = ch - '0'; // 差值
让指针指向特定地址
设置一个适当类型的指针取正确的值,使用明示的类型重置。
unsigned int * loc = (unsigned int *)0x22332233;
每一个不曾起舞的日子,都是对生命的辜负。