指针篇章(3)-(指针之间的区别)

news2024/9/27 19:17:17

学习目录

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

字符指针变量(常量字符串和 变量字符串)

 常量字符串和变量字符串是在编程中常见的两种字符串类型,它们有以下区别:

  1. 值的不可变性:常量字符串的值是不可变的,一旦被定义,就不能修改。而变量字符串的值是可变的,可以随时修改。

 常量字符串1:

const char* constantString = "Hello, World!";

在上述代码中,“Hello, World!” 是一个常量字符串,其值不可修改。

变量字符串1:

char variableString[] = "Hello, World!";

在上述代码中,variableString 是一个变量字符串,其值可以修改。

存储方式:常量字符串通常存储在只读内存区域,而变量字符串通常存储在可读写的内存区域。

————————————————————————————————————————————————————————————————————————————————————— 

常量字符串2:

const char* constantString = "Hello, World!";

在上述代码中,“Hello, World!” 是一个常量字符串,它通常存储在只读内存区域。

变量字符串2:

char variableString[] = "Hello, World!";

在上述代码中,variableString 是一个变量字符串,它通常存储在可读写的内存区域。

内存分配方式:常量字符串通常在编译时就被分配内存空间,而变量字符串通常在运行时动态分配内存空间。

—————————————————————————————————————————————————————————————————————————————————————  

常量字符串3:

const char* constantString = "Hello, World!";

在上述代码中,“Hello, World!” 是一个常量字符串,它在编译时就被分配了内存空间。

变量字符串3:

char variableString[] = "Hello, World!";

在上述代码中,variableString 是一个变量字符串,它在运行时动态分配了内存空间。

 想了解更多,可以看看这个篇章哦,有图像举例

C语言指针——常量字符串和 变量字符串-CSDN博客

 ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

指针数组

指针数组的作用

指针数组和数组指针是C语言中常用的概念,它们分别有不同的作用和用法。

  1. 指针数组: 指针数组是一个数组,其中的每个元素都是指针类型。它可以用来存储多个指针,每个指针可以指向不同的数据类型或者相同的数据类型。指针数组的作用是方便地管理多个指针,可以通过遍历数组来访问每个指针所指向的数据。
int* ptrArray[5];  // 定义一个包含5个指针的指针数组
int a = 1, b = 2, c = 3;
ptrArray[0] = &a;  // 第一个指针指向变量a
ptrArray[1] = &b;  // 第二个指针指向变量b
ptrArray[2] = &c;  // 第三个指针指向变量c

for (int i = 0; i < 3; i++) {
    printf("%d\n", *ptrArray[i]);  // 输出每个指针所指向的值
}

—————————————————————————————————————————————————————————————————————————————————————— 

整形数组 存放整形的数组

字符数组 存放字符的数组

指针数组 存放字符的数组

指针数组是一个数组,其中的每个元素都是指针类型。简单来说,它是一个存储指针的数组。

定义一个指针数组的语法

<数据类型> *<数组名>[<数组大小>];

其中,<数据类型>表示指针所指向的数据类型,<数组名>是数组的名称,<数组大小>表示数组的大小。

指针数组可以存储多个指针,每个指针可以指向不同的内存地址。这使得指针数组非常灵活,可以用于存储不同类型的数据或者不同对象的地址。

例如,定义一个指针数组来存储整型指针:

int *ptrArray[5];

这个指针数组可以存储5个整型指针。每个元素都可以指向一个整型变量或者整型数组。

使用指针数组时,可以通过索引来访问和操作每个指针元素。例如,可以通过ptrArray来访问第一个指针元素,并通过*ptrArray来访问该指针所指向的值。

总结一下,指针数组是一个存储指针的数组,它提供了一种灵活的方式来存储和操作不同类型的指针

下面进行指针数组的举例(参考指针数组模拟二维数组)

指针篇章-(2)-(一级指针和二级指针之间的理解)-CSDN博客

 ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

数组指针 

数组指针的作用

数组指针的作用主要有以下几个方面:

  1. 遍历数组:通过数组指针,可以使用指针算术运算来遍历数组中的元素,实现对数组的遍历操作。
  2. 传递数组给函数:通过将数组指针作为参数传递给函数,可以在函数内部对数组进行操作,而无需复制整个数组。
  3. 动态分配内存:通过数组指针,可以使用动态内存分配函数(如malloc)来动态创建数组,灵活地管理内存空间。

 —————————————————————————————————————————————————————————————————————————————————————

数组指针变量是什么

数组指针是指向数组的指针变量。它可以用来表示数组的首地址,并可以通过指针的偏移来访问数组中的元素。定义数组指针的语法如下:

其中,数据类型表示数组中元素的类型,指针变量名是指针变量的名称,数组长度表示数组的长度。

根本的说

指针数组,是数组

数组指针是指针

数组指针是指向数组的指针,它可以指向数组的首地址。通过数组指针可以访问数组中的元素,可以进行指针运算来遍历数组。例如,int* ptr 表示一个指向 int 类型的数组的指针。

数组指针变量是一个变量,它存储了一个数组指针的地址。它本身并不指向数组,而是指向一个指针,这个指针指向数组的首地址。通过数组指针变量可以间接地访问数组中的元素。例如,int* arrPtr[] 表示一个数组,其中的每个元素都是 int 类型的指针。

不加上括号则p和【】是一体的 加上了 则不是一体 [ ]的优先级更高

—————————————————————————————————————————————————————————————————————————————————————  

