【C】指针

指针的定义

  • 概念

    指针就是内存地址,指针变量是保存地址的变量。

  • 变量定义

    //整型指针:
    int *i_pointer = &i;//*i_pointer拿到4字节(整型)
    //字符指针:
    char *c_pointer = &c;//*c_pointer拿到1字节(字符型)
    

间接访问

  • & 是取地址运算符,它返回变量的地址。

    * 是解引用运算符,它用于指针,返回指针所指向地址的值。

  • int *i_pointer = &i;//i_pointer保存的是变量i的起始地址
    *i_pointer=10;//间接修改i的值
    

指针变量的大小

  • 系统差异

    • 64位系统:指针变量占8个字节(sizeof(i_pointer))
    • 32位系统:指针变量占4个字节(sizeof(i_pointer))
  • 取值大小(注意与上面区分)

    • sizeof(*_pointer)(等于sizeof(i))(4字节)
    • sizeof(*_pointer)(等于sizeof©)(1字节)
  • 重要特性

    • 指针变量大小固定,与被指向变量大小无关
    • 指针只存储变量的起始地址

指针的传递使用场景

这样子不会改变主函数a的值

  1. 值传递机制:它调用的是值传递,实参a的值复制给b
  2. 内存隔离:主函数main和change函数都有独立的栈空间,互不影响
#include <stdio.h>
void change(int b)
{
  b = 10;//只会影响变量b的值,对a没影响
}

int main()
{
  int a = 100;
  printf("before change\n");
  change(a);//传的是a的值
  printf("after change\n");
  printf("%d", a);//输出100
}

使用指针间接访问

  1. 地址传递:传递的是变量a的地址,而不是值

  2. 间接修改:通过*j=5访问变量i的内存空间

    #include <stdio.h>
    void change(int *b)
    {
      *b = 10;//直接修改a在内存地址的值
    }
    int main()
    {
      int a = 100;
      printf("before change\n");
      change(&a);//传的是a的内存地址
      printf("after change\n");
      printf("%d", a);//输出10
    }
    

指针的偏移

指针偏移是指针的加减运算,通过指针变量进行加或减操作实现内存地址的移动。

指针加减1时,实际偏移的长度是其基类型的大小(如int型指针偏移sizeof(int)字节)

#include <stdio.h>
void change(int *b)
{
  b[1] = 10;     // 下标直接修改
  *(b + 2) = 99; // 指针偏移
}
int main()
{
  int a[4] = {1, 3, 4, 6};
  int *p;
  p = a;
  change(p);
  for (int i = 0; i < 4; i++)
  {
    printf("%3d", *(p + i)); //*(p+i)相当于a[i]
  }
    //输出1 10 99  6
}

栈空间和堆空间

  • 栈空间:存放main函数的局部变量

  • 堆空间:通过malloc动态申请内存区域

  • 管理方式:栈由系统自动管理,堆需要手动申请(malloc)释放(free)

  • 大小确定性:栈空间大小在编译时确定不可变,堆空间可以动态改变

  • 生命周期:

    • 堆:

      函数内定义的局部变量存储在栈空间,函数执行结束后,栈空间自动释放

      (例:char c[100] = “I am print_stack func”; 存储在栈空间)

    • 通过函数malloc手动申请内存空间

      需要手动释放,否则会一直存在

      (例:char *p = (char)malloc(100); 申请100字节堆空间)

指针与malloc动态内存申请

  • 动态内存申请

    • malloc函数

      • 头文件:#include <stdlib.h>
      • 原型:void* malloc(size_t size)
      • 参数:整型变量,申请字节数
      • 返回值:无类型指针(void*),要强行转换成具体类型
    • 案例

      需要注意必须将void转换为具体指针类型

      若存储字符串需包含结束符’\0’的空间

      free时必须使用malloc返回的原始指针值,忘记free会导致内存泄漏

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      int main()
      {
        int size; // 记录申请空间大小
        scanf("%d", &size);
        char *p;
        p = (char *)malloc(size);
        strcpy(p, "malloc success"); // 使用分配的空间
        puts(p);
        free(p); // 释放时必须使用原始地址
        return 0;
      }
      

      (考研重点:链表、树等数据结构都需要使用堆空间)

注意事项

  • 推荐使用int *a,而不是用int* a
    (例:int* a,b,c 很多人会很自然的以为三个都是整型指针,但其实只有a是整型指针,其他两个只是普通的整型变量)

  • 禁止跨类型指针赋值

    float a;
    int *p;
    p = &a;//毫无意义且会报错
    
  • “&” 和 "*"的优先级一样,计算*&a,要按自右向左方向结合,但一般不会结合去使用

    1. 先计算 &a,得到变量 a 的地址。

    2. 然后对 &a 的结果(即地址)使用 * 运算符,即解引用该地址,得到该地址存储的值,也就是 a 的值。

    因此*&a等于a

  • 内存释放

    1. free时必须传入malloc返回的原始地址,不能是偏移后的地址
    2. free参数位void*,任何指针可以自动转换,直接传入
    3. 若free时地址不匹配,会导致进程崩溃
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值