指针

指针是一种数据类型,它占用内存空间,存储着一个内存地址。这篇笔记我们介绍C语言中指针的用法。

基本概念

把一个变量所在的内存单元的地址保存在另外一个内存单元中,保存地址的这个内存单元称为指针,通过指针和间接寻址访问变量,这种指针在C语言中可以用一个指针类型的变量表示,例如某程序中定义了以下全局变量。

int i;
int *pi = &i;
char c;
char *pc = &c;
  • *号是指针间接寻址运算符
  • &是取地址运算符

用一个指针给另一个指针赋值时要注意,两个指针必须是同一类型的,但是可以先强制类型转换然后赋值,例如把char*赋值给int*。为避免出现野指针,在定义指针变量时就应该给它明确的初值,或者把它初始化为NULL。NULL是一种特殊的指针值,表示不指向任何内存,对值为NULL的指针解引用的不合法的。

void*指针

在编程时经常需要一种通用指针,可以转换为任意其它类型的指针,任意其它类型的指针也可以转换为通用指针。void*指针与其它类型的指针之间可以隐式转换,而不必用类型转换运算符。

void func(void *pv)
{
    /* *pv = 'A' is illegal */
    char *pchar = pv;
    *pchar = 'A';
}
int main(void)
{
    char c;
    func(&c);
    printf("%c\n", c);
    // ...
}

指针做参数和返回值

#include <stdio.h>
int *swap(int *px, int *py)
{
    int temp;
    temp = *px;
    *px = *py;
    *py = temp;
    return px;
}
int main(void)
{
    int i = 10, j = 20;
    int *p = swap(&i, &j);
    printf("now i=%d j=%d *p=%d\n", i, j, *p);
    return 0;
}

指针和数组

数组做右值自动转换成指针,指针可以加减操作。以下三种写法等价:

void func(int a[10]) {}
void func(int *a) {}
void func(int a[]) {}

注:参数写成指针形式还是数组形式对编译器来说没区别,都表示这个参数是指针,之所以规定两种形式是为了给读代码的人提供有用的信息,如果这个参数指向一个元素,通常写成指针的形式,如果这个参数指向一串元素中的首元素,则经常写成数组的形式。

const限定符

const限定符可以用如下方式理解:

//a指向const int,a指向的内存单元不能改写,a可以改写
const int *a;
int const *a;

//a是指向int的const指针,*a可以改写,a不能改写
int * const a;

//a是指向const int的const指针,*a a 都不能改写
int const * const a;

指向非const变量的指针或者非const变量的地址可以传给指向const变量的指针,编译器可以做隐式类型转换,例如:

char c = 'a';
const char *pc = &c;

但是,指向const变量的指针或者const变量的地址不可以传给指向非const变量的指针,以免透过后者意外改写了前者所指向的内存单元,例如对下面的代码编译器会报警告:

const char c = 'a';
char *pc = &c;

即使不用const限定符也能写出功能正确的程序,但良好的编程习惯应该尽可能多地使用const,因为:

  • 可读性强
  • 编译期能提前发现一些错误
  • 便于编译器优化

字符串

字符串做右值和数组一样自动转换成指针。但要尤其注意的是,字符串字面值是不能改写的,如果把字符串传给一个指针,指针又改写了某些值,编译正常,但运行时报错。

const char *p = "abcd";
const char str1[5] = "abcd";
char str2[5] = "abcd";

指针和结构体

使用->可以访问结构体指针成员,(*p).c等价于p->c

#include <stdio.h>

struct complex_struct
{
    double x, y;
};

int main(void)
{
    struct complex_struct cs = {1, 2};
    struct complex_struct *csp = &cs;
    printf("%f\n", csp->x);

    return 0;
}

函数类型和函数指针

在C语言中,函数也是一种类型,可以定义指向函数的指针。我们知道,指针变量的内存单元存放一个地址值,而函数指针存放的就是函数的入口地址(位于.text段)。

#include <stdio.h>
void say_hello(const char *str)
{
    printf("Hello %s\n", str);
}
int main(void)
{
    void (*f)(const char *) = say_hello;
    f("Guys");
    return 0;
}

void (*f)(const char *)的解释:这个写法声明了一个变量ff首先跟*号结合在一起,因此是一个指针。(*f)外面是一个函数原型的格式,参数是const char *,返回值是void,所以变量f是指向这种函数的指针。函数名做右值自动转换成函数指针。也可以写成void (*f)(const char *) = &say_hello;

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap