【C语言】深入浅出理解指针及内存与指针的关系(详细讲解+代码展示)上

简介: 笔记

概述


指针,是C语言中的一个重要概念及其特点,也是掌握C语言比较困难的部分。指针也就是内存地址,指针变量是用来存放内存地址的变量,在同一CPU构架下,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的储存空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。


为了了解指针,我们首先需要讲解一下内存的概念。


内存

内存含义

存储器:在计算机的组成中,用来存储程序和数据,辅助CPU进行运算处理的重要部分。

内存:内部存贮器,暂存程序/数据——掉电丢失 SRAM、DRAM、DDR、DDR2、DDR3。

外存:外部存储器,长时间保存程序/数据—掉电不丢ROM、ERRROM、FLASH(NAND、NOR)、硬盘、光盘。


4.jpeg


内存是沟通CPU与硬盘的桥梁


内存作用:

暂存放CPU中的运算数据

暂存与硬盘等外部存储器交换的数据

5.jpeg


物理存储器和存储地址空间

有关内存的两个概念:物理存储器和存储地址空间。


物理存储器:实际存在的具体存储器芯片。

主板上装插的内存条

显示卡上的显示RAM芯片

各种适配卡上的RAM芯片和ROM芯片

我们所有的数据都存在内存中,对每一个物理存储单元,分配一个单元,我们称之为编码,可以根据分配的号码找到相应的存储单元,也称为寻址 。


存储地址空间:对存储器编码的范围。

编码:对每个物理存储单元(一个字节)分配一个号码 。

寻址:可以根据分配的号码找到相应的存储单元,完成数据的读写 。

6.jpeg


内存地址

在这里,我们将内存抽象成一个很大很大的一维字符数组。编码就是对内存的每一个字节去分配一个32位或64位的编号(位数与自己的处理器有关)。儿这个内存编号我们称其为内存地址。       内存中的每一个数据都会分配相应的地址,例如:char:占一个字节,分配一个地址 。int:占四个字节分配四个地址等。

7.png



指针和指针变量

内存区中的每一个字节都是有一个编号的,这个编号就是“地址”。如果我们在程序中定义了一个变量,在对这个程序进行编译或者运行的时候,系统会自动给这个变量分配内存单元,确定其地址。


我们将要学习的指针就是内存单元的编号,而指针变量就是存放地址的一个变量。我们平时通常会把指针变量称作指针,但是指针变量与指针的含义是完全不同的。

8.png



从这张图中就可以看出,b_point是指针,其存放了变量b的内存地址,也就是指针变量。


指针基础知识

上面我们了解完了内存以及内存和指针关系之后,那么接下来我们就来开始指针的学习吧!


指针变量的定义和使用

首先我们不要将指针想象的那么特殊,指针就是是一种数据类型,而指针变量也是一种变量,指针变量只想谁,就把谁的地址赋值给指针变量。我们使用“ * ”操作符操作指针变量指向的内存空间。而我们平时使用指针,主要是因为使用指针往往可以生成更高效、更紧凑的代码。


声明一个指针

上面说到指针就是一个变量所以,指针的声明方式与一般的变量声明方式没太大区别:

int *p ;        // 声明一个 int 类型的指针 p
char *p ;      // 声明一个 char 类型的指针 p
int *arr[10]   // 声明一个指针数组,该数组有10个元素,其中每个元素都是一个指针。
int (*arr)[10] // 声明一个数组指针,该指针指向一个 int 类型的一维数组
int **p;       // 声明一个指针 p ,该指针指向一个 int 类型的指针,也就是我们的二级指针。

初始化一个指针

声明一个指针变量并不会自动分配任何内存。在对指针进行间接访问之前,指针必须进行初始化,或是使他指向现有的内存,或者是给他动态分配内存,否则我们并不知道指针指向哪儿,这将是一个很严重的问题,也是我们后面所提到的野指针。所以我们在定义指针后一定要进行初始化,而初始化操作具体如下


方法1:使指针指向现有的内存  

