C++基础_指针

内存四区

a) 代码区。代码
b) 全局区。全局的常量字符串常量“ABC” 变量
c) 栈区。系统自动开辟,系统自动释放,并不是很大
d) 堆区。动态开辟的内存,手动开辟,手动释放。大

地址

把内存以单个字节为单位,分开,每一个编号,这个编号就是地址。
a) 编号是连续的
b) 唯一的
c) 取地址运算符:&单目运算符 优先级() [],结合性右往左
int a;
&a;

首地址

一段内存空间的第一个存储单元的地址

指针变量

1.用来存放地址的变量,2.内存大小4个字节

地址是编号,一种数据
整数 int a;
字符 char c;
小数 float b;
地址 指针变量

a) 指针变量的定义

int main(){
	int a;
	float b;
	char c;
	int *p;		// 定义一个指针变量p,存的是地址。int指名指针指向的数据类型,*指名p这个变量是一个指针变量
}

b) 指针变量的赋值

int a = 5;
int *p;
p = &a;		//p指向a

c) 指针的引用

int a = 5;
int *p;
p = &a;
printf("a=%d", a);
printf("a=%d", *p);

访问a这个变量:

  1. 使用变量名,
  2. 指针访问:指针变量。取值运算符,返回某一个地址中的值,单目运算符 右到左
    注意了:再定义指针变量的时候int *p; 只是表明p是一个指针变量。而非定义的时候p则是取值p指向的内存值。
    image

补充

野指针:不能明确指向的指针变量。危险。
int *p; // p里面保存的地址不确定,p的指向不明确的,重要数据有可能被操作到
解决方法:int *p = NULL;

空指针:int* float* char* double*
void* 转换成其它的数据类型
指针变量的运算:+ - ++ -- 只是作指针的偏移,去访问地址旁边的一些内存
指针变量的加减,是以指针所指向的类型空间为单位进行偏移

int main(){
	char *p;	// 一个char占1个字节,则p + 1表示p指向的地址偏移一个字节
	int *p1;	// 一个int占4个字节,则p1 + 1表示p1指向的地址偏移4个字节
	double *p2;	// 一个double占8个字节,则p2 + 1表示p2指向的地址偏移8个字节
}

一维数组与指针

  1. 定义一个一维数组,数组名是这个数组的“首地址”
int main()
{
	int a[5];
	printf("a = %d
", a);
	printf("&a = %d
", &a);
	printf("a+1 = %d
", a + 1);
	printf("&a+1 = %d
", &a + 1);
	return 0;
}

结果:
a = 13630344
&a = 13630344
a+1 = 13630348
&a+1 = 13630364
解析:
a 指向a[0], a[0]是int元素, a的类型就是 int*
a 指向a[0] int元素, int* 4字节
&a 这个地址指向整个数组, &a的类型就是 int(*)[5];(数组的指针)

  1. 访问数组的元素:
    a) 下标法:a[0] a[1]
    b) 指针法:
int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int* p = a;	// p指向a[0]
	/*
	p指向a[0]的地址
	p+1指向a[1]的地址
	...
	p+4指向a[4]的地址
	则取地址的值,使用取值运算符* *p、*(p+1)...*(p+4)

	*/
	for (int i = 0; i < 5;++i) {
		printf("%d ", *(p + i));  // 或者这样:printf("%d ", *p++);
	}
	// 结果为:1 2 3 4 5 
	return 0;
}

一些细节解析:

  • 和 ++ 是单目运算符,优先级相同,从右往左结合
  • 是双目运算符,优先级<和++
    所以
    (p+i)要加括号,而p++不需要(p++,先p++结合,然后再与*结合)
    当然也可以这么写:
for (int i = 0; i < 5;++i) {
	printf("%d ", *(a+i));  // 这里不能用*a++,因为a是数组名,也是第一个元素的首地址,但它永远都是数组名,这个主要意义不能忽略,所以就不能去a++
	}

再次强调:
1. 数组名是这个数组的首地址
2. 首地址就是一段内存中第一个存储单元的地址

二/多维数组与指针

需要知道:三维数组的存储单元是一个二维数组,二维数组的存储单元是一个一维数组,一维数组的存储单元是一个元素
image
int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

  1. 数组名a是这个二维数组的首地址,这个数组在内存中的第一个存储单元是a[0],即这个一维数组
    a的类型是:(数组的指针)int(*)[4]; 所以a+1 偏移16字节
  2. a[0]是一维数组的数组名,a[0]指向a[0][0];
    a[0]的类型是:(int类型指针)int*; 所有a[0]+1 偏移4个字节
#include <iostream>

using namespace std;

int main()
{
	int a[2][3] = { {1, 2, 3}, {4, 5, 6} };
	printf("a[1][2] = %d
", a[1][2]);  // 结果为:6
	printf("a[1][2] = *(a[1] + 2) = %d
", *(a[1] + 2));  // 结果为:6
	printf("a[1][2] = *(a[1] + 2) = *(*(a+1) + 2) = %d
", *(*(a + 1) + 2));  // 结果为:6
	cout << *(a + 1) << endl;  // 随机内存地址 00CFFEB0
	cout << a << endl;	//  随机内存地址 00CFFEA4
	cout << *a << endl;	//  随机内存地址 00CFFEA4
	
	
	return 0;
}

int a[3][4]
a 类型是:int()[4],a指向首地址,也指向a[0]
&a 类型是:int(
)[3][4], &a指向整个数组
a[0] 类型是:int*,a[0]指向一维数组的元素
a[0][0] 类型是:int,a[0][0]是一个元素,他的类型就是int类型

image

指针数组: int*[]
数组指针: int(*)[]


请相信自己

当我们迷茫,懒惰,退缩的时候 我们会格外的相信命运 相信一切都是命中注定

而当我们努力拼搏,积极向上时 我们会格外的相信自己

所以命运是什么呢? 它是如果你习惯它 那它就会一直左右你

如果你想挣脱它 那它就成为你的阻碍 可如果你打破了它 那它就是你人生的垫脚石!


如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

原文地址:https://www.cnblogs.com/suguangti/p/15413323.html