C初阶--指针初阶(上):什么是指针+指针类型+野指针(上)

简介: C初阶--指针初阶(上):什么是指针+指针类型+野指针(上)

☀️1. 指针是什么?


以32位机器为例,机器里面是有一根根物理的电线的,其中就包括地址线。我们假设高电平为1,低电平为0。那么32位机器中32根地址线一旦通电,电信号转换成数字信号,就可以产生2^32个这样的二进制序列,就可以作为2^32个地址,就可以管理2^32个内存单元,也就是2^32个字节的内存空间

在广阔的内存空间上,存在着很多变量,这就需要用某种方式来表示各个变量在内存中的"位置",这就是地址

e83f538889c14f468fc6fe66e0f3ce52.png

指针理解的2个要点:

1. 指针是内存中一个最小单元的编号,也就是地址

2. 平时口语中说的指针,通常指的是指针变量👇,是用来存放内存地址的变量

指针变量

我们可以通过&(取地址操作符)取出变量的内存起始地址,把地址可以存放到一个变量中,这个变量就是指针变量


单目操作符&❄️

将&运算符写在变量名之前,就可以得到该变量的地址--> &a  取出a的地址(生成指向a的指针)

int main()
{
  int a = 10;//a是整形,占用4个字节的内存空间,每个字节都有对应的地址
  int* pa = &a;
//&a - 得到的是a的地址(指针),其实得到的是a所占内存中4个字节中第一个字节的地址,pa是指针变量
  pa = 10;
  return 0;
}


🌀 总结:

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

那这里的问题是:

一个小的单元到底是多大?(1个字节)

如何编址?

经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。

对于32位的机器,假设有 32 根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0 );

那么 32 根地址线产生的地址就会是:

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000001

...

11111111 11111111 11111111 11111111

这里就有 2 的 32 次方个地址。

每个地址标识一个字节,那我们就可以给 ( 2^32Byte == 2^32/1024KB ==

2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB ) 4G 的空间进行编址。

这里我们就明白:

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

总结:

  1. 指针变量是用来存放地址的,地址是唯一标示一个内存单元的。
  2. 指针的大小在32位平台是4个字节,在64位平台是8个字节


2. 指针和指针类型🏠 

int num = 10;
p = #


要将&numnum的地址)保存到p中,我们知道p就是一个指针变量,那它的类型是怎样的呢?

我们给指针变量相应的类型。

char   * pc = NULL ;

int   * pi = NULL ;

short * ps = NULL ;

long   * pl = NULL ;

float * pf = NULL ;

double * pd = NULL ;


🏢指针的定义方式是: type + * 。


总结:


char* 类型的指针是为了存放 char 类型变量的地址。

short* 类型的指针是为了存放 short 类型变量的地址。

int* 类型的指针是为了存放 int 类型变量的地址。


指针类型的意义是什么?🚀


1.指针类型决定了,在解引用指针的时候能访问几个字节(有多大的权限)


  • int*类型指针:把一个整型变量a的地址放在一个整型指针里
int main()
{
  int a = 0x11223344;
  int* pa = &a;
  *pa = 0;
    return 0;
}


操作步骤:1.先按f10开始调试,之后像下面这样打开内存监视窗口

5fbada405f9c4e29a5351aefba48c08f.png

2.接着按下图这样继续走,发现a开始存放的是随机值,接着内存就被改成44 33 22 11的数据,至于与输入时为什么是倒着存放的不必解读,不影响接下来的步骤

dba219f630994829a0b83a01443e67bc.png

3.可以看到在经过*pa=0这一步时,也就是对a进行解引用操作,发现变量a里面存放的数据变成了00 00 00 00,

bbe720bf8f694dbfbb15dff8896ee75a.png

4.接下来做一些小改动,把&a放在一个字符指针里面去,重复1,2,3的步骤,可以发现只改a所占4个字节里面的第一个字节,改为char* pc=&a;

int main()
{
  int a = 0x11223344;
  char* pc = &a; 
  *pc = 0;
  return 0;
}

062e03c1d83c41f19592542c7ec9118d.png

 然而两边的代码差异就是指针类型,所以就是指针类型导致的结果

🚌总结:

指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节),个人的理解就是站在指针的角度考虑问题,把地址给字符指针的时候它认为它指向的就是一个字符的数据

我们可以在适当的情况下使用适当的指针类型

比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

📍一些需要注意的点:

为什么char*pc可以存放int a的地址?

答:pc是有能力把a的地址存起来的,因为pc大小是4byte,也是个指针变量,就可以存放地址

🚩警告:

以下是会出现的警告,因为&a的类型是int*,而左边是int*

1a7ea4e0c62743daa7d308391b90af6a.png


2.指针类型决定了,指针进行+1、-1的时候,一步走多远(步长)

int main()
{
  int a = 10;
  int*  pa = &a;
  char* pc = &a;
  printf("%p\n", pa);
  printf("%p\n", pa+1);
  printf("%p\n", pc);
  printf("%p\n", pc+1);
  return 0;
}


代码经过执行后可以看到差距:

22929e78799647608beb186a4049eceb.png

可以从以上代码得到总结:

3eaf7eacbed8453e9cf8c44ba0cf3dad.png

对于int*pa,它认为它指向的是整型,所以pa+n跳过n个整型

对于char*pc,它认为它指向的是字符,所以pc+n跳过n个字符

总结:指针的类型决定了指针向前或者向后走一步有多大(距离)

相关文章
|
1月前
|
C语言 C++
【C语言】指针篇-一篇搞定不同类型指针变量-必读指南(3/5)
【C语言】指针篇-一篇搞定不同类型指针变量-必读指南(3/5)
|
2月前
|
存储 Go
Go: struct 结构体类型和指针【学习笔记记录】
本文是Go语言中struct结构体类型和指针的学习笔记,包括结构体的定义、成员访问、使用匿名字段,以及指针变量的声明使用、指针数组定义使用和函数传参修改值的方法。
|
3月前
|
存储 安全 Go
深入理解 Go 语言中的指针类型
【8月更文挑战第31天】
41 0
|
4月前
|
编译器 C语言
【C语言初阶】指针篇—下
【C语言初阶】指针篇—下
|
4月前
|
存储 C语言
【C语言初阶】指针篇—上
【C语言初阶】指针篇—上
|
5月前
|
编译器 C++
函数指针和函数对象不是同一类型怎么替换
函数指针和函数对象不是同一类型,为何可替换用作同一函数的参数
|
5月前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
49 0
|
5月前
|
图形学 Windows
程序技术好文:记录类型指针
程序技术好文:记录类型指针
24 0
|
5月前
指针初阶(2)
指针初阶(2)
27 0
|
5月前
|
存储 编译器 Perl
指针初阶(1)
指针初阶(1)
29 0