自学内容网 自学内容网

#include<初见C语言之指针(3)>

目录

一、字符指针变量

二、数组指针变量

1.什么是数组指针变量?

2.数组指针怎么初始化?

三、二组数组传参的本质

四、函数指针变量

1.什么是函数指针变量?

2.函数指针变量使用 

 3.有趣代码

 3.1typedef关键字

五、函数指针数组

六、转移表

总结


一、字符指针变量

字符指针变量的指针类型是char*;

一般使用:

int main()
{
    char ch = 'w';
    char* pc = &ch;
    printf("%c\n", ch);
    *pc = 'p';
    printf("%c\n", *pc);
    
    return 0;

}

%c是打印字符的,%s是打印字符串的首地址

其他用法:

int main()
{
    const char* p= "hello world";//常量字符串,是不能修改的
    printf("%c\n", *p);
    //*p = 'q';//err
    
    return 0;

}

很容易把代码hello world放在指针*p中,但是本质是把字符串的首地址放在*p中。

画图演示:

下面我们再来看看一段代码:

 #include <stdio.h>
int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    const char* str3 = "hello bit.";
    const char* str4 = "hello bit.";
    if (str1 == str2)
        printf("str1 and str2 are same\n");
    else
        printf("str1 and str2 are not same\n");

    if (str3 == str4)
        printf("str3 and str4 are same\n");
    else
        printf("str3 and str4 are not same\n");

    return 0;
}

画图演示:

所以str1和str2不相同,str3和str4相同;(常量字符串,是不能修改的)


二、数组指针变量

1.什么是数组指针变量?

类比的方法:

  • 字符指针 char* p 指向字符的指针,存放的是字符地址
  • 整型指针 char* p 指向整型的指针,存放的是整型地址

所以数组指针是一种指针变量,是存放数组地址的指针变量

char ch = 'w';

char* pc =&ch;//字符指针

int n =10;

int* p =&n;//整型指针

数组指针变量

int (*p)[10];

解释:p先和*结合,说明p是一个指针变量,然后指向的是一个大小为10个整型的数组

 注意:[ ]的优先级要高于*,所以必须先加()保证p和*结合

2.数组指针怎么初始化?

在前面的学习中我们就知道,数组名是数组首元素的地址

int main()
{
    int arr[10] = { 10 };
    int(*p)[10] = &arr;//取出的是数组的地址
    //p应该是数组指针
    
    return 0;
}

&arr和p的类型是一致的 


三、二组数组传参的本质

二维数组的一般写法

void test(int arr[3][5],int r,int c)
{
    int i = 0;
    for (i = 0; i < r; i++)
    {
        int j = 0;
        for (j = 0; j < c; j++)
        {
            printf("%d ", arr[i][j]);
        }
    }
}


int main()
{
    int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
    test(arr, 3, 5);
    return 0;
}

二维数组名是谁的地址?

根据数组名是数组⾸元素的地址这个规则

  1. 二维数组的首元素就是第一行(一维数组)
  2. 每一行都是一个元素(一维数组)

画图演示:

void test(int (*p)[5], int r, int c)
{
    int i = 0;
    for (i = 0; i < r; i++)
    {
        int j = 0;
        for (j = 0; j < c; j++)
        {
            //printf("%d ", (*p+i)[j]);
            printf("%d ", *(*(p+i)+j));// arr[i]==*(arr+i)
        }
        printf("\n");
    }
}
int main()
{
    int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
    test(arr, 3, 5);
    return 0;
}

 结论:⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。


四、函数指针变量

1.什么是函数指针变量?

类比:

  • 数组指针,指向数组,存放数组地址
  • 整型指针,指向整型,存放整型地址

函数指针,指向函数,存放函数的地址

int Add(int a, int b)
{
    return a + b;
}

int* test(char* s)
{
    return 0;
}
//
函数指针变量的写法和数组指针变量写法类似

int main()
{
    int*(*pt)(char) = &test;
    int arr[8] = { 0 };
    int(*pa)[8] = &arr;//pa是数组指针变量
    int (*pf)(int,int) = &Add;//pf是函数指针变量
    int x = 10;
    int y = 20;
    int z = Add(x,y);
    printf("%p\n", &Add);
    printf("%p\n", Add);


    return 0;
}

&函数名和函数名都是表示函数地址 

函数指针变量

int (*pf) (int x,int y);

解析: 

2.函数指针变量使用 

int Add(int a, int b)
{
return a + b;
}

int main()
{
int (*pf1)(int, int) = &Add;//pf就是函数指针变量
int (*pf2)(int, int) = Add;

int r1 = (*pf1)(3,7);
int r2 = (*pf2)(3,7);//*可以
int r4 = pf2(3,7);
int r3 = Add(3, 7);

printf("%d\n", r1);
printf("%d\n", r2);
printf("%d\n", r3);
printf("%d\n", r4);

return 0;
}

 3.有趣代码

代码1:

void (*p)();

int main()
{
    (*(void (*)())0)();//函数调用
    //1.将0强制类型转换成void(*)()类型的函数指针
    //2.调用0地址放的这个函数
    
    return 0;
}

 代码2

int main()
{
    void (*signal(int, void(*)(int)))(int);//函数声明
    //声明的函数名叫:signal
    //signal的函数有2个参数,第一个参数的类型是int
    //第二个参数的类型是void(*)(int)的函数指针类型,该指针可以指向一个函数,指向的函数参数是int,返回类型是void
    // signal函数的返回类型是void(*)(int)的函数指针,该指针可以指向一个函数,指向的函数参数是int,返回类型是void
    
    //void (*)(int)signal(int, void(*)(int));//err
    return 0;
}

 3.1typedef关键字

