C语言初阶--指针

1. 指针是什么?

* 1. 指针是内存中一个最小的单元的编号,也就是地址.
* 2. 平时口语中说的指针,通常指的是指针变量,用来存放内存地址的变量.
* 总结:
	* 指针变量是用来存放地址的变量,地址是唯一标示一块地址空间的.
	* 指针的大小,在32位平台是4字节,在64位平台是8字节.

> 内存空间如何管理?
> 切割成内存的单元 - 1byte(字节)
> 把内存单元编号就称为地址(地址也叫指针).
> 指针其实就是地址,地址就是编号.
#include <stdio.h>
int main()
{
	int a = 0;
	int* pa = &a;
	//pa是指针变量,存放a的地址;
	return 0;
}

2. 指针和指针类型

2.1. 指针类型


char* pc = NULL;	//char*类型的指针是为了存放char类型变量的地址.
int* pi = NULL;		//int* 类型的指针是为了存放int 类型变量的地址.
short* ps = NULL;	//short* 类型的指针是为了存放short 类型变量的地址.
long* pl = NULL;	//long* 类型的指针是为了存放long 类型变量的地址.
float* pf = NULL;	//float* 类型的指针是为了存放float 类型变量的地址.
double* pd = NULL;	//double* 类型的指针是为了存放double 类型变量的地址.

  • X86 - 32位的环境
  • X64 - 64位的环境
  • sizeof返回的值的类型是无符号整型 unsigned int %zu
  • 0x表示是16进制数字,1个16进制数字转换为4个2进制数字

2.2. 指针类型的意义

1.指针类型决定了指针在被解引用的时候访问几个字节.
如果是int的指针,解引用访问4个字节
如果是char
的指针,解引用访问1个字节
2.指针的类型决定了指针±1操作的时候,跳过几个字节.
决定了指针的步长
如果是int* pi的指针,pi+1跳过4个字节
如果是char* pc的指针,pc+1跳过1个字节

#include <stdio.h>

int main()
{
	int n = 10;
	//0x0054f8c8
	char* pc = (char*)&n;
	//0x0054f8c8
	int* pi = &n;
	//0x0054f8c8
	printf("%p\n", &n);//0x0054f8c8
	printf("%p\n", pc);//0x0054f8c8
	printf("%p\n", pc+1);//0x0054f8c9
	//pc 是char* 类型的指针,+1,跳过1个字节
	printf("%p\n", pi);//0x0054f8c8
	printf("%p\n", pi+1);//0x0054f8cc
	//pi 是int* 类型的指针,+1,跳过4个字节
	return 0;
}

3. 野指针

  • 野指针:指针指向的位置是不可知的(随机的,不确定,没有明确限制的).

3.1. 野指针成因

3.1.1. 未初始化

int* p;//p没有初始化,就意味着没有明确的指向
//一个局部变量不初始化,放的是随机值.
*p = 10;//非法访问内存,这里的p就是野指针.

3.1.2. 超过数组范围,越界访问

int* arr[10]={0};
int* p = arr;//&arr[0]
int i = 0;
for(i=0;i<=10;i++)
{
	//0~10--循环11次,arr[10] -形成越界访问!
	*p=i;
	p++;
}

3.1.3. 指针指向的空间释放

int* test()
{
	int a = 10;
	return &a;
}

int main()
{
	int* p = test();//野指针
	return 0;
}

3.2. 规避野指针

  • 1.指针初始化
  • 2.小心指针越界
  • 3.指针指向空间释放及时置NULL
  • 4.避免返回局部变量的地址
  • 5.指针使用之前检查有效性
	int* p = NULL; //空指针
	
	//*p = 100;//err
	
	//建议
	if(p != NULL)
	{
		*p = 100;
	}

4. 指针运算

4.1. 指针±整数

	*p++;
	//*p;
	//p++;
	(*p)++;
	//(*p)解引用的值+1;
int main()
{
	int arr[10] = {0};
	int i = 0;
	int sz = sizeof(arr)/ sizeof(arr[0]);
	//数组下标写法
	//for(i = 0; i < sz;i++)
	//{
	//	arr[i] = 1;
	//}
	
	/*int* p = arr;
	for(i = 0; i < sz; i++)
	{
		*p = 1;
		p++;
	}*/
	
	int* p = arr;
	for(i = 0; i < sz; i++)
	{
		*(p + i) = 1;
	}
	return 0;
}

4.2. 指针 - 指针

* 指针 - 指针得到的指针和指针之间的元素个数
* 注:
	* 不是所有的指针都能相减,只有指向同一空间的2个指针才可以.
	&arr[9]-&arr[0]==9
//指针-指针求字符串长度
int my_strlen(char* str)
{
	int* start = str;
	while(*str != '\0')
	{
		str++;
	}
	return (str-start);
}

4.3. 指针的关系运算

  • 标准规定:
    允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,
    但是不要允许与指向第一个元素之前的那个内存位置的指针进行比较.

5. 指针和数组

  • 数组名表示的是数组元素的首地址.(除了2个例外:sizeof,&)
int arr[10]={1,2,3,4,5,6,7,8,9,0};
int* p = arr;	//p存放的是数组首元素的地址

//通过指针来访问数组
for(i = 0; i < sz; i++)
{
	printf("%d ",*(p + i));
	//p+i--计算的是arr下标
	//printf("%d ",*(arr + i));
	//arr表示首元素地址
	//arr[i]-->*(arr+i)
}

6. 二级指针

  • 二级指针是存放一级指针变量的地址.
	int a = 10;
	
	int* pa = &a;//pa是一个指针变量,一级指针变量
	//* 表示是指针,int 表示,pa指向int 类型的变量
	
	int** ppa = &pa;//ppa是一个二级指针变量
	//   *--ppa是指针
	//int* ----ppa指向的对象是int* 类型
	
	*ppa;//对ppa中的地址进行解引用,找到pa
	**ppa;//先通过*ppa找到pa,然后对pa进行解引用操作,找到a
	

7. 指针数组

  • 存放指针的数组就是指针数组.
	int a = 10;
	int b = 20;
	int c = 30;
	
	int* pa = &a;
	int* pb = &b;
	int* pc = &c;
	
	int arr[10];
	
	int* parr[10] = { &a, &b, &c };
	//parr[]数组,指向int* 
	
	int arr1[4] ={ 1, 2, 3, 4};
	int arr2[4] ={ 2, 3, 4, 5};
	int arr3[4] ={ 3, 4, 5, 6};
	
	int* parr[3] = { arr1, arr2, arr3 };
	
	for(int i = 0; i < 3; i++)
	{
		for(int j = 0;j < 4; j++)
		{
			prntf("%d ",parr[i][j]);
		}
		printf("\n");  
	}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

婧婧子♔♔♔

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

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

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

打赏作者

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

抵扣说明:

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

余额充值