C语言——深入理解指针(1)


在这里插入图片描述

1. 内存和地址

1.1内存

计算机把内存划分为⼀个个的内存单元,每个内存单元的⼤⼩取1个字节(1 byte)。其中,每个内存单元,相当于我们的学⽣宿舍,⼀个⼈字节空间⾥⾯能放8个⽐特位,就好⽐我们住的宿舍是⼋⼈间,每个⼈是⼀个⽐特位(bit)。

1.2地址

每个内存单元都有⼀个编号,这个编号就相当于我们宿舍房间的⻔牌号。有了门牌号,辅导员就可以快速查到我们寝室来检查卫生,而计算机有了这个内存单元的编号,CPU就可以快速找到⼀个内存空间。
⽣活中我们把⻔牌号叫地址,在计算机中我们把内存单元的编号也称为地址。
C语⾔中给地址起了新的名字叫:指针。
所以:内存单元的编号 == 地址 == 指针

计算机中的编址,并不是把每个字节的地址记录下来,⽽是通过硬件设计完成的。

2. 指针变量和地址

2.1取地址操作符&

在C语⾔中创建变量其实就是向内存申请空间。
创建一个整形变量a,向内存中申请4个字节,⽤于存放整数10,其中每个字节都有地址。
在这里插入图片描述操作符(&)-取地址操作符在这里插入图片描述
虽然整型变量占⽤4个字节,但是我们只要知道了第⼀个字节地址,顺藤摸⽠访问到4个字节的数据也是可⾏的。

2.2指针变量

存放地址的变量

#include <stdio.h>
int main()
{
 	int a = 6;
 	int* pa = &a;//取出a的地址并存储到指针变量pa中
 	return 0;
 }

2.3拆解指针类型

int a = 10; 
int* pa = a; 

*表示pa是指针变量,前面的int 则说明pa指向的对象类型是int型。

2.4解引用操作符

我们把地址用指针变量存着,应为地址是有用的。可是怎么使用呢?要拿到了地址,就可以通过地址找到地址指向的对象,然后可以操作它。
通过地址找到地址指向的对象,通过解引⽤操作符(*)来实现。
在这里插入图片描述

2.5指针变量的大小

不同位数的机器有不同的大小
32位,指针变量大小为4字节
64位,指针变量大小为8字节
这是为什么呢?
假设是32位平台下的机器,有32根地址总线,从每根地址线出来的电信号转换位0或1的数字信号,把32根地址线产生的数字信号看做成一个地址,1字节=8比特,那么就需要4个字节用来存储。
相同平台下不同类型的指针变量的大小是一样的。

3. 指针变量类型的意义

既然相同平台下不同类型的指针变量的大小是一样的,那为什么,还分int*,char*,…?不直接造一个专属指针变量型。
因为指针的解引⽤,指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)。
在这里插入图片描述
在这里插入图片描述指针 ± 整数
在这里插入图片描述
指针的类型决定了指针向前或者向后⾛⼀步有多⼤

4. const修饰指针

三种情况

const 修饰的变量,这个变量就不能被修改了。

#include <stdio.h>
int main()
{
	int m = 0;
	m = 20;//m是可以修改的
	const int n = 0;
	n = 20;//n是不能被修改的,这里报错
	int* p = &n;
	//但是指针可以修改,666,就像高启强想弄死李宏华,
	//不能亲自动手,就找老默去干。此时老默就是指针变量p
	*p = 20;
	printf("n = %d\n", n);

	return 0;
}

那修饰指针

#include <stdio.h>
int main()
{
	 int n = 20;
	 int m = 666;
	 
	int const * p = n;//1号
	const int * p = n;//2号  
	
	p = &m;
	int * const p = n;//3号 
	
	//*p = 888;
	int const * const  p = n;//4号 
	
	// p = &m
	// *p = 888;
	return 0;
}

1号和2号一样的,const 修饰 *p 即不能进行解引用操作,n的值不能改,p里的内容可以改
3号const 修饰 指针变量p, 即p里的值不能改,*p可以改,n的值可以改
4号const 修饰 *p和p,即二者都不能发生改动

结论:
const 修饰谁,谁就不能被修改了。

5. 指针运算

指针的基本运算有三种,分别是:

5.1指针± 整数

指针遍历数组

#include <stdio.h>
int main()
{
	 int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	 int *pa = &arr[0];
	 int i = 0;
	 int size = sizeof(arr)/sizeof(arr[0]);
	 for(i=0; i<size; i++)
	 {
		 printf("%d ", *(pa+i));//pa+i 这⾥就是指针+整数
 	}
	 return 0;
}

5.2指针-指针

求字符串的长度

#include <stdio.h>
int my_strlen(char *s)//求字符串的长度
{
	 char *p = s;
	 while(*p != '\0' )
	 {
	 	p++;
	 }
	 return p-s;
}

int main()
{
 	printf("%d\n", my_strlen("abc"));
	 return 0;
}

5.3指针的关系运算

#include<stdio.h>
int main()
{
	int a[] = {0,1,2};
	int *pa = a;
	int* pb = a + 1;
	if (pa < pb)
	{
		printf("pa < pb");
	}
	else
	{
		printf("pa > pb");//输出的结果
	}

	return 0;
}

6. 野指针及预防

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

导致野指针的原因 | 解决
1.指针未初始化 |||| 指针初始化
2.指针越界访问 |||| 注意界限
3.指针指向的空间释放 | 用完及时置NULL

7. assert断⾔

assert断⾔⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终⽌运⾏。assert断⾔使⽤对程序员来说是⾮常友好的。直接报出错误在第几行。
在这里插入图片描述

8. 指针的使⽤和传址调⽤

交换数字(传值)
在这里插入图片描述
实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改并不影响实参。

交换数字(传址)
在这里插入图片描述
交换数字成功。

  • 36
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我是无敌小恐龙

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

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

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

打赏作者

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

抵扣说明:

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

余额充值