数组指针示范1

 这里取出的是整个数组的地址 ,但是他本身代表的的是数组首元素的地址 

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main() 
{
    int arr[10] = { 0 };

    int* pl = arr;
    printf("%p\n", pl);
    printf("%p\n", pl + 1);//所以+1 加上的是一个地址大小

    int(*p2)[10] = &arr;//这里取出的是整个数组的地址 ,但是他本身代表的的是数组首元素的地址 
    printf("%p\n", p2);
    printf("%p\n", p2 + 1);//所以+1 加上的是整个地址
    return 0;
}

—————————————————————————————————————————————————————————————————————————————————————  

数组指针语法格式 

数据类型 (*指针变量名)[数组长度];

这里注意要带括号 

int arr[5] = {1, 2, 3, 4, 5};
int (*ptr)[5];  // 定义一个指向整型数组的指针变量
ptr = &arr;     // 将指针指向数组的首地址

—————————————————————————————————————————————————————————————————————————————————————  

数组指针示范 2

#include <stdio.h>

int main() {
    int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int (*p)[10] = &arr;
    int i = 0;
    for (i = 0; i < 10; i++) {
        printf("%d ", (*p)[i]);
    }
    return 0;
}
在main函数中,首先定义了一个长度为10的整型数组arr,
并初始化了数组的元素。然后定义了一个指向数组的指针p,
并将其指向数组arr。接下来使用一个循环遍历数组arr,
通过指针p来访问数组元素,并使用printf函数将每个元素打印出来。

—————————————————————————————————————————————————————————————————————————————————————  

二维数组传参的本质

一维数组和二维数组

指针指向第一行的五个元素的数组

一次跳过一行

j是二维数组里面的一维数组的每个元素

二维数组传参可以写成数组也可以写成指针的形式

补充

这里详细介绍二维数组和一维数组以及指针的的关系,在指针5里面会进行详细介绍

这里可以先进行学习一下 这里主要是讲解的是数组名的代表的分别是什么

sizeof和strlen的详细万字解读-CSDN博客

——————————————————————————————————————————————————————————————————————————————————————

指针数组和数组指针二者的区别总结

  1. 数组指针(Array Pointer): 数组指针是指向数组的指针变量。它可以用来访问数组中的元素。数组指针的语法格式如下:

    数据类型 (*指针变量名)[数组长度];
    这里的数据类型表示数组中元素的类型,指针变量名是指向数组的指针变量的名称,数组长度表示数组的长度。例如,如果要定义一个指向整型数组的指针变量,可以使用以下语法:
    
    int (*ptr)[5];
    这样就定义了一个指向包含5个整型元素的数组的指针变量ptr。

  2. 指针数组(Array of Pointers): 指针数组是一个数组,其中的每个元素都是指针。它可以存储多个指针值。指针数组的语法格式如下:

    数据类型 *指针数组名[数组长度];
    这里的数据类型表示指针所指向的数据类型,指针数组名是指针数组的名称,数组长度表示数组的长度。例如,如果要定义一个包含3个整型指针的指针数组,可以使用以下语法:
    
    
    int *arr[3];
    这样就定义了一个包含3个整型指针的指针数组arr。

实例剖析 

指针篇章-(冒泡排序详解)-CSDN博客

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

函数指针变量和函数指针数组

函数指针变量

函数指针变量的作用

函数指针变量是指向函数的指针,它可以用来存储函数的地址,并且可以通过该指针调用相应的函数。函数指针变量的作用主要有以下几个方面:

  1. 回调函数:函数指针变量可以作为参数传递给其他函数,从而实现回调函数的功能。当某个条件满足时,可以通过函数指针调用相应的回调函数,实现特定的功能。

  2. 动态选择函数:通过函数指针变量,可以在运行时根据不同的条件选择不同的函数执行。这样可以提高程序的灵活性和可扩展性。

  3. 函数的别名:函数指针变量可以作为函数的别名使用,可以简化代码,提高代码的可读性。

  4. 实现函数表:通过将多个函数的指针存储在一个数组或者结构体中,可以实现函数表。通过索引或者其他方式,可以方便地调用相应的函数。

 ——————————————————————————————————————————

 函数指针变量语法格式 

这里和指针数组 

———————————————————————————————————————————

函数指针变量的定义和举例

函数指针是指向函数的指针变量。它可以用来存储函数的地址,从而可以通过指针调用函数。函数指针的定义方式如下:

返回类型 (*指针变量名)(参数列表);

其中,返回值类型是函数的返回值类型,指针变量名是函数指针的名称,参数列表是函数的参数类型和个数。

下面是一个函数指针的示例:

例如,我们有一个函数 add,它接受两个整数参数并返回它们的和。我们可以声明一个函数指针 p 来指向该函数:
int add(int a, int b) {
    return a + b;
}

int (*p)(int, int);  // 声明一个函数指针变量p

p = add;  // 将函数add的地址赋值给p

int result = p(3, 4);  // 通过函数指针调用add函数

在上面的例子中,我们声明了一个返回类型为 int,参数列表为 (int, int) 的函数指针 p。然后,我们将函数 add 的地址赋值给了 p,最后通过 p 调用了 add 函数并将结果赋给了 result。

函数指针在实际应用中非常有用,可以用于实现回调函数、动态加载库中的函数等场景

———————————————————————————————————————————

函数指针变量语法格式的讲解

数组指针->指针->指向数组的->存放的是数组的地址
&数组名是数组的地址
数组名是数组首元素的地址,两个地址的值是一样的!

对于首元素的理解不深入的 ,可以看一下这一篇文章 

指针数组和数组指针(详细解释)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/Jason_from_China/article/details/136581096

pf专门 用来存放地址 

 按照函数指针的格式来进行书写,就变成函数指针

这里是语法是相互对应的 

 这里的括号是不能去掉的,虽然pf是变量名字,但是那个括号是不能去掉的

去掉*pf外面的括号的话

pf就变成了名字不再是代表指针函数数组

而是变成,表示一个函数的声明,该函数返回一个返回值类型的指针变量。

所以,这里的语法格式是不能改变的

所以,这样也是可以的

函数指针变量函数名的调用和函数指针调用的对比

函数名调用

拿一个数值进行接收,直接传参 

函数指针的调用

此时pf的*和()可以写也可以不写

并且函数名本身就等于调用的函数,类似于重命名

最后打印接收的返回值

——————————————————————————————————————————————————————————————————————————————————————

补充知识 

强制类型转化

作用

C语言中的强制类型转换是一种将一个数据类型转换为另一个数据类型的操作。它可以通过显式地指定要转换的数据类型来实现。强制类型转换可以用于以下几种情况:

  1. 改变变量的数据类型:当需要将一个变量的数据类型从一种类型转换为另一种类型时,可以使用强制类型转换。例如,将一个整数转换为浮点数,或者将一个字符转换为整数。

  2. 提升数据类型:当进行表达式计算时,如果参与计算的操作数具有不同的数据类型,C语言会自动进行隐式类型转换,将较低精度的操作数提升为较高精度的操作数。但是有时候我们需要手动进行提升,以确保计算结果的准确性。

  3. 缩小数据类型:有时候我们需要将一个较高精度的数据类型转换为较低精度的数据类型,这时候就需要使用强制类型转换。需要注意的是,缩小数据类型可能会导致数据丢失或溢出,因此需要谨慎使用。

强制类型转换的语法如下:

(目标类型) 表达式

其中,目标类型是要转换成的数据类型,表达式是要进行转换的值或变量。

需要注意的是,强制类型转换可能会导致数据的精度丢失或溢出,因此在使用时需要谨慎考虑。此外,过度使用强制类型转换可能会导致代码可读性降低,建议在必要的情况下使用。

 举例

C语言中的强制类型转换是一种将一个数据类型转换为另一个数据类型的操作。它可以通过使用强制类型转换运算符来实现,即将要转换的数据类型放在要转换的值或表达式前面,用括号括起来。

例如,将一个整数类型转换为浮点类型可以使用强制类型转换。下面是一个示例:


int num = 10; float result = (float)num;

在上面的示例中,我们将整数类型的变量num强制转换为浮点类型,并将结果赋给浮点类型的变量result。

需要注意的是,强制类型转换可能会导致数据丢失或精度损失。因此,在进行强制类型转换时,需要谨慎考虑数据类型之间的兼容性和可能的副作用。

具体举例  

函数的返回类型

强制类型转化的语法 

——————————————————————————————————————————————————————————————————————————————————————

typedef 

typedef类型重命名

这里一笔带过 ,在指针2里面讲的很清楚,结构体和结构体的重命名

结构体详解-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/Jason_from_China/article/details/136477956指针篇章-(2)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/Jason_from_China/article/details/136408404

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

函数指针数组 

函数指针数组的作用

函数指针数组是一个数组,其中的每个元素都是一个函数指针。函数指针是指向函数的指针变量,可以用来调用相应的函数。函数指针数组的作用是可以根据需要动态地选择并调用不同的函数。

函数指针数组的使用场景有很多,以下是一些常见的应用:

  1. 回调函数:函数指针数组可以用于实现回调机制,即在某个事件发生时,根据不同的情况选择并调用相应的回调函数。
  2. 状态机:函数指针数组可以用于实现状态机,即根据当前状态选择并调用相应的处理函数。
  3. 命令分发:函数指针数组可以用于实现命令分发,即根据接收到的命令选择并调用相应的处理函数。
  4. 策略模式:函数指针数组可以用于实现策略模式,即根据不同的策略选择并调用相应的处理函数。

总之,函数指针数组提供了一种灵活的方式来选择并调用不同的函数,可以根据具体需求动态地改变函数的行为。

——————————————————————————————————————————  

函数指针数组的语法格式

函数指针数组是一个数组,其中的元素都是函数指针。函数指针是指向函数的指针变量,可以用来调用相应的函数。函数指针数组的语法格式如下:

返回值类型 (*指针数组名[数组大小])(参数列表);

其中,返回值类型是函数的返回值类型,指针数组名是函数指针数组的名称,数组大小是指针数组中元素的个数,参数列表是函数的参数类型和个数。

举个例子,

如果我们有一个函数指针数组,其中包含两个元素,个元素都指向一个无返回值、无参数的函数,可以这样声明:

void (*funcPtrArray[2])();

这里,funcPtrArray是一个包含两个元素的函数指针数组,每个元素都是一个指向无返回值、无参数的函数的指针。

使用函数指针数组时,可以通过索引来访问数组中的元素,并通过函数指针调用相应的函数。

——————————————————————————————————————————  

函数指针数组语法格式的讲解

举例来说,我们可以定义一个函数指针数组,其中的元素指向不同的排序算法函数:

#include <stdio.h>

// 声明排序算法函数
void bubbleSort(int arr[], int size);
void selectionSort(int arr[], int size);
void insertionSort(int arr[], int size);

int main() {
    // 定义函数指针数组并初始化
    void (*sortFuncs[3])(int[], int) = {bubbleSort, selectionSort, insertionSort};
    //函数指针 函数指针定义三个 ,然后是(数组和,整形类型的)

    // 调用函数指针数组中的函数
    int arr[] = {5, 2, 8, 1, 9};
    int size = sizeof(arr) / sizeof(arr[0]);

    for (int i = 0; i < 3; i++) 
    {
        sortFuncs[i](arr, size);//这里主要是看这一段 这个代码是我随机从网上找的,主要是让你们看看这个语法格式的使用 ,下面会进行转移表,也就是计算器的使用版本2,就是采取函数指针数组的形势进行计算的
        printf("排序结果:");

        for (int j = 0; j < size; j++) 
        {
            printf("%d ", arr[j]);
        }

        printf("\n");
    }

    return 0;
}

// 冒泡排序
void bubbleSort(int arr[], int size) {
    // 排序逻辑...
}

// 选择排序
void selectionSort(int arr[], int size) {
    // 排序逻辑...
}

// 插入排序
void insertionSort(int arr[], int size) {
    // 排序逻辑...
}

——————————————————————————————————————————————————————————————————————————————————————

函数指针数组的实际使用(转移表(计算器))

这里会简单提一嘴,在指针4篇章还会进行详细的解释,指针4篇章会详细解释qsort函数的使用和构建模拟

计算器的模拟版本1

运算函数 

主函数 

计算器形成

但是之前的代码是有问题的,冗余性太强

#include<stdio.h>

// 函数原型声明
int add(int x, int y);
int subtract(int x, int y);
int multiply(int x, int y);
int divide(int x, int y);

int main() {
    int input;
    printf("请输入运算类型(1-加法,2-减法,3-乘法,4-除法,0-退出):");
    scanf("%d", &input);

    while (input != 0) {
        switch (input) {
            case 1:
                printf("请输入两个加数:");
                int x, y;
                scanf("%d %d", &x, &y);
                printf("%d\n", add(x, y));
                break;
            case 2:
                printf("请输入两个减数:");
                scanf("%d %d", &x, &y);
                printf("%d\n", subtract(x, y));
                break;
            case 3:
                printf("请输入两个乘数:");
                scanf("%d %d", &x, &y);
                printf("%d\n", multiply(x, y));
                break;
            case 4:
                printf("请输入两个数,其中第二个数为除数:");
                scanf("%d %d", &x, &y);
                if (y != 0) {
                    printf("%d\n", divide(x, y));
                } else {
                    printf("除数不能为0。\n");
                }
                break;
            default:
                printf("输入错误,请输入正确的运算类型。\n");
                break;
        }
        printf("是否继续?(0-否,其他值-是):");
        scanf("%d", &input);
    }

    printf("退出计算器。\n");
    return 0;
}

// 函数定义
int add(int x, int y) {
    return x + y;
}

int subtract(int x, int y) {
    return x - y;
}

int multiply(int x, int y) {
    return x * y;
}

int divide(int x, int y) {
    return x / y;
}

这里ai解释一下 不过多赘述 
这次计算机的目的是为了进行回调函数和函数指针数组的学习

