首页 > 编程知识 正文

函数指针数组的指针的数组的指针,函数指针数组的指针

时间:2023-05-04 07:24:17 阅读:254749 作者:140

一、指针的概念(任何变量的声明都遵循:TYPE name = value)
1、变量:
变量(type name =value):声明一个变量就像盖了一间房子,假设房子地址为0x20,(计算机为变量开辟出一个内存地址空间),赋值类似于房子住进了人口。地址不变,存储内容可更改即为变量的定义。

直接访问:直接更改地址里的存储内容

间接访问(指针):(无法直接访问变量时,适用于跨函数,即从一个函数里改变另一个函数里变量的值)
比如:有3个抽屉,第1个抽屉藏500元(我直接打开抽屉,取走500称为直接访问)

int i=500;int *K1=&i;int **K2=&K1;

附:① int *K1=&i ; 与 ② int *K1; K1=&i ; 表达一致,原因如下:
任何变量的声明都是:type name = value;①可以拆解为,括号()为拆解部分: (int *)(K1)=&i
1)即w我声明了一个变量K1,它的类型是int *(整形指针),*代表变量是一个指针类型
2)&i赋值给了变量K1 而非 *K1。
3) 所谓变量类型就是指你希望定义的变量里存啥。
(int **)(K2)=&K1;与(int *)(K2)=&K1; 存储内容不同

但是考虑其安全性低,我锁上第1个抽屉,并把钥匙K1(== 钥匙即为地址==)放进第二个抽屉存储,(int *K1=&i)当我访问第2个抽屉里的内容时 就可以改变第一个抽屉的内容(即指针存放地址,可访问地址取出该指针指向地址处的值)---- ---------------------------------------------------一级指针就是这样
但是我还不放心,我把第2个抽屉锁上,并把K2放进第3个抽屉里存储,当我访问第3个抽屉时即可得到第2个抽屉的钥匙即地址(int *)(K2)=&K1; ,
再次访问第二个抽屉时即可取出K1即(int **)(K2)=&K1;(指针指向地址处的值)-------二级指针

3、野指针

举个例子:int i,j;//只给变量声明而不初始化,那么变量就是随机值int *P;//这个指针指向内存中的什么地方我们无法知道即野指针。假设它随机指向了正好我们在运行的地址0x80;*p=100;//这时100会存储到0x80里,设备运行崩溃。

附:

TYPE *p =addr *p=val 把val写入地址addr的内存中(写入字节取决于定义的类型)

4、空指针
当我们不知道指针指向时,可以先定义指针为空。

int *p =NULL;*p=100;

5、空类型指针(不确定当前定义指针类型,万金油)

int i =1;int *p = &i;void *q = 0x80;p=q;//此时指针类型会自动转换

程序出现截断错误:野指针或数组越界。

6、指针运算(& * + -)
&(取地址)
*(取值)
指针做减法:两个指针必须指向连续地址空间

void *p=0x10;void *q=0x80; int b; b= q-p;//b==6,指针相减得出来的是地址之间相差多少个存储单元而非0x70

二、指针与数组(直接访问与间接访问)
1、指针与一维数组

int a[3] ={1,2,3};int *p=a; a[i] == *(a+i) == *(p+i) ==p[i] //最后一个没写错,对照a[i]&a[i] == a+i == p+i == &p[i]

2、指针与二维数组

#include<stdio.h>int main(void){int a[2][3] = { {1,2,3},{4,5,6} };int *p=a; // a在这里代表的是二维数组的行首地址, 单纯的*p是一个只能指向一维数组的指针}error:无法从“int [2][3]”转换为“int *”// 指针数组(重音在后):int *a[3]; // int a[3];它的类型为整形,那么int *指针类型 若给*a加()即 int (*a)[3],那么它就变成**数组指针**了,它表示一个指针*a指向int[3]这样的二维数组 即上上面的数组指针(重音在后)可以改写为: int (*p)[3]; p=a;

三、指针与函数
1、函数指针(重音落在指针上)
理解函数指针、指针函数前先理解下面这段话:
1)、函数的名字即函数的入口地址的指代;
2)、函数的名字并不重要,就像变量的名字一样,区别函数的标准是它的类型返回值和传参类型
下面是函数指针:

int add(int a, int b) { return a+b; } int main() { int a = 3,b = 5; int (*p)(int,int) //它是一个指针(*P),指向返回类型是int,参数时两个int类型的函数; p=add; //函数的名字即函数的入口地址的指代;printf("%d",p(a,b)) //printf("%d",add(a,b))

当不方便直接调用一个函数时可以间接调用,如上。

2、指针函数(重音落在函数上)
理解下面这段话:
如果一个函数返回类型是整形,称为整形函数: int add(int a, int b)
如果一个函数返回类型是指针,称为指针函数: int* add(int a, int b),但它本质上还是一个函数,只是返回类型是指针类型。
3、函数指针数组(重音落在数组上)
int (*arr[2])(int,int);

**综合:(函数指针数组存放函数指针)**若干个类型相同的变量可以组成一个数组

int add(int a, int b) { return a+b; } int sub(int a, int b) { return a-b; } int main() { int a = 3,b = 5,i=0; int (*p)(int,int) ; int (*q)(int,int); p=add; //函数的名字即函数的入口地址的指代; q=sub; int (*arr[2])(int,int); arr[0]=p; arr[1]=q; for(i=0;i<2;i++) printf("%dn",arr[i](a,b))

四、type name =value 辅助承上启下的理解,看完第四个再重头开始理解,理解感会有质的提升哦!

int i = 100;char ch ='a';int a[3] = {1,2,3};早期数组定义:int [3] a = {1,2,3}; 这时再回忆 int (*p) [3] = a; 即(int [3] *) p=a数组指针,后期改进把指针提前即int (*p)[3]=a ;和 (int *)a[3];较为容易理解。 //(类型) (*p被看作一个整体) //(类型)

我们再看函数定义:

int add(int,int)即 int (int,int) add; //(type) //name 要定义一个和它类型相同的指针才能指向这个函数;int (int,int) *p = add,但现在编译器不识别了,必须把 *p提前即 int(*p)(int,int)=add

五、typedef
typedef int INT;
INT a; =>int a;
typedef int FUNC(int);
FUNC f1 =>int (int) f1 => int f1(int)

六、结构体指针 ->

结构体
结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构。
语法:struct 自定义类型名称 {成员}
自定义类型名称:一些类型集合组成的一个类型

//比如:创建学生数据类型,学生包括(姓名,班级,学号) struct student { //成员列表char name[20];int class;int number;}; //此时,我们创建好了一个学生类型,类似于int ,char,接下来我们通过学生类型创建具体结构体变量(学生) int main(void) { struct student s1={"zhangsan",1,18}; printf("name:%s class:%d number:%dn,s1.name,s1.class,s1.number) } //结构体类型,利用操作符访问结构体里的成员

C语言结构体(struct)最全的讲解(万字干货)

结构体指针
"->"是一个整体,它适用于指向结构体子数据的指针,用来取子数据。
换种说法,如果我们在C语言中定义了一个结构体,然后俭朴的嚓茶一个指针p指向这个结构体,那么我们要用指针p取出结构体中的数据,就要用到“->”。
例如:
struct T
{
int a;
char b;
}s;

struct T* p=&s; //type name =value;你希望定义的变量里存储啥就把它定义为啥类型,这里把p定义为结构体指针类 /型,p存放的是结构体变量s的地址,即p=&s。
那么,
大家都熟悉的访问结构体成员:s.a(结构体变量名.成员名)

这里*代表取值: (*p).a (*p相当于p指向的结构体变量s)
指针-> 成员名 p->a (前提是p必须事先指向结构体变量s)
三者等价。
.“一般情况下读作"的”。
“->”一般读作"指向的结构体的”。

struct 结构体类型名 *指针名;//结构体指针
struct 结构体类型名 *指针名 = &一个结构体的名字;//结构体指针并赋初值

typedef 结构体指针(上面没听懂?再啰嗦几句)

我们都知道,typedef 是给已有类型起一个新的名字,并非创建新类型

typedef struct student { int num; char name[20]; float score;}STU; //这里我们给struct student 结构体类型更换为名字简单的STUint main(){STU xwdxhd; //struct student xwdxhdSTU *p=&xwdxhd;p->num=101; //对p指向的结构体变量xwdxhd里的成员num进行赋值
UsinguseState()withanobjectasstate

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。