typedef对整型类型
typedef unsigned int uint;

int main()
{
    unsigned int num1;
    uint num2;
    return 0;
}


typedef对指针类型重命名
typedef int* pint;

int main()
{
    int* p1 = NULL;
    pint p2 = NULL;
    return 0;
}


数组指针重命名
typedef int(*parr_t)[5];
//*parr_t等价于int(*)[5]
int main()
{
    int arr[5] = { 10 };
    int(*p)[5] = &arr;//p是数组指针变量,p是变量的名字
    //int (*)[5] -- 数组指针类型
    parr_t p2 = &arr;
}
void test(char* s)
{

}


//对函数指针类型重命名产生新的类型pf_t
typedef void(*pf_t)(char*);

int main()
{
    void(*pf)(char*) = test;
    //void (*)(char*)
    pf_t pf2 = test;
}


五、函数指针数组

类比:

  • 字符指针数组 char* arr1[5];
  • 整型指针数组  int* arr2[5];

如果要把多个相同类型的函数指针存放在一个数组中,这个数组就叫:函数指针数组

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 div(int x,int y)
{
    return x / y;
}
int main()
{
    int (*pf1)(int,int ) = add;
    int (*pf2)(int,int ) = sub;
    int (*pf3)(int,int ) = mul;
    int (*pf4)(int,int ) = div;


    int (*pfarr[4])(int, int) = { add,sub,mul,div };//pfarr就是函数指针数组
    int i = 0;
    for(i=0;i<4;i++)
    {
        int ret = pfarr[i](8,4);
        printf("%d\n", ret);
    }

    return 0;
}

int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };

解析:

 

六、转移表

我们这里写一个计算机,实现加减乘除法;

第一种写法:

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 Div(int x, int y)
{
return x / y;
}
//想写一个计算器
//完成2个整数的运行
//1.加法
//2.减法
//3.乘法
//4.除法
void menu()
{
printf("**************************\n");
printf("*****1.Add     2.Sub******\n");
printf("*****3.Mul     4.Div******\n");
printf("*****     0.exit    ******\n");
printf("**************************\n");
printf("**************************\n");
printf("**************************\n");
}
int main()
{
int input = 0;
int x = 0;
int y = 0;
int ret = 0;
do
{

menu();
int input = 0;
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入2个操作数:");
scanf("%d %d", &x, &y);
ret = Add(x, y);
printf("%d", ret);
break;
case 2:
printf("请输入2个操作数:");
scanf("%d %d", &x, &y);
ret = Sub(x, y);
printf("%d", ret);
break;
case 3:
printf("请输入2个操作数:");
scanf("%d %d", &x, &y);
ret = Mul(x, y);
printf("%d", ret);
break;
case 4:
printf("请输入2个操作数:");
scanf("%d %d", &x, &y);
ret = Div(x, y);
printf("%d", ret);
break;
case 0:
printf("退出计算器\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
} while (input);
return 0;
}

我们可以看到选择这一部分是很冗余的,所以我们可以利用函数指针数组来解决。

第二种写法:

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 Div(int x, int y)
{
return x / y;
}
//想写一个计算器
//完成2个整数的运行
//1.加法
//2.减法
//3.乘法
//4.除法
void menu()
{
printf("**************************\n");
printf("*****1.Add     2.Sub******\n");
printf("*****3.Mul     4.Div******\n");
printf("*****     0.exit    ******\n");
printf("**************************\n");
printf("**************************\n");
printf("**************************\n");
}
int main()
{
int input = 0;
int x = 0;
int y = 0;
int ret = 0;
//创建一个函数指针的数组
//转移表
int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };

do
{
menu();
int input = 0;
printf("请选择:");
scanf("%d", &input);
if (input >= 1 && input <= 4)
{
printf("请输入2个操作数:");
scanf("%d %d", &x, &y);
pfArr[input](x, y);
}
else if (input == 0)
{
printf("退出计算机\n");
}
else
{
printf("选择错误\n");

}

} while (input);


return 0;
}

这一种写法就看起来清爽很多,这样也可以添加更多的功能。

我们这里可以小结一下之前所学指针:

拓展:

char*(*(*p)[4])(int,char*) = &pfArr;//取出的是函数指针数组的地址

//p就是指向函数指针数组的指针;

所以我们就有第三种写法:

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 Div(int x, int y)
{
return x / y;
}
想写一个计算器
完成2个整数的运行
1.加法
2.减法
3.乘法
4.除法
void menu()
{
printf("**************************\n");
printf("*****1.Add     2.Sub******\n");
printf("*****3.Mul     4.Div******\n");
printf("*****     0.exit    ******\n");
printf("**************************\n");
printf("**************************\n");
printf("**************************\n");
}
void calu(int (*pf)(int,int))
{
int x = 0;
int y = 0;
int ret = 0;
printf("请输入2个操作数:");
scanf("%d %d", &x, &y);
ret = pf(x, y);
printf("%d", ret);
}
int main()
{
int input = 0;

do
{
menu();
int input = 0;
printf("请选择:");
scanf("%d", &input);

switch (input)
{
case 1:
calu(Add);
break;
case 2:
calu(Sub);
break;
case 3:
calu(Mul);
break;
case 4:
calu(Div);
break;
case 0:
printf("退出计算器\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}

} while (input);

return 0;
}

第二种是将函数指针数作为跳板、第三种写法我们都是将 取出函数指针数组的地址作为跳板


总结

指针的第三节主要是字符指针变量、数组指针变量、二维数组传参的本质、函数指针变量、函数指针数组以及转移表。


原文地址:https://blog.csdn.net/weixin_62408950/article/details/136782814

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!