C语言学习笔记——指针(三)

简介: C语言学习笔记——指针

10.回调函数

10.1.回调函数的基本介绍

  1. 函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数
  2. 回调函数是由别人的函数执行时调用你传入的函数(通过函数指针完成)(回调函数就是一个通过函数指针调用函数的函数,嵌套函数中的内层函数)

10.2回调函数的代码示例

使用回调函数的方式,给一个整型数组 int arr[10] 赋 10 个随机数

#include <stdlib.h> 
#include <stdio.h>
// 回调函数 
// //1.int (*f)(void)
//2. f 就是 函数指针 , 它可以接收的函数是 (返回 int ,没有形参的函数) 
//3. f 在这里被 initArray 调用,充当了回调函数角色
void initArray(int* array, int arraySize, int (*f)(void)) {
  int i;
  //循环 10 
  for ( i=0; i<arraySize; i++) { 
    array[i] = f(); //通过 函数指针调用了 getNextRandomValue 函数
  }
}
// 获取随机值 
int getNextRandomValue(void) {  
  return rand();//rand 系统函数, 会返回一个随机整数
}
int main(void) {
  int myarray[10], i; //定义一个数组和 int
  //说明 
  //1. 调用 initArray 函数 
  //2. 传入了一个函数名 getNextRandomValue (地址), 需要使用函数指针接收 
  initArray(myarray, 10, getNextRandomValue);
  //输出赋值后的数组 
  for (i = 0; i < 10; i++) {
    printf("%d ", myarray[i]);
  }
  printf("\n");
  return 0;
}

17bda238b92f43d48f950558c0947b9d.png

11.指针的注意事项和细节

  1. 指针变量存放的是地址,从这个角度看指针的本质就是地址
  2. 变量声明的时候,如果没有确切的地址赋值,为指针变量赋一个 NULL 值是好的编程习惯
  3. 赋为 NULL 值的指针被称为空指针,NULL 指针是一个定义在标准库 <stdio.h>中的值为零的常量 #define NULL 0

12.动态内存分配

12.1.C程序中,不同数据在内存中分配说明:

  1. 全局变量——内存中的静态存储区
  2. 非静态的局部变量——内存中的动态存储区——stack 栈
  3. 临时使用的数据——建立动态内存分配区域,需要时随时开辟,不需要时及时释放——heap 堆
  4. 根据需要向系统申请所需大小的空间,由于未在声明部分定义其为变量或者数组,不能通过变量名或者数组名 来引用这些数据,只能通过指针来引用)(堆)

12.2 内存动态分配的相关函数

  1. 头文件 #include <stdlib.h> 声明了四个关于内存动态分配的函数
  2. 函数原型 void* malloc(usigned int size) //memory allocation 取m和alloc字母组成

         1作用——在内存的动态存储区(堆区)中分配一个长度为 size 的连续空间

          2形参 size 的类型为无符号整型,函数返回值是所分配区域的第一个字节的地址(首地址,即此函数是一个指针型函数, 返回的指针指向该分配域的开头位置

malloc(100);//开辟100 字节的临时空间,返回值为其第一个字节的地址

3 函数原型 void* calloc(unsigned n,unsigned size)

  1. 作用——在内存的动态存储区中分配 n 个长度为 size 的连续空间,这个空间一般比较大,足以保存一个数组;函数返回指向所分配域的起始位置的指针;
  2. 分配不成功,返回NULL
p = calloc(50, 4); //开辟 50*4 个字节临时空间,把起始地址分配给指针变量 p

函数原型:void free(void *p)

  1. 作用——释放变量 p 所指向的动态空间,使这部分空间能重新被其他变量使用
  2. p 是最近一次调用 calloc 或malloc 函数时的函数返回值
  3. free 函数无返回值
free(p); // 释放 p 所指向的已分配的动态空间

5.函数原型 void *realloc(void *p,unsigned int size)

  1. 作用——重新分配malloc 或 calloc 函数获得的动态空间大小,将 p 指向的动态空间大小改变为 size,p 的值不变,分配失败返回NULL
  2. 可以增大或者减小已经分配malloc或者calloc获得的空间大小
realloc(p, 50); // 将 p 所指向的已分配的动态空间 改为 50 字节

6.返回类型说明

  1. C 99标准把以上malloc、calloc、realloc函数的基类型定为void类型。这种指针称为无类型指针(typeless pointer),
  2. c99允许使用基类型为void的指针类型。可以定义一个基类型为void的指针变量(即void*型变量),它不指向任何类型的数据。请注意:不要把“指向void类型”理解为能指向“任何的类型”的数据,应理解为“指向空类型"或“不指向确定的类型”的数据。在将它的值赋给另一指针变量时由系统对它进行类型转换,使之适合于被赋值的变量的类型。(void*类型指针不能用*p的方式取值)例如:
#include<stdio.h>
void main() {
  int a = 3;//定义a为整型变量
  int* p1 = &a;//定义一个指向int类型的指针变量p1,并指向int型变量
  char* p2;//定义一个指向char类型的指针变量p2
  void* p3; //定义一个无类型的指针变量p3(也可以理解为类型为void型)
  p3 = (void*)p1;//将p1的值转换为void*类型,然后赋值给p3(可以理解为强制类型转换)
  p2 = (char*)p3;//将p3的值转换换cha*类型,然后赋值给p2
  printf("%d", *p1);//合法,输出a的值
  p3 = &a;//只有在C99下才能这么写,相当于p3 = (void*)&a
  printf("%d", *p3);//不合法,p3是无指向的,不能指向a
}

7dfcae12436546a9ab4d671e4cbbfe19.png

12.3.动态内存分配代码示例

动态创建数组,输入 5 个学生的成绩,另外一个函数检测成绩低于 60 分的,输出不合格的成绩

#include<stdio.h>
#include<stdlib.h>
void check(int *p) {
  int i;
  printf("\n不及格的成绩有:");
  for (i = 0; i < 5; i++) {
    if (p[i] < 60) {
      printf("\n%d", p[i]);
    }
  }
}
void main() {
  int* p, i;
  //在堆区开辟一个5 * 4的空间,并将地址(void*),转成(int*),赋给p
  p = (int*)malloc(5 * sizeof(int));
  for (i = 0; i < 5; i++) {
    scanf_s("%d", p + i);
  }
  check(p);
  free(p);//销毁p的空间
}

d7930a69a3a345f9bee4a19961765f17.png

12.4.动态分配内存的基本原则

  1. 避免分配大量的小内存块。分配堆上的内存有一些系统开销,所以分配许多小的内存块比分配几个大内存块的系统开销大
  2. 仅在需要时分配内存。只要使用完堆上的内存块,就需要及时释放它(如果使用动态分配内存,需要遵守原则: 谁分配,谁释放), 否则可能出现内存泄漏(用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。
  3. 总是确保释放以分配的内存。在编写分配内存的代码时,就要确定在代码的什么地方释放内存
  4. 在释放内存之前,确保不会无意中覆盖堆上已分配的内存地址,否则程序就会出现内存泄漏。在循环中分配内存时,要特别小心



bf82adb19a4b47ceb4387dfb06332827.png


相关文章
|
10天前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
58 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
10天前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
34 9
|
10天前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
32 7
|
20天前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
81 12
|
13天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
13天前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
43 3
|
14天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
13天前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
29 1
|
17天前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
17天前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。