一、指针的理解与定义
1.1变量的访问方式
计算面中程序的运行都是在内存中进行的,变量也是内存中分配的空间,且不同类型的变量占用不同大小的空间。那如何问内存中变量存储的数据呢?有两种方式:直接访问和间接访问。
直接访问:直接使用变量名进行的访问,以前的程序都是采用这种方式。
int num1=10;
int num2=20;
int num3=num1+num2;
间接访问:通过指针来实现。下面看如何理解指针。
1.2内存地址与指针
在计算机内存中,每个存储单元都有一个唯一的地址(内存编号)。
通俗理解,内存就是房间,地址就是门牌号。
通过地址能找到所需的变量单元,可以说, 地址指向该变量单元,将 地址形象化地称为“指针”。 1. 变量:命名的内存空间,用于存放各种类型的数据。 2. 变量名:变量名是给内存空间取一个容易记忆的名字。 3. 变量值:在变量单元中的存放的数据值。 4. 变量的地址:变量所使用的内存空间的地址,即指针。
1.3指针和指针变量
1.指针是一种特殊的变量类型,它用于存储内存地址。
指针的实质就是内存“地址”
2.指针变量就是存储这个地址的变量。
指针变量:一个变量专门用来存放另一个变量的内存中数据的地址(即指针),则它称为“指针变量”。我们可以通过访问指针变量达到访问内存中另一个变量数据的目的。(有时为了阐述方便,将指针变量直接说成指针)
上图中 地址:0X2000 是变量i_pointer就是一个指针变量。
体会:指针就是内存地址,使用指针访问变量,就是直接对内存地址中的数据进行操作。
指针的作用:可间接修改变量的值
1.4指针变量的定义
1.指针也是一种数据类型,其类型是指针指向的内存空间的数据类型,指针变量也是一种变量,用来存储地址的变量。
语法格式:
数据类型 *指针变量名[=初始地址值]
1.数据类型 是指变量所指向变量数据类型。可以是int、char、float等基本类型,也可以是数据等构造类型。(变量)
2.字符*用于告知系统这里定义的是一个指针变量,通常跟在类型关键字的后面。(指针变量)
比如,char*表示一个指向字符的指针,float*表示一个指向float类型的值的指针。
此外,还有指向数组的指针、指向结构体的指针。
int num=10;
//-----------
int * p ;// 读作 :指向 int 的指针 或简称 int 指针
//int * p ;
//int* p ;
p=#
p=num;// 错误的
//两个都是指针变量,不正确的定义
int *p1,p2;
注意:1.指针变量的名字是p,不是*p
2.指针变量中只能存放地址,不要将一个整数(或任何其它非地址类型的数据)赋值给一个指针变量。
1.5 const修饰的指针变量
语法格式:
int a=1;
const int*p1=&a; //等价于int const*p1=&a;
int *const p2=&a;
-------------------------------------------------------------------------------------------------------------------------
1.从左往右看,跳过类型,看修饰那个字符
2.如果是*,说明指针指向的值不能修改
3.如果是指针变量,指针变量的指向不能改
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
//const修饰的指针变量
int a = 10;
//指针指向的内存的值不能直接修改
const int* p = &a; //p可以改 *p不可以改
int b = 90;
p = &b;
//*p = 900; //不能修改
printf("%d\n", *p);
//p2不能改 *p2可以改
int* const p2 = &a;
int c = 33;
//p2 = &c;//不行
*p2 = 777;//可以
//p3 *p3都不能修改
const int* const p3 = &a;
return 0;
}
1.6应用场景
场景1:使用指针访问变量或数组的元素。
场景2:应用在数据结构中。
二、指针的运算
指针作为一种特殊的类型可以参与运算,但与其他数据类型不同的是,指针的运算都是针对内存中的地址来实现的。
普通变量定义:
类型 变量;
指针变量定义:
类型 *指针变量=&变量
1.&叫取地址,返回操作数的内存地址
2.*叫解引用,指 操作指针所指向的变量的值
3.在定义变量时,*号表示所声明的变量为指针类型
(1)指针变量要保存某个变量的地址,指针变量的类型比这个变量的一个类型多一个*
4.在指针使用时,*号表示操作指针所指向的内存空间
2.1取址运算符:&
取值运算符,使用“&”符号来表示。
作用:取出指定变量在内存中的地址。
语法:&变量
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
//定义一个变量 同时赋值为10
int num = 10;
//变量的本质:当定义一个变量时,实际上向内存申请了一块空间用来存放值
//而每一个存储单元(byte),都有一个唯一的编号,叫做内存地址
//打印输出变量的地址 也就是变量所占内存的起始地址
printf("%p\n", &num); //00000012B44FF6B4
-------------------------------------------------
//定义一个指针变量 保存int a的地址
int* p;//定义了一个指针变量p
p = #//指针指向了a的地址
//p就是指针变量,指向了a的地址 *p就是a的值
printf("%d\n", *p);
printf("%p\n", p);
return 0;
}
注意:
1.在输出取址 运算获得的地址时,需要使用“%p”作为格式输出符
2.这里num的4个字节,每个字节都有地址,取出的第一个字节的地址(较小的地址)。
指针变量赋值
指针变量中只能存放地址 (指针),不要将一个整数(或任何其它非地址类型的数据)赋值给一个指针变量
C语言中的地址包括位置信息(内存编号,或称纯地址)和它所指向的数据的类型信息,即它是 ”带类型的地址“。
所以,一个指针变量只能指向同一个类型的变量,不能抛开类型随意赋值。
如: char *类型的指针是为了存放char类型变量的地址
3.在没有对指针变量赋值时,指针变量的值是不确定的,可以系统会分配一个未知的地址,此时使用此指针变量可能会导致
不可预料的后果甚至是系统崩溃。为了避免这个问题,通常给指针变量赋初值为0(或NULL),并把值为0的指针变量称为空指针变量。
重点理解
1.指针变量指向谁,就把谁的地址赋值给指针变量
2.通过*指针变量 间接修改变量的值
2.2取址运算符:*
在C语言中针对运算还提供了一个取值运算符,使用“*”符号表示。其作用与&相反,根据一个给定的内存地址取出该地址对应变量的值。也称为解引用符号
int main(){
int a=2024;
int *p;
p=&a;
printf("%p\n",&a); //地址
printf("%p\n",p);、//地址
printf("%p\n",*p);//2024
--------
printf("*&a=%d\n",*&num)// 2024
//--------------------------------------------------
//通过指针间接修改变量的值
int num = 10;
int* p = &um;//定义一个指针p 指向num的地址
*p = 20;//通过指针间接修改a的值
printf("%d\n", 20);//20
}
问题1:&*p的含义是什么?
- & 和 * 两个运算符的优先级别相同,但按自右而左方向运算。因此, &*p 与&a相同,即变量a的地址。
- 如果有p1= &*p; 它的作用是将&a(a的地址)赋给p1, 如果p1原来指向b,经过重新赋值后它已不再指向b了,而指向了a
问题2:*&a的含义是什么?
先进行&a运算,得a的地址,再进行*运算。 *&a和* p的作用是一样的,它们都等价于变量a。
即 *&a 与a等价。
2.3指针的常用运算
指针本质上就是一个无符号整数,代表了内存地址。除了取址和取值 运算外,指针还可以与整数加减、自增自减、同类指针相减运算等。但是规则并不是整数的运算
格式: 指针 + (-) 整数
指针与整数的加减运算,表示指针所指向的内存地址和移动(加,向后移动; 减,向前移动)。指针移动的单位,与指针指向的数据类型有关。 数据类型占据多少个字节,每单位就移动多少个字节。
2.3.1指针步长
指针步长指的是通过指针进行递增或递减操作时,指针所指向的内存地址相对于当前地址的偏移量。
●指针的步长取决于所指向的数据类型。
○指针加n等于指针地址加上 n 个 sizeof(type) 的长度
○指针减n等于指针地址减去 n 个 sizeof(type) 的长度