第八章 指针1

1、概念

● 每个变量都被存放在从某个内存地址(以字节为单位)开始的若干个字节中。

● “指针”,也称为“指针变量”,大小为4个字节(或8个字节)的变量,其内容代表一个内存地址。

● 通过指针,能够对该指针指向的内存区域进行读写。

● 如果把内存的每个字节都想像成宾馆的一个房间,那么内存地址相当于就是房间号,而指针里存放的,就是房间号 。

2、定义

类型名 * 指针变量名;

int * p;      //p是一个指针,变量 p 的类型是 int*
char * pc;    //pc是一个指针,变量 pc 的类型是 char*
float * pf;   //pf 是一个指针,变量 pf 的类型是 float*

3、指针的内容

int * p=(int *)40000; //类型强制转化 40000为int类型,p为指针类型

p的内容:
十进制:40000 ----> 十六进制:0x9C40

二进制每个比特 0000 0000 0000 0000 1001 1100 0100 0000

p 指向地址 40000,地址 p 就是地址 40000,*p 就代表地址 40000 开始处的若干字节的内容

4、通过指针访问其指向的内存空间

定义指针变量:

int * p = (int *)40000;

往地址 40000 处起始的若干字节的内存空间里写入 5000:
(真实操作的时候,一般报错,因为40000处可能存放的是操作系统的指令。)

*p = 5000;

将地址 40000 处起始的若干字节的内容赋值给 n:
(“若干” = sizeof(int),因为 int* p;)

int n = *p;

5、指针定义总结

T * p; //T可以是任何类型的名字,比如int,double,char等等

p的类型:T *      *p的类型:T

通过表达式 *p,可以读写从地址 p 开始的 sizeof(T) 个字节

*p 等价于存放地址 p 处的一个 T 类型的变量

* 为间接引用运算符

sizeof(T*) 4 字节(64 位计算机上可能 8 字节)

6、指针的用法

char ch1 = 'A';

char * pc = &ch1;  //使得pc指向变量ch1

&:取地址运算符 

&x:变量 x 的地址(即指向 x 的指针)

对于类型为 T 的变量 x,&x 表示变量 x 的地址(即指向 x 的指针)&x 的类型是 T*

用法:

char ch1 = 'A'; 
char * pc = &ch1; //使得pc指向变量ch1
*pc = 'B';  //使得ch1='B'
char ch2 = *pc;//使得ch2=ch1
pc = &ch2; //使得pc指向变量ch2
*pc = 'D'; //使得ch2='D'

7、指针的作用

problem:
变量的赋值直接就可以进行,为什么还有先访问地址,再去进行赋值呢,岂不多此一举?
answer:
有了指针,就有了自由访问内存空间的手段。

  • 不需要通过变量,就能对内存直接进行操作。通过指针,程序能访问的内存区域就不仅限于变量所占据的数据区域 。
  • 在 C++ 中,用指针 p 指向 a 的地址,然后对 p 进行加减操作,p 就能指向 a 后面或前面的内存区域,通过 p 也就能访问这些内存区域。

8、指针的互相赋值

不同类型的指针,如果不经过强制类型转换,不能直接互相赋值。

int * pn , char * pc , char c = 0x65;

pn = pc;  //类型不匹配,编译出错

pn = &c;  //类型不匹配,编译出错

pn = (int *)&c;

int n = *pn;  //n的值是不确定:char 一个字节  int 四个字节

*pn = 0x12345678; //编译能过但运行可能出错,从 pn 指向的位置开始四个字节写入 0x12345678,会覆盖掉原来的内容,或者操作系统根本不让访问这一块区域

9、指针的运算

  1. 两个同类型的指针变量,可以比较大小。
地址p1 < 地址p2 <=> p1 < p2值为真

地址p1 = 地址p2 <=> p1 == p2值为真

地址p1 > 地址p2 <=> p1 > p2值为真
  1. 两个同类型的指针变量,可以相减。
两个 T* 类型的指针 p1 和 p2

p1 - p2 = (地址 p1 - 地址 p2) / sizeof(T)   //p1和p2之间能存放多少个T类型的变量

例:int * p1 , * p2;

若 p1 指向地址 1000,p2 指向地址 600,则 p1 - p2 = (1000 - 600)/sizeof(int) =(1000-600) / 4 = 100
  1. 指针变量加减一个整数的结果是指针
p:T* 类型的指针

n:整数类型的变量或常量

p + n:T* 类型的指针,指向地址:p + n * sizeof(T)

n + p、p - n、*(p+n)*(p-n),含义一样
  1. 指针变量可以自增、自减