int n = 1;
int *p = &n;  // 指针 p 被初始化,指向变量 x ,其中取地址符 & 用于产生操作数内存地址

方法2:动态分配内存给指针

int *p ;
p = (int *)malloc(sizeof(int) * 10) ;    // malloc 函数用于动态分配内存
free(p) ;    // free 函数用于释放一块已经分配的内存,常与 malloc 函数一起使用。

总结:

#include <stdio.h>
int main()
{
  int a = 0;
  char b = 100;
  printf("%p, %p\n", &a, &b); //输出a, b的地址
  //int * 代表是一种数据类型,int*指针类型,p才是变量名
  int *p;
  p = &a;//将a的地址赋值给变量p,p也是一个变量,值是一个内存地址编号
  printf("%d\n", *p);//p指向了a的地址,*p就是a的值
  char *p1 = &b;
  printf("%c\n", *p1);//*p1指向了b的地址,*p1就是b的值
  return 0;
}

附: &可以取得一个变量在内存中的地址。但是不能取寄存器变量,因为寄存器变量不在内存里,而在CPU里面,所以是没有地址的。

所以这里将上面所讲的部分总结为代码,也希望大家都可以去看懂并理解这些内容。

#include <stdio.h>
int main()
{
  int a = 0 ;
  int b = 11 ;
  int *p = &a ;
  *p = 100 ;
  printf("a = %d, *p = %d\n", a, *p) ;
  p = &b;
  *p = 22;
  printf("b = %d, *p = %d\n", b, *p) ;
}

运行结果:9.png


指针大小

测量指针大小时我们需要使用sizeof()。


sizeof()是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小。


sizeof 运算符可用于获取类、结构、共用体和其他用户自定义数据类型的大小。其使用语法如下:


sizeof (data type)

其中,data type 是要计算大小的数据类型,其实包括类、结构、共用体以及其他用户自定义数据类型。


并且sizeof()测的是指针变量指向存储地址的大小,在32位平台,所有的指针(地址)都是32位(4字节),同理在64位平台,所有的指针(地址)都是64位(8字节) 。

#include <stdio.h>
int main()
{
  int *p1;
  int **p2;
  char *p3;
  char **p4;
  printf("sizeof(p1) = %d\n", sizeof(p1));
  printf("sizeof(p2) = %d\n", sizeof(p2));
  printf("sizeof(p3) = %d\n", sizeof(p3));
  printf("sizeof(p4) = %d\n", sizeof(p4));
  printf("sizeof(double *) = %d\n", sizeof(double *));
}

运行结果10.png

其中我们可以看出,我们在定义了多级指针之后,通过输出发现,其内存大小是相同的,所以内存大小是不受指针级数的影响。


相关文章
|
10天前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
24 3
|
4天前
|
存储 C语言
C语言32位或64位平台下指针的大小
在32位平台上,C语言中指针的大小通常为4字节;而在64位平台上,指针的大小通常为8字节。这反映了不同平台对内存地址空间的不同处理方式。
|
4天前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
4天前
|
存储 C语言
C语言指针与指针变量的区别指针
指针是C语言中的重要概念,用于存储内存地址。指针变量是一种特殊的变量,用于存放其他变量的内存地址,通过指针可以间接访问和修改该变量的值。指针与指针变量的主要区别在于:指针是一个泛指的概念,而指针变量是具体的实现形式。
|
5天前
|
C语言
C语言指针(3)
C语言指针(3)
9 1
|
5天前
|
C语言
C语言指针(2)
C语言指针(2)
9 1
|
11天前
|
编译器 程序员 C语言
深入C语言:动态内存管理魔法
深入C语言:动态内存管理魔法
|
11天前
|
C语言
深入C语言指针,使代码更加灵活(三)
深入C语言指针,使代码更加灵活(三)
深入C语言指针,使代码更加灵活(三)
|
6天前
|
C语言
保姆级教学 - C语言 之 动态内存管理
保姆级教学 - C语言 之 动态内存管理
11 0
|
10天前
|
存储 C语言
C语言指针(1)
C语言指针(1)
20 0