目录
1.概念
2.格式
3.指针操作符
4.初始化
1. 将普通变量的地址赋值给指针变量
a. 将数组的首地址赋值给指针变量
b. 将指针变量里面保存的地址赋值给另一个指针变量
5.指针运算
5.1算术运算
5.2 关系运算
指针的大小
总结:
段错误
指针修饰
1. const修饰
2. void
大小端
二级指针
指针和数组
1. 指针和一维数组
直接访问:
间接访问:
2. 指针和二维数组
直接访问:
间接访问:
数组指针
数组指针
定义:本质是指针,指向的是数组(又称行指针)
格式:存储类型数据类型(*指针变量名)[列数];
大小
指针的优点:
- 使程序更加简洁、紧凑、高效
- 有效的表达更复杂的数据结构
- 动态分配内存
- 得到多余一个数的函数的返回值
1.概念
地址:内存中每个字节单元都有点编号
指针:指针就是地址
指针变量:用于存放地址的变量叫做指针变量
2.格式
存储类型 数据类型 * 指针变量名
int* p;
使用:
int a=5;
int* p=&a;
char ch=‘t’;
char* p=&ch;
3.指针操作符
&:取地址符--->取变量的地址
*:取内容 --->取地址里面的内容
*&a==a;// *和&是互逆运算
// a是变量就是错的,a是地址就是对的
&*a
4.初始化
指针变量只使用前不仅要定义还要初始化,未初始化的指针变量是不能随便使用的,会产生野指针
int* p;
1. 将普通变量的地址赋值给指针变量
int a=10;
1)int* p=&a;//定义的同时赋值
2)int* p=NULL;//先定义指针变量在进行赋值
p=&a;
int* p = NULL; // int *p
p = &a;
printf("%d %d\n", a, *p); // 打印 a 的值 10 10
printf("%p %p\n", &a, p); // 打印 a 的地址
*p = 3;
printf("%d %d\n", a, *p); // 打印 a 的值 3 3
printf("%p %p\n", &a, p); // 打印 a 的地址
a. 将数组的首地址赋值给指针变量
char str[10] = "hello";
char* p = str; // 指针指向数组的首地址,指向字符'h'的地址
b. 将指针变量里面保存的地址赋值给另一个指针变量
floatf = 1.3;
float* p = &f;
float* q = p;
5.指针运算
5.1算术运算
char str[32] = "hello";
char* p = str;
p++; // 指针向高地址方向移动一个数据单位(看数据类型),指针指向发生变化
p--; // 指针向低地址方向移动一个数据单位(看数据类型),指针指向发生变化
int* p; p++;// 移动4字节
double*p; p++; // 移动8字节
p+n:访问高地址方向第n 个数据的地址,指针指向不会发生变化
p-n:访问低地址方向第n 个数据的地址,指针指向不会发生变化
偏移了多少地址(字节) = n *sizeof(数据类型)
两个地址之间的差 = 两个地址之间相隔元素的个数
q - p=两个地址之间相隔的元素个数
char str[] = "hello";
char* p = str;
char* q = p+3;
printf("%d\n", q - p);
5.2 关系运算
> < == !=
指针之间的关系运算比较的是它指向地址的高低
高地址的指针大于低地址的指针
char str[32] = "hello";
char* p1 = &str[1];
char* p2 = &str[3];
p2 > p1
注意:指向不同类型的数组指针关系运算没有意义,指向不同区域的指针关系运算也没有意义
(同一个数组间进行比较)
指针的大小
int a = 5;
int* p = &a; // 4
short b = 2;
short* p1 = &b; // 4
double c = 1.1;
double* p2 = &c; // 4
szieof(指针变量名)
32位操作系统:指针为4字节
8位16进制表示,4字节
64位操作系统:指针为8字节
16位16进制表示,8字节
总结:
1.32位操作系统:指针为4字节, 64位操作系统:指针为8字节
2. 内存地址是固定的,但是变量的地址不固定的(栈区随机分配)
3. 指针类型根据指针指向空间的数据类型
段错误
Segentation fault (core dumped
1) 野指针,没有规定指向的指针会在内存中乱指,野指针产生原因
1. 指针变量定义没赋值
2. 指针 p被 free之后,没有置 NULL,会让人以为p是合法指针
解决:int* p = NULL;
2)内存泄漏,对非法空间进行赋值
指针修饰
1. const修饰
1) const int num = 10;
const int num = 10;
num = 3;
int* p = #
*p = 3; // 可以
2)const int *p;//修饰*p,指针指向的内容不能更改,指针指向可以修改
int const *p; //也可以这样修饰*p
int num=10;
const int* p=&num;
*p=20;//错误,因为*p被修饰
int sum=20;
p=&sum;//可以
3)int* const p;//修饰p,指针的指向不能修改,但是指针指向的内容可以修改
int num=10;
int sum=20;
int* const p=&num;
p=*sum;//错误
*p=20;//可以
4)修饰函数参数
2. void
void num;//不允许修饰变量
void* p; //p是任意类型的指针,需要强转才能使用
使用场景:函数参数或者函数返回值
注意:通过void类型指针进行取内容,需要对地址进行强转
强转方式:void* p=NULL;强转(int*)p 取内容*((int* )p)
大小端
TCP协议(三次握手四次挥手){网编时应用}
在计算机进行超过1字节数据进行储存时,会出现存储数据顺序不同的情况即大小端储存
Big-Endian(大端字节序)大端:在低地址存放高字节数据,高地址存放低字节数据
Little-Endian(小端字节序)小端:在低地址存放低字节数据,高地址存放高字节数据
举例:存储数据 0x12345678,起始地址 0x4000
0x4000 0x4001 0x4002 0x4003
大端:0x12 34 56 78
小端:0x78 56 34 12
查看电脑是大端还是小端,代码如下:
int a = 0x12345678;
char b;
b = (char)a;
printf("%#x\n", b);
// 电脑是小端,网络是大端
// 电脑向网络传输东西,数据要从小端变成大端,传出去
// 网络向电脑传输东西,数据要从大端转成小端,接收过来
二级指针
一级指针:存放变量地址
二级指针:存放的是一级指针的地址
格式: 存储类型 数据类型 **指针变量名
int num = 10;
int *p = #
int **q = &p;
访问 num 的值:
num *p **q
访问 num 的地址:
&num p *q
访问 p 的地址:
&p q
指针和数组
直接访问:按变量的地址存取变量的值(通过数组名访问)
间接访问:通过存放变量地址的变量去访问变量(通过指针访问)
1. 指针和一维数组
int a[5] = {1, 2, 3, 4, 5};
int *p = arr;
直接访问:
int a[5] = {1, 2, 3, 4, 5};
int *p = a;
printf("%p %p %p\n", a, a+1, a+3); // 直接访问元素的地址
printf("%d %d\n", a[1], *(a+1));
间接访问:
int a[5] = {1, 2, 3, 4, 5};
int *p = a;
printf("%p %p %p\n", a, a+1, a+2);
printf("%p %p %p\n", p, p+1, p+2);
printf("%d %d %d\n", *p, *(p+1), *(p+2));
printf("%d %d %d\n", p[0], p[1], p[2]);
a 和 p 本质上不同,a地址常量, p是变量,a不能执行 ++ 操作,但是 p 可以
访问数组元素a[i]的值:
直接访问:a[i] *(a+i)
间接访问:p[i] *(p+i)
访问数组元素a[i]的地址:
直接访问:&a[i] a+i
间接访问:&p[i] p+i
inta[3] = {3, 2, 1};
int *p = a;
printf("%d\n", *p++);// 3在打印一次的话就是 2
printf("%d\n", *a++); //错误,a地址常量
运算方法:
1) ++和 *都是单目运算符,优先级相同
2) 单目运算符从右向左进行运算
int a[3] = {3, 2, 1};
int *p = a;
printf("%d\n",下列打印);
*(p++)// 3实际上指针指向到了第二个元素的地址
(*p)++// 打印出来是 3,实际上第一个元素值变成 4
++*p // 打印出来 4,自加完之后的值
++(*p) // 同上
*++p; // 2,先将指针向高地址方向移动一个数据单位,然后取地址内容
*(++p); // 同上
2. 指针和二维数组
int a[2][3]= {1, 2, 3, 4, 5, 6}; // a:数组名:表示第一行的首地址,a+1:第二行首地址
在a前面加*,表示将行地址降级为列地址
*a+0:第一行第一列的地址
*a+1:第一行第二列的地址
*(a+1):第二行第一列的地址
*(a+1)+1:第二行第二列的地址
a[0]:第一行第一列的地址
a[0]+1:第一行第二列的地址
a[1]:第二行第一列的地址
a[1]+1:第二行第二列的地址
直接访问:
间接访问:
数组指针
数组指针
定义:本质是指针,指向的是数组(又称行指针)
格式:存储类型数据类型(*指针变量名)[列数];
int a[2][3] = {1, 2, 3, 4, 5,6};
int (*p)[3] = a;
p:int (*)[3]; 运算三个三个运算
p可以代替a进行元素访问,但是本质不同
访问 a[i][j]的地址:
*(p+i)+j &p[i][j]p[i]+j
访问a[i][j]的元素
*(*(p+i)+j) *(p[i]+j)p[i][j]
大小
sizeof(p) ==4