【C中二三事】指针专题

指针专题

在 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;
}

【C中二三事】指针专题_第1张图片

场景三

​ 能否使用 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  // 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;
      








每一个不曾起舞的日子,都是对生命的辜负。

你可能感兴趣的:(#,C程序实例,c语言,开发语言)