文章目录
1 指针的概念
指针就是地址 ,就是编号
指针变量就是保持地址的变量
32位系统下,指针变量的大小是4字节
2 指针的定义和使用
#include <stdio.h>
int main()
{
int a = 10;
//需求 定义一个指针变量来保存 a的地址
//ubunqu指针定义3步骤
//1.需要保存谁的地址 将其定义形式放在此处
//2.定义一个 *和符号结合
//3.使用*和符号替换掉定义形式里面的变量名或数组名或函数名
//1. int a 2. *p 3.int *p
int *p = &a;
//ubunqu指针分析3步骤
//1 只要在定义处看到符号和*结合,这个符号一定是一个指针变量
//2 指针变量的类型 将符号拖黑剩下的类型 int *
//3 指针变量保存什么数据类型的地址 将符号和符号最近的一个*拖黑剩下的类型
//指针的使用 在使用时 对指针变量取* 得到的是取这个指针变量指向那块内存空间的值
printf("%d\n",*p);
*p = 100;
printf("%d\n", *p);
printf("%d %d\n", sizeof(p), sizeof(int *));
return 0;
}
注意:
在使用时 对一个表达式取& 会使这个表达式的类型 加一级*
在使用时 对一个表达式取* 会使这个表达式的类型 减一级*
3 指针的步长
宽度: 取指针变量指向空间的内容 取的字节数
步长 :指针变量加1 跨过的字节数
宽度== 步长
步长 = sizeof( 将符号和符号最近的拖黑剩下的类型)
int main()
{
int num = 0x01020304;
int *p1 = #
short *p2 = (short*)#
char *p3 = (char* )#
printf("%x %x %x\n",*p1,*p2,*p3);
return 0;
}
4 多级指针
int *P
int **P
int **p
对于普通指针,定义的指针类型只需要比需要保存的数据的类型多一级
int main()
{
int a = 10;
int *p = &a;
// int *p ; *q ; int **q
int **q = &p;
//int **q ; *k ; int **(*k)
int ***k = &q;
int ****j = &k;
int ***********************n = NULL;
int ************************m = &n;
printf("%d %d %d\n",*p,**q,***k);
return 0;
}
5 野指针
未初始化的指针,不能直接使用,指向是随机的,未知的
int main()
{
//野指针 - 未初始化的指针
//int a = 10;
int *p ;// p的指向是随机的 指向的内存也是随机的
//int *p = (int *)0x1000; 指针保存的地址 一定是合法的(向系统申请过空间返回的地址)
printf("%d\n",*p);
*p = 100;
printf("%d\n", *p);
return 0;
}
5 空指针
空指针: 指针被赋值为NULL
作用是作为一个标志
定义指针是赋值为NULL
使用时不为NULL
使用结束后,赋值为NULL
通过判断指针是否为NULL ,这个指针是否还在使用
int main()
{
//野指针 - 未初始化的指针
//#define NULL 0x00
int *p = NULL;// 用来作为一个标志 如果这个指针等于NULL 代表没有被使用
printf("%d\n",*p);//error
*p = 100;//error
printf("%d\n", *p);//error
return 0;
}
6 万能指针
void* 可以保存任意类型的地址
int main()
{
int a = 10;
char b = 20;
short c = 30;
//int *p =&a;
//short *q = &c;
//char *k = &b;
void * p1 = &a;//int *
void * p2 = &b;//char*
void * p3 = &c;//short*
//void x; 不可以定义
*(int*)p1 = 200; // *p1 宽度 sizeof(void)
* (char*)p2 = 10;
return 0;
}
7 const修饰的指针
const int *p == int const *p
不能修改p指向那块空间的内容 p本身的值可以改变,
int * const p ;
不能更改p指针变量本身的值 ,但是可以修改p指向那块空间的内容
const int * const p
不能修改p指向那块空间的内容,不能更改p指针变量本身的值
int main()
{
int a = 10;
int b = 0;
//const int b;
//const int *p == int const *p
// int * const p;
int const * const p = &a;
//不能通过*p去修改p指向那块空间的内容
//*p = 1000; error
//p = &b;
return 0;
}
8 指针修改实参的值-指针作为形参
想在一个函数中修改实参的值,实参必须传地址
void swap(int *x, int *y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
int main()
{
int a = 10;
int b = 20;
swap(&a,&b);
printf("a=%d b=%d\n",a,b);
return 0;
}
9 指针与数组的使用
定义一个指针变量保存数组首元素地址,既可以访问数组的每一个元素
int main()
{
int a[5] = { 1,2,3,4,5 };
int *p = a;
for (int i = 0; i < 5; i++)
{
//printf("%d ",a[i]);
printf("%d ", *(a+i));
//printf("%d ", *(p+i));
//printf("%d ", p[i]); // A[i] == *(A+i)
}
return 0;
}
10 数组作为函数形参会被退化为指针
// void print_array(int x[5])
// void print_array(int x[50000])
void print_array(int *x,int n)
{
for (int i = 0; i < n; i++)
{
//printf("%d ",*(x+i));
printf("%d ", x[i]);
}
}
int main()
{
int a[5] = { 1,2,3,4,5 };
print_array(a,sizeof(a)/sizeof(a[0]));
return 0;
}
11 指针数组
指针数组 : 本质是一个 数组 ,数组的每一个元素是指针
整型数组
int main()
{
int a = 0;
int b = 1;
int c = 2;
int * p[3] = {&a,&b,&c};//定义了一个数组 数组有3个元素 ,每个元素int*类型
/*for (int i = 0; i < 3; i++)
{
printf("%d ",*p[i]);
}*/
int **q = p;
for (int i = 0; i < 3; i++)
{
//printf("%d ", *(*(q+i)));
printf("%d ", *q[i]);
}
return 0;
}
12 数组指针
本质是一个指针,指针变量保存一个数组的地址
int main()
{
int a[5] = { 1,2,3,4,5 };
//&a
// int a[5]; *p ; int (*p)[5]
int(*p)[5] = &a;
// 指针的类型 int(*)[5] ; 保存的数据 int[5]的地址
printf("%d ",sizeof(p));
printf("%u %u\n",p,p+1);//sizeof(int[5] )
//通过数组指针可不可以访问数组的每一个元素?
//* p 特殊: 对数组指针取* 不是得到整个数组的内容,而是得到首元素地址
//如果将p看成一个行地址 对行地址取* 得到的是该行的第0列的地址
for (int i = 0; i < 5; i++)
{
printf("%d ", *(*p + i));
}
return 0;
}
13 数组指针在二维数组中使用
int main()
{
int a[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
//int [4]
int(*p)[4] = a;
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
for (int j = 0; j < sizeof(a[0]) / sizeof(a[0][0]); j++)
{
//printf("%d ", *(*(p + i) + j));
printf("%d ", p[i][j]);
}
printf("\n");
}
return 0;
}
14 指针的运算
相同类型的两指针相减得到的是两个指针之间的步长数
指针不可以做相加运算
指针可以比较 p == q p>q