T* 类型的指针 p 指向地址 n

p++++p:p 指向 n + sizeof(T)

p----p:p 指向 n - sizeof(T)
  1. 指针可以用下标运算符 “[]” 进行运算
p 是一个 T* 类型的指针,n 是整数类型的变量或常量

p[n] 等价于 *(p + n)

10、常见运算

problem:
如何访问 int 型变量 a 前面的那一个字节?

int a;

char * p = (char *) &a; //&a 是 int* 类型

--p;  //一个字节,为char,不能直接int,所以强制转化为char

printf("%c" , *p); //可能导致运行错误,操作系统要能让访问才可以  

*p = 'A';   //可能导致运行错误 

经典应用:

#include<bits/stdc++.h>
#include<algorithm>
using namespace std;
int main()
{
	int * p1 , * p2;
	int n = 4;
	char * pc1 , * pc2;
	p1 = (int *) 100;
	p2 = (int *) 200;
	cout << p2 - p1 << endl;
	//输出 25,(200-100)/sizeof(int)=100/4=25
	pc1 = (char *) p1;
	pc2 = (char *) p2;
	cout << pc1 - pc2 << endl;
	//输出 -100,(100-200) / sizeof(char)=-100
	cout << (p2 + n) - p1 << endl;
	//输出 29,(200 + 4 * 4 - 100) / 4 
	int * p3 = p2 + n;
	cout << p3 - p1 << endl; 
	//输出 29
	cout << (pc2 - 10) - pc1 << endl;
	//输出 90,pc1 和 pc1 都为 char 类型,占一个字节 
	return 0;
}
  • 地址 0 不能访问,指向地址 0 的指针就是空指针。

  • 可以用 “NULL” 关键字对任何类型的指针进行赋值。NULL 实际上就是整数 0,值为 NULL 的指针就是空指针。

    int * pn = NULL;
    char * pc = NULL;
    int * p2 = 0;
    
  • 指针可以作为条件表达式使用。如果指针的值为 NULL,则相等于为假,值不为NULL,就相等于为真。

    if(p) <=> if(p != NULL)
    if(!p) <=> if(p == NULL)
    

11、指针作为函数参数

#include<iostream>
using namespace std;
void Swap(int * p1 , int * p2)
{
	int tmp = * p1; //p1 指向的变量的值,赋给tmp 
	* p1 = * p2;  //将 p2 指向的变量的值,赋给 p1 指向的变量 
	* p2 = tmp;  //将 tmp 的值赋给 p2 指向的变量 
}
int main()
{
	int m = 3 , n = 4;
	Swap(&m , &n);  //p1 指向 m , p2 指向 n 
	cout << m << " " << n << endl; //输出 4 3 
	return 0;
}

12、指针和数组

  • 数组的名字是一个指针常量,指向数组的起始地址

    T a[N];
    
    a 的类型是 T*,可以用 a 给一个 T* 类型的指针赋值
    
    a 是编译时其值就确定了的常量,不能够对 a 进行赋值
    
  • 作为函数形参时,T * pT p[] 等价

    void Func(int * p)
    {
    	cout << sizeof(p);
    }
    
    <=>
    
    void Func(int p[]) 
    {
    	cout << sizeof(p);
    }
    
  • 应用1

    #include<iostream>
    using namespace std;
    int main()
    {
    	int a[200];
    	int  * p;
    	p = a;  //p 指向数组 a 的起始地址,亦指向了a[0]
    	* p = 10; //a[0] = 10
    	* (p + 1) = 20; //a[1] = 20
    	p[0] = 30;  //p[i] 和 *(p+i)是等效的,使得a[0]=30 
    	p[1] = 40;  //a[4]=40
    	for(int i = 0; i < 10; i++)
    		*(p + i) = i;
    	++p; //p指向a[1]
    	cout << p[0] << endl; //输出1,p[0]等效于*p,p[0]即是a[1]
    	p = a + 6;  //p 指向a[6]
    	cout << * p << endl;  //输出6 
    	return 0;
    }
    
  • 应用2

    #include<iostream>
    using namespace std;
    void Reverse(int * p , int size)
    {
    	for(int i = 0; i < size / 2; i++)
    	{
    		int tmp = p[i];
    		p[i] = p[size - i - 1];
    		p[size - i - 1] = tmp;
    	}
    }
    int main()
    {
    	int a[5] = {1 , 2 , 3 , 4 , 5};
    	Reverse(a , sizeof(a) / sizeof(int));
    	for(int i = 0; i < 5; i++)
    		cout << *(a + i) << " "; 
    	return 0;
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zaiyang遇见

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值