这段C语言代码实现了一个简单的计算器,能够进行加法、减法、乘法和除法运算。下面是逐行解释:
1. `#include<stdio.h>`:这行代码包含了标准输入输出头文件`stdio.h`,它是C语言中用于输入输出函数的基础头文件。
2. 函数原型声明:这些是函数原型声明,指明了将要定义的四个函数`add`、`subtract`、`multiply`和`divide`的返回类型和参数类型。
3. `int main()`:这是主函数的定义,`main`是C程序的入口点。
4. `int input;`:这行代码定义了一个整数变量`input`,用于存储用户的选择。
5. `printf("请输入运算类型(1-加法,2-减法,3-乘法,4-除法,0-退出):");`:这行代码打印出提示信息,要求用户输入运算类型。
6. `scanf("%d", &input);`:这行代码使用`scanf`函数从用户那里读取一个整数,并存储在变量`input`中。
7. `while (input != 0) {`:这是一个`while`循环,它会在用户输入0之前一直执行。
8. `switch (input)`:这是一个`switch`语句,它根据变量`input`的值来执行不同的代码块。
9. `case 1:`:这是一个`case`标签,当`input`等于1时,执行后面的代码块。
10. `printf("请输入两个加数:");`:这行代码打印出提示信息,要求用户输入两个加数。
11. `scanf("%d %d", &x, &y);`:这行代码使用`scanf`函数从用户那里读取两个整数,并存储在变量`x`和`y`中。
12. `printf("%d\n", add(x, y));`:这行代码调用`add`函数,并打印出返回的结果。
13. `break;`:这个关键字用于退出`switch`语句。
14. `case 2:`:这是一个`case`标签,当`input`等于2时,执行后面的代码块。
15. `printf("请输入两个减数:");`:这行代码打印出提示信息,要求用户输入两个减数。
16. `scanf("%d %d", &x, &y);`:这行代码使用`scanf`函数从用户那里读取两个整数,并存储在变量`x`和`y`中。
17. `printf("%d\n", subtract(x, y));`:这行代码调用`subtract`函数,并打印出返回的结果。
18. `break;`:这个关键字用于退出`switch`语句。
19. `case 3:`:这是一个`case`标签,当`input`等于3时,执行后面的代码块。
20. `printf("请输入两个乘数:");`:这行代码打印出提示信息,要求用户输入两个乘数。
21. `scanf("%d %d", &x, &y);`:这行代码使用`scanf`函数从用户那里读取两个整数,并存储在变量`x`和`y`中。
22. `printf("%d\n", multiply(x, y));`:这行代码调用`multiply`函数,并打印出返回的结果。
23. `break;`:这个关键字用于退出`switch`语句。
24. `case 4:`:这是一个`case`标签,当`input`等于4时,执行后面的代码块。
25. `printf("请输入两个数,其中第二个数为除数:");`:这行代码打印出提示信息,要求用户输入两个数,其中第二个数为除数。
26. `scanf("%d %d", &x, &y);`:这行代码使用`scanf`函数从用户那里读取两个整数,并存储在变量`x`和`y`中。
27. `if (y != 0) {`:这是一个`if`语句,它检查除数`y`是否不为0。
28. `printf("%d\n", divide(x, y));`:这行代码调用`

———————————————————————————————————————————

计算器的模拟版本2(函数指针数组的使用)(回调函数)

简化

冗余

老的代码的问题就是

冗余

写死

不能完成不同的任务

函数调用的时候只需要知道地址就可以

calc计算器

这里也称之为转移表

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int add(int x, int y)
{
	return x + y;
}
int subtract(int x, int y)
{
	return x - y;
}
int multiply(int x, int y)
{
	return x * y;
}
int except(int x, int y)
{
	return x / y;
}
void meun()
{
	printf("**************************\n");
	printf("*****    0  退出    ******\n");
	printf("*****    1  加法    ******\n");
	printf("*****    2  减法    ******\n");
	printf("*****    3  乘法    ******\n");
	printf("*****    4  除法    ******\n");
	printf("**************************\n");
}
void cala(int* compute(int, int))
{
	int x = 0; int y = 0;
	int pf = 0;
	scanf("%d %d", &x, &y);
	pf = compute(x, y);
	printf("%d ", pf);
}
int main()
{
	meun();
	int input = 0;
	scanf("%d", &input);	
	switch (input)
	{
	case 0:
		break;
	case 1:
		cala(add);
		break;
	case 2:
		cala(subtract);
		break;
	case 3:
		cala(subtract);
		break;
	case 4:
		cala(except);
		break;
	default:
		break;
	}
}

这里 用ai 逐行解释一下 我不过多作图解释了:
1. `#define _CRT_SECURE_NO_WARNINGS 1`:这是一个预处理器指令,用于告诉编译器忽略与安全相关的警告
2. `#include<stdio.h>`:这是一个预处理器指令,用于包含标准输入输出头文件`stdio.h`,这是C语言中用于输入输出函数的基础头文件。
3. `int add(int x, int y)`:这是一个函数定义,`add`是一个函数名,它接受两个整数参数`x`和`y`,并返回它们的和。
4. `int subtract(int x, int y)`:这是另一个函数定义,`subtract`是一个函数名,它接受两个整数参数`x`和`y`,并返回它们的差。
5. `int multiply(int x, int y)`:这是另一个函数定义,`multiply`是一个函数名,它接受两个整数参数`x`和`y`,并返回它们的积。
6. `int except(int x, int y)`:这是另一个函数定义,`except`是一个函数名,它接受两个整数参数`x`和`y`,并返回它们的商。注意,这个函数没有进行除数是否为0的检查,这在实际使用中是不安全的。
7. `void meun()`:这是一个函数定义,`meun`是一个函数名,它没有返回值。这个函数的作用是打印出菜单供用户选择运算类型。
8. `void cala(int* compute(int, int))`:这是另一个函数定义,`cala`是一个函数名,它接受一个指向函数的指针作为参数。这个函数的作用是调用用户提供的运算函数,并打印出结果。
9. `int main()`:这是主函数的定义,`main`是一个特殊的关键字,表示程序的入口点。
10. `meun();`:这行代码调用`meun`函数,打印出菜单。
11. `int input = 0;`:这行代码定义了一个整数变量`input`并初始化为0,用于存储用户的选择。
12. `scanf("%d", &input);`:这行代码使用`scanf`函数从用户那里读取一个整数,并存储在变量`input`中。
13. `switch (input)`:这是一个`switch`语句,它根据变量`input`的值来执行不同的代码块。
14. `case 0:`:这是一个`case`标签,当`input`等于0时,执行后面的代码块。
15. `break;`:这个关键字用于退出`switch`语句。
16. `case 1:`:这是一个`case`标签,当`input`等于1时,执行后面的代码块。
17. `cala(add);`:这行代码调用`cala`函数,并传递`add`函数的地址作为参数。
18. `break;`:这个关键字用于退出`switch`语句。
19. `case 2:`:这是一个`case`标签,当`input`等于2时,执行后面的代码块。
20. `cala(subtract);`:这行代码调用`cala`函数,并传递`subtract`函数的地址作为参数。
21. `break;`:这个关键字用于退出`switch`语句。
22. `case 3:`:这是一个`case`标签,当`input`等于3时,执行后面的代码块。
23. `cala(subtract);`:这行代码调用`cala`函数,并传递`subtract`函数的地址作为参数。这里似乎是一个错误,因为`subtract`函数并不适合乘法操作。
24. `break;`:这个关键字用于退出`switch`语句。
25. `case 4:`:这是一个`case`标签,当`input`等于4时,执行后面的代码块。
26. `cala(except);`:这行代码调用`cala`函数,并传递`except`函数的地址作为参数。
27. `break;`:

—————————————————————————————————————————— 

版本3(函数指针数组的使用)

计算机代码的简化

创建函数指针的数组

