C语言指针

1. 指针的理解与定义

  • 变量的访问方式
    • 直接访问:直接使用变量名进行访问。
    • 间接访问:通过指针访问,指针存储的是变量的内存地址。
  • 内存地址与指针
    • 每个内存单元都有一个编号,称为内存地址
    • 变量的地址形象化地称为“指针”。
    • 指针变量:用于存放变量地址的变量。
  • 指针变量的定义
    • 格式:数据类型 *指针变量名 [=初始地址值];
    • 举例:int *p; 表示一个指向int类型数据的指针变量。
2. 指针的运算
  • 取址运算符(&)
    • 作用:取出指定变量在内存中的地址。
    • 举例:int num = 10; int *p = #
  • 取值运算符(*)
    • 作用:根据给定的内存地址取出该地址对应变量的值。
    • 举例:int a = 2024; int *p = &a; printf("%d\n", *p);
  • 指针的常用运算
    • 指针与整数值的加减运算:表示指针所指向的内存地址的移动。
    • 指针的自增、自减运算:指针向前或向后移动。
    • 同类指针相减运算:返回它们之间的距离(以数据单位计)。
    • 指针间的比较运算:比较内存地址的大小。
3. 野指针
  • 野指针:指针指向的位置是不可知、不正确、没有明确限制的。
  • 野指针的成因
    • 指针使用前未初始化。
    • 指针越界访问。
    • 指针指向已释放的空间。
  • 野指针的避免
    • 指针初始化。
    • 小心指针越界。
    • 避免返回局部变量的地址。
    • 指针指向空间释放后,及时置为NULL。
    • 指针使用之前检查有效性。
4. 二级指针(多重指针)
  • 二级指针:指向指针的指针。
  • 格式数据类型 **指针名;
  • 举例int a = 10; int *pa = &a; int **ppa = &pa;
5. 指针与数组
  • 一维数组与指针
    • 指针可以指向数组元素,并遍历数组。
    • 指针带下标的使用:p[i] 等价于 *(p+i)
    • &数组名 与 数组名 的区别:&数组名 是数组的地址,类型为 数组类型指针数组名 是数组首元素的地址。
  • 二维数组与指针
    • 使用数组名访问二维数组。
    • 使用指针变量访问二维数组,例如通过指针遍历二维数组元素。
  • 指针数组
    • 数组指针 vs 指针数组
      • 数组指针:指针变量里存放一个数组的首地址。
      • 指针数组:数组用来存放指针,每个元素都是一个指针变量。
    • 使用:例如,通过指针数组表示字符串数组。
  • 字符数组 vs 字符指针变量
    • 字符数组:由若干字符元素组成。
    • 字符指针变量:存放字符串/字符数组的首地址。
  • 字符串数组的表示
    • 二维字符数组:每个元素是一个字符数组。
    • 字符指针数组:每个元素是一个字符指针,指向一个字符串。
  • 拓展:指向固定长度数组的指针变量
    • 定义格式:(*标识符)[一维数组元素个数];
    • 举例:int (*p)[4]; 表示指向包含4个元素的一维数组的指针变量。

      当然,我们可以继续深入探讨C语言中指针和其他相关概念的应用和细节。

      指针的高级应用

    • 1. 动态内存分配

    • 在C语言中,malloccallocrealloc等函数用于动态地在堆上分配内存。这些函数返回指向分配的内存的指针。使用这些函数时,程序员需要负责在不再需要这块内存时,使用free函数来释放它,以避免内存泄漏。

    • malloc:分配指定字节大小的内存块,并返回指向该内存块的指针。如果分配失败,则返回NULL。

      int *arr = (int*)malloc(n * sizeof(int));  
      if (arr == NULL) {  
          // 处理错误  
      }
    • calloc:分配指定数量的元素,每个元素大小为指定的大小,并将所有位初始化为零。它同样返回指向分配的内存的指针。

      int *arr = (int*)calloc(n, sizeof(int));  
      if (arr == NULL) {  
          // 处理错误  
      }
    • realloc:调整之前通过malloccalloc等分配的内存块的大小。如果原内存块足够大,则可能不需要移动;否则,会分配一个新的内存块,复制旧数据,并释放旧内存块。

      int *new_arr = (int*)realloc(arr, new_size * sizeof(int));  
      if (new_arr == NULL) {  
          // 处理错误  
      }  
      arr = new_arr; // 更新指针
    • 2. 指针与结构体

      结构体是一种允许将不同类型的数据项组合成一个单一类型的方式。在C语言中,结构体通常与指针一起使用,以便于动态创建和管理结构体实例。

      typedef struct {  
          int id;  
          char name[50];  
          float score;  
      } Student;  
        
      // 动态分配一个Student结构体  
      Student *student = (Student*)malloc(sizeof(Student));  
      if (student != NULL) {  
          student->id = 1;  
          strcpy(student->name, "Alice");  
          student->score = 92.5f;  
          // 使用完毕后,释放内存  
          free(student);  
      }
      3. 指针与函数
    • 函数指针:指向函数的指针,允许程序在运行时调用不同的函数。

      int add(int a, int b) {  
          return a + b;  
      }  
      
      int subtract(int a, int b) {  
          return a - b;  
      }  
      
      int main() {  
          int (*op)(int, int);  
          op = add;  
          printf("%d\n", op(5, 3)); // 输出8  
          op = subtract;  
          printf("%d\n", op(5, 3)); // 输出2  
          return 0;  
      }
    • 回调函数:作为参数传递给另一个函数的函数。在C标准库中,很多函数都接受函数指针作为参数,以实现回调函数的功能。

    • 4. 指针与数组的高级操作
    • 指针算术:在遍历数组时,指针算术允许我们直接通过指针的递增来访问数组的下一个元素,而无需使用索引

      int arr[] = {1, 2, 3, 4, 5};  
      int *p = arr;  
      for (; p < arr + sizeof(arr)/sizeof(arr[0]); p++) {  
          printf("%d ", *p);  
      }
    • 指针与多维数组:多维数组在内存中实际上是以一维数组的形式存储的,但可以通过指针运算来访问。

    • 5. 指针与文件操作

      在C语言中,文件操作也大量使用了指针。例如,FILE* fopen(const char *path, const char *mode);函数返回一个指向FILE对象的指针,该对象包含了所有用于文件操作的信息。

      FILE *fp = fopen("example.txt", "w");  
      if (fp != NULL) {  
          fprintf(fp, "Hello, world!\n");  
          fclose(fp);  
      }
  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值