定义
存储内存单元地址,变量
类型名 *变量名
int i=10; //内存开辟空间 ,i地址为 012FFB90
int *p=&i; //将i的地址存放在p变量中
使用:
指针变量的值
p : 存储的地址;
*p :地址随对应的值; //指针的解引用,通过解引用可以对指针所指向地址的值进行操作
void pointorInit()
{
int i = 10;
int* p = &i;
printf("i的地址——%p\n", &i);
printf("p的值——%p\n", p);
printf("*p的值——%d\n", *p); //指针的解引用
*p = 15;
printf("i的值——%d\n", i);
}
大小及类型
32位:4个字节
64位:8个字节
void pointorSize()
{
char* p1 = NULL;
int* p2 = NULL;
float* p3 = NULL;
double* p4 = NULL;
printf("char类型——%d\n", sizeof(p1));
printf("int类型——%d\n", sizeof(p2));
printf("float类型——%d\n", sizeof(p3));
printf("double类型——%d\n", sizeof(p4));
}
32位
类型意义
指针类型决定了指针移动的距离
void pointorMove()
{
int n = 10;
char* pc = (char*)&n;
int* pi = &n;
printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc + 1);
printf("%p\n", pi);
printf("%p\n", pi + 1);
}
char类型移动了1字节
int类型移动了4字节
野指针
指针指向位置不可知;
1.指针未初始化
默认为随机值
2.指针越界
数组越界
#include <stdio.h>
int main()
{
int arr[10] = {0};
int *p = arr;
int i = 0;
for(i=0; i<=11; i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
return 0;
}
3.指针指向的空间释放
避免
1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放即使置NULL
4. 指针使用之前检查有效性
指针操作
赋值
将地址赋给指针
解引用
*运算符给出指针指向地址上存储的值
不能解引用未初始化的指针
int *p; //未初始化的指针
*p=5; //错误
第二行的意思是把5储存在p指向的位置。
但p为被初始化,其值为一个随机值,所以5存储的位置未知。
可能不会有错,也可能会崩溃。
创建一个指针时,系统只分配了存储指针本身的内存,并未分配存储数据的内存。
在使用前一定要用已分配的地址初始化它。
还可以使用malloc()函数先分配内存
取址
指针也是变量,也有自己的地址
&运算符取出指针本身的地址
指针+-整数
指针指向地址的前移或后移,移动大小为指针类型大小与整数相乘
递增递减指针
指向数组元素的指针可以让该指针移动至数组的下一个或上一个元素
指针-指针
计算两个指针的差值,同常,求差的指针分别指向同一个数组的不同元素,差值为两元素之间的元素个数
示例
void my_strlen()
{
char s[] = "hellow";
char* p = s;
while (*p != '\0')
p++;
printf("%d\n",p - s);
}
比较
使用关系运算符可以比较两个指针的值,前提时两个指针指向相同类型的值
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许 与指向第一个元素之前的那个内存位置的指针进行比较。
指针与数组
void pointorArray()
{
int ar[10] = { 1,2,3,4,5,6,7,8,9,10 };
ar[0] = 100; //ar[0] ==> *(ar+0) ==> *(0+ar)==>0[ar]
0[ar] = 1000;
//1 数组的使用,方便人们的使用
for (int i = 0; i < 10; ++i)
{
printf("%d ", ar[i]);
}
printf("\n");
//2 数组的底层实现
for (int i = 0; i < 10; ++i)
{
printf("%d ", *(ar + i));
}
printf("\n");
//3 指针变量获取数组首地址,指针操作数组
int* p = ar;
for (int i = 0; i < 10; ++i)
{
printf("%d ", *(p + i));
}
printf("\n");
//4 2、4 等价
int* q = ar;
for (int i = 0; i < 10; ++i)
{
printf("%d ", q[i]);
}
printf("\n");
}
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许 与指向第一个元素之前的那个内存位置的指针进行比较。
二级指针
还是指针
存储指针的指针
类型名**指针名
void secondPointor()
{
int i = 10;
int* p = &i;
int** pp = &p;
printf("i的地址——%p\n", &i);
printf("p的值——%p\n", p);
printf("p的地址——%p\n", &p);
printf("pp的值——%p\n", pp);
printf("*p的值——%d\n", *p);
printf("*pp的值——%p\n", *pp);
printf("**pp的值——%d\n", **pp);
}
二级指针
存储指针地址的指针
类型名**指针名;
void secondPointor()
{
int i = 10;
int* p = &i;
int** pp = &p;
printf("i的地址——%p\n", &i);
printf("p的值——%p\n", p); //&i
printf("*p的值——%d\n", *p); //i
printf("p的地址——%p\n", &p);
printf("pp的值——%p\n", pp); //&p
printf("*pp的值——%p\n", *pp); //&i
printf("**pp的值——%d\n", **pp); //i
}
指针数组
是数组
类型名*指针名[const]
各个元素都为指针
void类型 可以定义指针,不可以定义变量
泛型指针不能进行任何操作,通过强转类型可以操作。
void voidPointor()
{
//泛型指针 void只能定义指针,且无法进行指针操作,通过强转类型可实现操作
char ch = 'A';
void* p1 = &ch; //4
printf("%c\n", *(char*)p1);
int i = 1;
void* p2 = &i;
printf("%d\n", *(int*)p2);
double d = 12.34;
void* p3 = &d;
printf("%f\n", *(double*)p3);
}
const修饰的指针
const int *p;
int const*p;
指针指向的地址的值不可改变;
const修饰的数组,只能用const修饰的指针指向
int*const p;
指针指向的地址不可改变;
const int *const p;
指针指向的地址的值不可改变和指向的地址不可改变;
最难不过坚持!