#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int add(int x, int y)
{
	return x + y;
}
int subtract(int x, int y)
{
	return x - y;
}
int multiply(int x, int y)
{
	return x * y;
}
int except(int x, int y)
{
	return x / y;
}
void meun()
{
	printf("**************************\n");
	printf("*****    0  退出    ******\n");
	printf("*****    1  加法    ******\n");
	printf("*****    2  减法    ******\n");
	printf("*****    3  乘法    ******\n");
	printf("*****    4  除法    ******\n");
	printf("**************************\n");
}
int main()
{

	int (*compute[5])(int, int) = { 0, add,subtract,multiply,except };
	int input = 0; 

	do
	{
		meun();
		printf("请选择:\n");

		scanf("%d", &input);
		printf("请输入:");
		if (input>=1&& input<=4)
		{
			int x = 0; int y = 0; int zd = 0;
			scanf("%d %d", &x, &y);
			zd = (*compute[input])(x, y);
			printf("%d\n", zd);
		}
		else if (input == 0)
		{
			printf("退出程序。");
			break;
		}
		else 
		{
			printf("输入错误。");
		}

	} while (input);
}

这里 用ai 逐行解释一下 我不过多作图解释了:
这段代码是C语言编写的一个简单计算器程序,下面是逐行解释:
1. `#define _CRT_SECURE_NO_WARNINGS 1`:这是一个预处理器指令,用于告诉编译器忽略与安全相关的警告,特别是在使用像`fgets`、`fopen`等函数时。这行代码应该只包含一次,重复定义可能会导致编译错误。
2. `#include<stdio.h>`:这是一个预处理器指令,用于包含标准输入输出头文件`stdio.h`,这是C语言中用于输入输出函数的基础头文件。
3. `int add(int x, int y)`:这是一个函数定义,`add`是一个函数名,它接受两个整数参数`x`和`y`,并返回它们的和。
4. `int subtract(int x, int y)`:这是另一个函数定义,`subtract`是一个函数名,它接受两个整数参数`x`和`y`,并返回它们的差。
5. `int multiply(int x, int y)`:这是另一个函数定义,`multiply`是一个函数名,它接受两个整数参数`x`和`y`,并返回它们的积。
6. `int except(int x, int y)`:这是另一个函数定义,`except`是一个函数名,它接受两个整数参数`x`和`y`,并返回它们的商。注意,这个函数没有进行除数是否为0的检查,这在实际使用中是不安全的。
7. `void meun()`:这是一个函数定义,`meun`是一个函数名,它没有返回值。这个函数的作用是打印出菜单供用户选择运算类型。
8. `int main()`:这是主函数的定义,`main`是一个特殊的关键字,表示程序的入口点。
9. `int (*compute[5])(int, int) = { 0, add,subtract,multiply,except }`:这行代码定义了一个函数指针数组`compute`,长度为5。每个元素指向一个算术运算函数。数组的第一个元素被初始化为`0`,这通常用于指针数组的终止标志。
10. `int input = 0;`:这行代码定义了一个整数变量`input`并初始化为0,用于存储用户的选择。
11. `do`:这是一个循环开始关键字,表示开始一个`do-while`循环。
12. `meun();`:这行代码调用`meun`函数,打印出菜单。
13. `printf("请选择:\n");`:这行代码打印出提示信息“请选择:”。
14. `scanf("%d", &input);`:这行代码使用`scanf`函数从用户那里读取一个整数,并存储在变量`input`中。
15. `printf("请输入:");`:这行代码打印出提示信息“请输入:”。
16. `if (input>=1&& input<=4)`:这是一个条件判断,检查用户输入是否在1到4之间,包括1和4。
17. `{ int x = 0; int y = 0; int zd = 0;`:这个大括号开始了一个代码块,用于执行当用户输入在1到4之间时的操作。
18. `scanf("%d %d", &x, &y);`:这行代码使用`scanf`函数从用户那里读取两个整数,并存储在变量`x`和`y`中。
19. `zd = (*compute[input])(x, y);`:这行代码调用相应的运算函数,并将结果存储在变量`zd`中。
20. `printf("%d\n", zd);`:这行代码打印出计算结果。
21. `}`:这个大括号结束了上面的代码块。
22. `else if (input == 0)`:这是另一个条件判断,检查用户输入是否为0。
23. `{ printf("退出程序。");`:这个代码块用于执行当用户输入为0时的操作,打印出提示信息。
24. `break;`:这个关键字用于退出循环。
25. `}`:这个大括号结束了上面的条件判断。
26. `else`:这是另一个条件判断,用于处理用户输入不在1到4之间

—————————————————————————————————————————— 

计算器代码总结 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//菜单
void meun()
{
	printf("**************************\n");
	printf("*****    0  退出    ******\n");
	printf("*****    1  加法    ******\n");
	printf("*****    2  减法    ******\n");
	printf("*****    3  乘法    ******\n");
	printf("*****    4  除法    ******\n");
	printf("**************************\n");
}
// 函数定义
int add(int x, int y) 
{
    return x + y;
}

int sub(int x, int y) 
{
    return x - y;
}

int mul(int x, int y) 
{
    return x * y;
}

int dive(int x, int y) 
{
    return x / y;
}

//函数指针数组的使用
void Function_pointers()
{
	int(*compute[5])(int, int) = { 0,add,sub,mul,dive };
	int input = 0; int x = 0; int y = 0;
	do
	{
		if (input > 0 && input <= 4)
		{
			meun();
			printf("请输入>\n");
			scanf("%d", &input);
			printf("请输入计算数值>\n");
			scanf("%d %d", &x, &y);
			int outcome = (*compute[input])(x, y);
			printf("结果是:%d\n", outcome);
		}
		else if (input == 0)
		{
			printf("退出");
			break;
		}
		else
		{
			printf("输入错误。");
		}

	} while (input);
}

