#include
int main()
{
int a = 0x11223344; // a申请一块内存空间 同时获得该内存空间的编号
//内存空间用于存放a的数值0x11223344
int* p = &a; // 存放a的数值的内存空间编号存放在变量p
return 0;
}
总结 :
指针存放的是指向空间的内存编号
字符型指针两种用途
#include
int main()
{
char a = 'a';
printf("%d", a);
char* p = &a; //p存放的就是a的地址
return 0;
}
#include
int main()
{
char* p = "abcdef";
printf("%c\n", *p); //打印结果可知 cha*p存放的任然是首地址
printf("%s\n", p);
return 0;
}
注意 :
#include
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";
char *str3 = "hello bit.";
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;
}
结果
结果是显而易见的 作为const修饰的数组 他就成为一个常量,系统无需要为其开辟两个内存空间我们在vs2019 调试验证
str3 和str4虽然是指针 但是他们指向的地址却是一样的
可见 系统不会为相同的常量开辟两个空间。
整形指针用来存放整形变量的地址的指针
#include
int main()
{
int i = 0x11223344;
int* p = &i; //将i的地址编号存放在p中
return 0;
}
浮点数使用方式同整形一致
但浮点数 存储方式与整形不同戳这里 浮点数动态内存分配
#include
int main()
{
float a = 3.14;
float* p = &a;
printf("%f", *p);
return 0;
}
指针步长与指针对应数据类型的大小一致
char*的指针走一步只能前进一个字节
1.数组指针的基本使用
由打印结果 可知 数组指针的步长就是数组指针定义的数组 ·
2.数组指针在一维数组的使用
打印一个数组
#include
int main()
{
int arr[10] = {
1,2,3,4,5,6,7,8,9,10 };
int(*parr)[10] = &arr;
for (int i = 0; i < 10; i++)
{
printf("%d ", *((*parr) + i));
printf("%d ", parr[0][i]);
printf("%d ", (*parr)[i]);
}
return 0;
}
我们在对arr和&arr 进行总结
接下来我们解读 parr *parr arr &arr 内存存放 以及 内存编号
注意:
void print(int(*parr)[5], int r, int c)
{
for (int i = 0; i < r; i++)
{
for (int j = 0; j < c; j++)
{
printf("%d ", *(*(parr + i) + j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {
{
1,2,3,4 },{
2,3,4,5,6},{
3,4,5,6,7} };
print(&arr, 3, 5);
return 0;
}
举例使用
#include
void print(int x)
{
printf("%d", x);
}
int main()
{
int i = 12;
print(i);
void (*pf)(int) = &print;
return 0;
#include
int Add(int x, int y)
{
return x + y;
}
int main()
{
int i = 9;
int k = 10;
int (*pf)(int, int) = &Add;
int ret=(*pf)(i, k);
printf("%d", ret);
return 0;
}
上例中 int (*pf)(int, int) = &Add;
中* 不可少 但 int ret=(*pf)(i, k);
但这个却可以改成int ret=(pf)(i, k);
甚至可以加任意*号 这是为什么呢
我们观察函数地址以及内存存放
我们发现 在vs2019编译器中函数的地址没有放在函数指针里面
我们在调试反汇编可看出 函数指针存的地址需要跳到另一个地址处 该地址存放着函数的指针 所以 函数指针很不安全 使用过程应该小心
接下来 我们研究两个经典案例
(*(void (*)())0)();//如何解读??
然后在调用该函数 及是本行代码的旨意。
总结: 调用0地址处函数 该函数无参 返回值为void。
void (*signal(int , void(*)(int)))(int);
去掉函数传参部分 就是函数返回类型 可见 函数返回类型任然是函数指针。
那么我们怎么简化这个函数声明呢。
我们可先定义一个 指针类型 pf
typedef void(*pf)(int);
注 : pf 不可写在外面 这是函数指针定义规则
那么
pf<==>void(* ) ( int );
pf signal(int, pf);
注意:
数组元素全为指针变量的数组称为指针数组,指针数组中的元素都必须具有相同的存储类型、指向相同数据类型的指针变量
可以得出结论 指针数组是有一个个指针构成的 将函数指针存放在数组中就可得到函数数组。
指针数组,含有10个指针元素 也就是说每一个元素都是指针。先是解析[]表示它是一个数组,然后*表示指针,int表示为int型指针m 即表示定义一个指针数组,含有10个int类型指针元素。
可以这样初始化:
for(int i=0; i<10;i++)
{
p[0] = &i; // 每个元素都是指针
}
如下:
int students[] = {
101, 102, 103, 104, 105, 0, 0, 0, 0, 0, 201, 202,203, 204, 0, 0, 0, 0, 0, 0, 301, 302, 303, 0, 0, 0, 0, 0, 0, 0 };
int * q = students;
3、对上面进行总结
指针是一个指向int的地址, 数值指针 是一个指向int* 值
辨析数组指针与指针数组 阿里面试题
#include
int main()
{
int i = 2;
int a[4][4] = {
0 };
int* p;
int* q[4];
//p = a;
q[i] = a[i];
p = q[i];
p = &a[2][1];
return 0;
}
因为a是错误选项 所以将a注释后 调试观察
p作为一个普通指针 不能用二维数组对其赋值 应使用数组指针
可见此题a错误。
#include "stdio.h"
void fun1(void)
{
printf("fun1 \r\n");
}
void fun2(void)
{
printf("fun2 \r\n");
}
void fun3(void)
{
printf("fun3 \r\n");
}
int main()
{
int i=0;
void (*p1)(void)=NULL;
void (*p2)(void)=NULL;
void (*p3)(void)=NULL;
void(*p_arry[3])(void)={
NULL,NULL,NULL};
p1=fun1;
p2=fun2;
p3=fun3;
p_arry[0]=p1;
p_arry[1]=p2;
p_arry[2]=p3;
for(i=0;i<3;i++)
{
(*(p_arry+i))();
}
printf("*************************\r\n");
p1();
p2();
p3();
return 0;
}
2. 函数指针数组是一个存放函数指针的数组 。本质也是数组