C学习笔记(十一):指针详解

📅 2026/8/1 5:57:24 👁️ 阅读次数 📝 编程学习
C学习笔记(十一):指针详解

一、为什么需要指针?

普通变量保存的是:

数据本身。

例如:

int a = 10;

变量a中保存:

10

但是计算机在内存中存储数据时,每个数据都有自己的存储位置。

例如:

内存: 地址 数据 0x1000 10

其中:

  • 10是数据;

  • 0x1000是数据存储的位置。

这个位置称为:

地址。


指针的作用:

通过地址直接访问内存空间。

因此:

指针可以让程序:

  • 更高效;

  • 更灵活;

  • 更方便地操作内存。


二、内存地址

1. 什么是地址?

计算机为了区分不同的内存空间,会给每个内存空间编号。

这个编号就是:

内存地址。

例如:

地址 数据 1000 20 1004 30

程序通过地址找到对应的数据。


2. 内存按字节编址

计算机中的内存:

按字节进行编号。

例如:

0x0000 0x0001 0x0002 0x0003 ...

每一个地址对应一个字节空间。


三、指针的概念

1. 什么是指针?

指针:

可以理解为地址。

地址就是指针。

例如:

变量:

int a = 10;

假设:

a所在地址: 0x1000

那么:

0x1000

就是变量a的指针。


2. 指针变量

用于保存地址的变量:

称为:

指针变量。

例如:

int *p;

表示:

定义一个指向int类型数据的指针变量p。


关系:

普通变量 a ↓ 保存数据10 指针变量 p ↓ 保存地址0x1000

四、取地址运算符 &

1. 功能

&

获取变量的地址。

例如:

int num = 10; printf("%p",&num);

输出:

num的地址

2. 使用规则

只有:

左值

才能进行取地址操作。

例如:

正确:

&a

错误:

&10

原因:

常量没有存储空间。


3. 类型变化

例如:

int a;

a类型:

int

执行:

&a

之后:

类型变为:

int *

即:

int类型指针。


五、取值运算符 *

1. 功能

*

根据地址访问对应空间的数据。

例如:

int a=10; int *p=&a;

此时:

p ↓ a的地址

使用:

*p

表示:

访问a中的数据。

结果:

10

2. 修改变量值

例如:

int a=10; int *p=&a; *p=20;

执行后:

a变为:

20

原因:

*p代表p指向的空间。


3. 类型变化

例如:

int *p;

执行:

*p

类型:

int

即:

指针类型降级。


六、指针变量定义

格式:

数据类型 *变量名;

例如:

int *p; char *q; float *r; double *s;

表示:

不同类型的指针。


指针变量大小

无论什么类型:

int * char * float * double *

指针变量本身大小都是:

8字节

因为保存的是地址。


七、野指针

1. 什么是野指针?

野指针:

未初始化的指针,或者指向已经释放空间的指针。

例如:

int *p; *p=10;

此时:

p没有指向有效空间。

程序可能崩溃。


2. 如何避免?

定义指针后:

不要直接使用。

应该:

int a; int *p=&a;

或者:

int *p=NULL;

八、空指针 NULL

空指针:

指向地址0的指针。

例如:

int *p=NULL;

表示:

p暂时不指向任何有效空间。


注意:

不能:

*p=10;

因为:

NULL地址不可访问。

会导致:

程序崩溃。


九、指针类型

不同类型指针:

int *p; char *p; float *p; double *p;

区别:

指向空间的数据类型不同。

例如:

int *p;

表示:

p指向4字节整数空间。


十、指针的算术运算

指针支持:

  • ++


  • 指针相减


1. 指针++

例如:

int *p; p++;

不是增加1字节。

而是:

增加:

sizeof(int)

个字节。

例如:

int占4字节:

地址: 1000 ↓ 1004

2. 指针--

类似:

向低地址移动。


3. 指针相减

例如:

p1-p2

得到:

两个地址之间相差多少个元素。


十一、指针操作

指针有两种操作方式。


1. 修改指针本身

例如:

p=&b;

改变:

p的指向。


2. 修改指针指向的数据

例如:

*p=100;

改变:

指向空间中的值。


示例:

int a=100; int b=200; int *p=&a; p=&b;

改变:

p指向b。

而:

*p=300;

改变:

b的值。


十二、指针作为函数参数

前面学习函数传参:

默认是:

值传递。


1. 值传递

例如:

void change(int a) { a=100; }

调用:

int x=10; change(x);

结果:

x仍然是:

10

因为:

形参只是副本。


2. 地址传递

如果想修改外部变量:

需要传地址。

例如:

void change(int *p) { *p=100; }

调用:

int x=10; change(&x);

执行后:

x=100

地址传递作用:

  • 修改函数外部变量;

  • 一个函数返回多个结果。


十三、数组与指针关系

C语言中:

数组名本质上是指向数组第一个元素的指针常量。

例如:

int a[5]={1,2,3,4,5};

数组名:

a

等价于:

&a[0]

例如:

int *p=a;

表示:

p指向数组第一个元素。


访问:

a[2]

等价于:

*(a+2)

也等价于:

*(p+2)

十四、一维数组指针传参

数组作为函数参数:

例如:

int fun(int array[],int len);

等价于:

int fun(int *array,int len);

示例:

冒泡排序函数:

void BubbleSort(int *array,int len) { }

调用:

BubbleSort(a,10);

数组地址传入函数。


注意:

数组传参时:

函数中操作的数组:

和外部数组:

是同一个空间。

因此可以直接修改数组内容。