//回调函数的使用
void invoke(int*ps(int, int))
{
	int x = 0; int y = 0;
	printf("请输入计算数值>\n");
	scanf("%d %d", &x, &y);
	int outcome = (*ps)(x, y);
	printf("结果是:%d\n", outcome);

}
void Callback()
{
	int input = 0;
	do
	{
		meun();
		printf("请输入>\n");
		scanf("%d", &input);

		switch (input)
		{
		case 0:
			break;
		case 1:
			invoke(add);
			break;
		case 2:
			invoke(sub);
			break;
		case 3:
			invoke(mul);
			break;
		case 4:
			invoke(dive);
			break;
		default:
			printf("输入错误。");
			break;
		}
	} while (input);
}
//正常计算函数
void count()
{
	int input = 0;
	do
	{
		int x = 0; int y = 0;
		meun();
		printf("请输入>\n");
		scanf("%d", &input);
		int outcomt = 0;
		switch (input)
		{
		case 0:
			printf("退出");
			break;
		case 1:
			printf("请输入计算数值>\n");
			scanf("%d %d", &x, &y);
			outcomt = add(x, y);
			printf("结果是:%d\n", outcomt);
			break;
		case 2:
			printf("请输入计算数值>\n");
			scanf("%d %d", &x, &y);
			outcomt = sub(x, y);
			printf("结果是:%d\n", outcomt);
			break;
		case 3:
			printf("请输入计算数值>\n");
			scanf("%d %d", &x, &y);
			outcomt = mul(x, y);
			printf("结果是:%d\n", outcomt);
			break;
		case 4:
			printf("请输入计算数值>\n");
			scanf("%d %d", &x, &y);
			outcomt = dive(x, y);
			printf("结果是:%d\n", outcomt);
			break;
		default:
			printf("输入错误。");
			break;
		}
	} while (input);
}



//主函数
int main()
{
	//printf("函数指针数组的使用>\n");
	//Function_pointers();

	//printf("回调函数的使用>\n");
	//Callback();

	printf("正常函数的使用>\n");
	count();
}

———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— 

函数指针变量和函数指针数组区别

函数指针变量和函数指针数组是两种不同的概念。

  1. 函数指针变量是指向函数的指针,它可以存储一个函数的地址。通过函数指针变量,我们可以直接调用该函数。函数指针变量的声明方式为:返回类型 (*指针变量名)(参数列表)。例如,int (*funcPtr)(int, int)表示一个返回类型为int,接受两个int类型参数的函数指针变量。

  2. 函数指针数组是一个数组,其中的每个元素都是一个函数指针。每个函数指针可以指向不同的函数。函数指针数组的声明方式为:返回类型 (*数组名[数组长度])(参数列表)。例如,int (*funcPtrArray)(int, int)表示一个包含5个元素的函数指针数组,每个元素都是一个返回类型为int,接受两个int类型参数的函数指针。

总结一下:

  • 函数指针变量可以指向一个函数,通过该指针变量可以直接调用该函数。
  • 函数指针数组是一个数组,其中的每个元素都是一个函数指针,每个函数指针可以指向不同的函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1507079.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序开发系列(二十六)·小程序运行机制(启动、前后台状态、挂起、销毁)和小程序更新机制

目录 1. 小程序运行机制 1.1 启动 1.2 前台和后台状态 1.3 挂起 1.4 销毁 2. 小程序更新机制 1. 小程序运行机制 1.1 启动 小程序启动可以分为两种情况&#xff0c;一种是冷启动&#xff0c;一种是热启动。 冷启动&#xff1a;如果用户首次打开&#xff0c;或小…

mysql的trace追踪SQL工具,进行sql优化

trace是MySQL5.6版本后提供的SQL跟踪工具&#xff0c;通过使用trace可以让我们明白optimizer&#xff08;优化器&#xff09;如何选择执行计划。 注意&#xff1a;开启trace工具会影响mysql性能&#xff0c;所以只适合临时分析sql使用&#xff0c;用完之后请立即关闭。 测试数…

电脑中缺失EMP.dll文件怎么办,解决EMP.dll丢失问题的有效方法分享

当你的电脑出现由于找不到emp.dll无法继续执行代码的提示&#xff0c;那你要怎么办呢&#xff1f;其实解决方法还是挺多的&#xff0c;今天就来给大家详细的说说emp.dll这方面的信息吧。 一、电脑为什么会出现emp.dll丢失 不完全卸载软件&#xff1a;在卸载程序时&#xff0c;…

小迪安全37WEB 攻防-通用漏洞XSS 跨站权限维持钓鱼捆绑浏览器漏洞

#XSS跨站系列内容:1. XSS跨站-原理&分类&手法 XSS跨站-探针&利用&审计XSS跨站另类攻击手法利用 XSS跨站-防御修复&绕过策略 #知识点&#xff1a; 1、XSS 跨站-另类攻击手法分类 2、XSS 跨站-权限维持&钓鱼&浏览器等 1、原理 指攻击者利用…

可商用的HuoCMS建站系统,基于thinkphp内核且免费开源

HuoCMS是一套内容管理系统&#xff0c;同时也是一套适用于企业官网建设的系统&#xff0c;能够帮助用户快速搭建个人网站。满足企业站、外贸站、个人博客等多种建站需求。HuoCMS的优势在于可以通过统一后台管理多个网站的内容&#xff0c;方便维护和共享不同内容在不同网站上的…

关于playbook中when条件过滤报The conditional check ‘result|failed‘ failed的问题

