C++的初阶指针学习

本文详细介绍了指针的基本概念,包括其定义、不同类型、野指针的产生原因及规避方法,指针运算(+/-整数、指针关系运算),以及指针与数组、二级指针和指针数组的关系。
摘要由CSDN通过智能技术生成

1.指针的定义

        1. 指针是内存中一个最小单元的编号,也就是地址
        2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量        
故指针就是地址,口语中说的指针是指针变量
指针变量
是通过&(取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个变量就是指针变量

(a变量占用4个字节的空间,这里是将a4个字节的第一个字节的地址存放在p变量中,p就是一个之指针变量)

指针变量,用来存放地址的变量(存放在指针中的值都被当成地址处理)

  • 32位的机器上,地址是320或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节
  • 那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地

总结:

  • 指针是用来存放地址的,地址是唯一标示一块地址空间的
  • 指针的大小在32位平台是4个字节,在64位平台是8个字节(一个字节是八个比特位)

2.指针和指针类型

指针类型:

type+*

#include<stdio.h>
int main()
{
    char  *pc = NULL;//char* 类型的指针是为了存放 char 类型变量的地址。
    int   *pi = NULL;//short* 类型的指针是为了存放 short 类型变量的地址。
    short *ps = NULL;//int* 类型的指针是为了存放 int 类型变量的地址。
    long  *pl = NULL;//...
    float *pf = NULL;//....
    double *pd = NULL;//...
    return 0;
}

指针的解引用

int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	char* pc = arr;
	printf("%p\n", p);
	printf("%p\n", p + 1);

	printf("%p\n", pc);
	printf("%p\n", pc+ 1);

	int a = 0x11223344;
	char* pb = &a;
	*pb = 0; //重点在调试的过程中观察内存的变化
	int* pa = &a;
	*pa = 0;

	return 0;
}

指针类型意义:

  • 决定了指针向前或者向后走一步有多大(距离)
  • 决定了,对指针解引用的时候有多大的权限(能操作几个字节)
  • 比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

3.野指针

定义:

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

原因:

  • 指针未初始化
  • 指针越界访问
  • 指针指向的空间释放
int main()
{
	//这里的p就是一个野指针
	int* p;//p是一个局部的指针变量,局部变量不初始化的话,默认是随机值
	*p = 20;//非法访问内存
	//2.越界访问
	int arr[10] = { 0 };
	int* p = arr;
	int i = 0;
	for (i = 0; i <= 10; i++)
	{
		*p = i;
		p++;
	}
	return 0;
}
//3.指针指向的空间释放
int* test()
{
	int a = 10;
	return &a;//这里在函数取了a的地址
}
int main()
{
	int* p = test();//但是在函数结束后,a的地址也被释放了所以p指向的是空地址
	*p = 20;
	return 0;
}

如何规避野指针

  • 指针初始化
  • 小心指针越界
  • 指针指向空间释放及时放置NULL(空指针)
  • 避免返回局部变量的地址
  • 指针使用之前检查有效性

4.指针运算

指针+-整数

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int* pend = arr + 9;
	while (p <= pend)
	{
		printf("%d ", *p);
		p++;
	}
	return 0;
}

指针-指针

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d\n", &arr[9] - &arr[0]);
	return 0;
}

my_strlen(char* str)//模拟strlen函数
{
	char* start = str;
	while (*str != '\0')
	{
		str++;
	}
	return str - start;
}
int main()
{
	int len = my_strlen("abc");
	printf("%d\n", len);
	return 0;
}

指针关系运算

#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp = &values[N_VALUES]; vp > &values[0];)
{
    *--vp = 0;//运算关系,先减减在使用
}

标准规定:

允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与
指向第一个元素之前的那个内存位置的指针进行比较。

5.指针和数组

int main()
{
	int arr[10] = { 0 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);//结果与上一行一致
	return 0;
}

数组名是首元素的地址

数组与指针的联系

int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%p<==>%p\n", &arr[i], p + i);// p+i 其实是数组 arr 下标为i的地址
		*(p + i) = i+1;
	}
	printf("%d\n", 2[arr]);
	printf("%d\n", arr[2]);
	printf("%d\n", p[2]);//p[2]-->*(p+2)
	//arr[2]-->*(arr+2)——>*(2+arr)——>2[arr]
	//[]是一个操作符 2和arr是两个操作数
	//arr[2] <==> *(p+2) <==> *(2+p) <==> *(2+arr)<==>*(arr+2)
	//2[arr]<==>*(2+arr)
	return 0;
}

6.二级指针

int main()
{
	int a = 10;
	int* pa = &a;//pa是指针变量,一级指针
	//ppa就是一个二级指针变量
	int* *ppa=&pa;//pa也是个变量,&pa取出pa在内存中起始地址
	printf("%p\n", pa);
	printf("%p\n", *ppa);
	//以此类推也有***pppa......
	//*ppa==pa  *pa==a  **ppa==a  pa==*ppa
	return 0;
}

7.指针数组

int main()
{
	int arr[10];//整形数组 - 存放整形
	char ch[5];//字符数组 - 存放字符
	//指针数组 - 存放指针的数组
	int* parr[5];//整形指针的数组
	char* pch[5];//字符指针的数组
	return 0;
}

【注】:内容有不完善的地方,这仅仅是指针初阶,之后会有进阶指针会更好的讲解指针内容

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值