问题现象 在使用plabook中的when做过滤脚本如下&#xff1a; --- - hosts: realserversremote_user: roottasks:- name: Check if httpd service is runningcommand: systemctl status httpdregister: resultignore_errors: True- name: Handle failed service checkdebug:ms…

离线数仓(六)【ODS 层开发】

前言 1、ODS 层开发 ODS层的设计要点如下&#xff1a; &#xff08;1&#xff09;ODS层的表结构设计依托于从业务系统同步过来的数据结构&#xff08;JSON/CSV/TSV&#xff09;。 &#xff08;2&#xff09;ODS层要保存全部历史数据&#xff0c;故其压缩格式应选择高压缩比的…

Android 学习之追踪应用的安装情况

先上结论&#xff0c;急用的话直接看结论 结论一、借助 API 读取安装信息&#xff0c;然后上报二、借助手动埋点&#xff0c;然后上报三、对比 前提过程 结论 一、借助 API 读取安装信息&#xff0c;然后上报 通过 PackageManager 的 API&#xff0c;我们可以得知自身应用安装…

基于VSCode安装Node.js开发环境

根据官网介绍&#xff0c;Node.js 是一个免费的、开源的、跨平台的JavaScript实时运行环境&#xff0c;允许开发人员在浏览器之外编写命令行工具和服务器端脚本. Node.js框架由于是采用JavaScript语法进行调用的&#xff0c;因此Node.js环境除了用来编写调试Node.js代码&#…

2024 年排名前 5 名的 Mac 数据恢复软件分享

如果您已经在 Mac 上丢失了数据并且正在寻找恢复数据的方法&#xff0c;那么您来对地方了。互联网上有超过 50 个适用于 Mac 的数据恢复程序。哪个是最好的 Mac 数据恢复软件&#xff1f;不用担心。本文列出了 5 款 Mac 数据恢复软件&#xff0c;可帮助您在 Mac OS 下恢复丢失的…

jvm八股

文章目录 运行时数据区域Java堆对象创建对象的内存布局对象的访问定位句柄直接指针 GC判断对象是否已死引用计数算法可达性分析算法 引用的类别垃圾收集算法分代收集理论标记清除算法标记复制算法标记整理算法 实现细节并发的可达性分析 垃圾收集器serial收集器ParNew收集器Par…

手机短信恢复 - 如何在 Android 手机上恢复删除的短信

手机每天发送和接收的短信数以亿计&#xff0c;而Android消息丢失每天都在发生。 Android短信恢复对于那些在设备中保存了一些重要信息的人来说显得至关重要。首先&#xff0c;我们向您推荐奇客数据恢复安卓版&#xff0c;这款软件能够高效、安全地恢复已删除的短信&#xff0…

结构指针的使用

结构指针的使用 指针类型变量&#xff1a; 指针类型&#xff0c;是变量类型的一种&#xff0c;它是专门用来存储变量的地址的。 例如 int *p; 表示p是一个指针变量&#xff0c;它用来存储某个整型变量的地址。 int a5; int *p&a; 这样&#xff0c;就将整型变量a的地…

有什么针对新闻媒体行业的安全解决方案

对媒体行业而言&#xff0c;门户网站是最易受到攻击的地方。常见的攻击方式有网页篡改、挂马和被植入暗链等。门户网站作为新闻媒体对外的第一扇门&#xff0c;通常承载了大量的流量&#xff0c;一旦遭到攻击&#xff0c;造成的影响会更具有可怕的“传播力”。那么我们应该如何…

Tree Shaking:优化前端项目的利器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

1、功能安全入门之内功心法ISO26262介绍

目录 0. 对于安全规范的认知 0.1 ISO26262简介 0.2 功能安全的必要性 2. ISO26262第1部分基本术语 2. ISO26262第2部分-功能安全管理 3. ISO26262第3部分-概念阶段 4. ISO26262第4部分-产品开发:系统层面 5. ISO26262第5部分-产品开发:硬件层面 6. ISO26262第6部分-…

使用VBA快速梳理多层级族谱(组织架构)

实例需求&#xff1a;族谱&#xff08;或者公司组织架构等&#xff09;都是典型的带有层级关系数据&#xff0c;例如下图中左侧表格所示。 A列为层级&#xff08;准确的讲是B列成员的层级&#xff09;&#xff0c;从一开始递增B列和C列为成员直接的父&#xff08;/母&#xff…

搭建一款实用的个人IT工具箱——it-tools

一、it-tools介绍 IT-Tools是一款开源的个人工具箱&#xff0c;专为IT从业人员打造&#xff0c;支持Docker私有化部署&#xff0c;包含众多实用的IT工具。其功能丰富多样&#xff0c;涵盖二维码生成、数据格式转换、MAC地址生成等&#xff0c;可满足用户多样化的需求。 二、本…

armv8/armv9 MMU深度学习

目录 1、MMU概念介绍2、虚拟地址空间和物理地址空间2.1、(虚拟/物理)地址空间的范围2.2、物理地址空间有效位(范围)2.2.1、页表翻译相关寄存器的配置 3、Translation regimes4、地址翻译/几级页表&#xff1f;4.1、思考&#xff1a;页表到底有几级&#xff1f;4.2、以4KB granu…

《日期类》的模拟实现

目录 前言&#xff1a; 头文件类与函数的定义Date.h 实现函数的Date.cpp 测试Test.cpp 运行结果&#xff1a; 前言&#xff1a; 我们在前面的两章初步学习认识了《类与对象》的概念&#xff0c;接下来我们将实现一个日期类&#xff0c;是我们的知识储备更加牢固。 头文件…