C语言指针与数组:从原理到多维引用的实战指南

周予安
周予安
发布时间:2026-10-16| 7人浏览过
原创

本文深入解析C语言中指针与数组的底层交互机制,涵盖指针的定义与引用逻辑。通过代码实例对比值传递与地址传递的差异,详细推导一维数组的两种遍历方式,并针对二维及多维数组的行指针与列指针变换进行图解分析,提供实用的多维数组元素访问方案。

C语言指针的核心概念与定义

C语言的指针本质上是对内存空间的管理工具。当程序定义一个变量时,系统会根据数据类型为其分配特定的内存单元。内存中的每个字节都有唯一的编号,即地址。

访问变量数据通常有两种路径:

  1. 直接访问:通过变量名直接读写其对应的内存地址。
  2. 间接访问:指针变量(如 i_pointer)中存储的是目标变量(如 i)的地址。程序先获取该地址,再根据地址找到变量所在的内存单元进行存取。

在以下示例中,p 为整型指针变量,a 为整型变量:

int *p;
int a = 3;
p = &a;      // &取地址符,将a的地址赋给p
*p = 2;      // *解引用运算符,修改p所指向地址的值(即a变为2)

指针在函数参数中的应用

在函数传参时,理解数据流向至关重要。C语言实参与形参之间的传递默认为“单向值传递”。若希望函数内部操作能改变外部变量,必须传递变量的地址。

下面通过两个变量的交换案例展示差异:

#include<stdio.h>

// 情况1:值传递(无法实现外部变量交换)
void swap1(int x, int y) {
	int z;
	z = x;
	x = y;
	y = z;
}

// 情况2:地址传递(成功交换)
void swap2(int *p1, int *p2) {
	int t = *p1;
	*p1 = *p2;
	*p2 = t;
}

/* 
注意野指针风险:若指针未初始化或指向无效内存,对其解引用可能导致崩溃。
建议对不使用的指针初始化为NULL(0地址),避免误操作保留内存区域。
*/
void swap4(int *p1, int *p2) {
	int *t = NULL;
	t = p1;
	p1 = p2;
	p2 = t;
}

int main() {
	int a, b;
	scanf("%d %d", &a, &b);
	
	// 测试swap1:仅交换副本,原值不变
	swap1(a, b);
	printf("%d %d\n", a, b); 
	
	int *p1 = &a, *p2 = &b;
	// 测试swap2:交换实际地址指向的内容
	swap2(p1, p2);
	printf("%d %d\n", a, b); 
	
	// swap4尝试交换指针本身的指向,但不会影响主函数中*a和*b的值
	swap4(p1, p2);
	return 0;	
}

一维数组与指针的操作

使用指针操作数组前,需牢记两条关键规则:
1. 首地址指一段内存空间的第一个存储单元。
2. 指针加减运算以指针指向的基类型空间大小为单位进行偏移(而非按字节)。

以下是数组输入输出的两种实现方式对比:

#include<stdio.h>
int main() {
	int a[5];
	
	// 方法一:下标法输入
	for(int i = 0; i < 5; i++) 
		scanf("%d", &a[i]);   
	
	int *p;
	p = a;           // p指向数组首地址,等价于 &a[0]
	
	// 方法二:输出-下标法
	for(int i = 0; i < 5; i++)
		printf("%d ", a[i]);
	printf("\n");
	
	// 方法三:输出-指针法
	// *(p + i) 等同于 a[i]
	for(int i = 0; i < 5; i++) 
		printf("%d ", *(p + i));		
	printf("\n");
	
	// 方法四:指针递增遍历(效率较高,需注意不要越界)
	for(p = a; p < (a + 5); p++)
		printf("%d ", *p); 
	return 0; 
}

数组名作为函数参数

当数组名作为函数参数传递时,实质上传递的是该数组首元素的地址。在函数内部,形参无论是声明为数组 a[] 还是指针 *x,编译器都将其视为指针处理。因此,对形参的操作会直接影响实参数组。

示例:将包含10个元素的数组逆序排列

#include<stdio.h>

// 形式A:数组形式接收参数
void swap(int a[], int n) {
	int h = 0, t = n - 1, m = (n - 1) / 2;
	for(h; h <= m; h++) {
		int tmp = a[h];
		a[h] = a[t]; 		// 利用地址偏移特性交换元素
		a[t] = tmp;
		t--;
	}
}

// 形式B:指针形式接收参数
void swap1(int *x, int n) {
	int *i = x;                 // 头指针
	int *j = x + n - 1;         // 尾指针
	int *p = x + (n - 1) / 2;   // 中间点指针

	for( ; i <= p; i++, j--) {
		int tmp = *i;
		*i = *j;    // 解引用后交换
		*j = tmp;
	}
}

int main() {
	int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
	swap(a, 10);            // 逆序
	for(int i = 0; i < 10; i++) printf("%d ", a[i]);
	printf("\n");
	
	swap1(a, 10);           // 再次恢复原位(因上一步已完全倒置)
	for(int i = 0; i < 10; i++) printf("%d ", a[i]);
	return 0;	
}

指针指向二维数组的解析

二维数组在内存中也是连续存放的。理解多维数组指针的关键在于区分“行指针”与“列指针”。

对于一个 a[3][4] 数组:

  • a 是行指针常量,指向第一个一维数组。执行 a + 1 时,地址增加的是一个一维数组的大小(16字节)。其类型为 int(*)[4]。
  • a[0] 是列指针常量,指向元素 a[0][0]。执行 a[0] + 1 时,地址增加一个 int 的大小(4字节)。其类型为 int*。
对象 类型 移动含义 偏移量
行指针 a + i int (*)[4] 跳向下一行 16 bytes
列指针 a[i] + j int * 跳向同一行的下一个元素 4 bytes

验证地址关系的代码示例:

#include<stdio.h>
int main() {
	int a[3][4] = {{1}, ...}; // 初始化略
	
	// 打印验证地址等效性
	// a 与 *a 数值相同(都是第0行第0列的地址),但类型不同
	printf("%d %d\n", a, *a);
	
	// 第n行第m列元素的值:*(*(a + n) + m)
	printf("%d %d\n", a[1][0], *(*(a + 1) + 0));
	return 0;
}

多维数组指针的高级应用

指向多维数组(如三维数组)的元素依然遵循上述嵌套规律。对于 a[2][3][4],其首地址 a 的类型为 int(*)[3][4],每次偏移代表跨越整个二维数组(48字节)。

为了高效处理多维数据,可以使用“指向一维数组的指针”作为函数参数:

#include<stdio.h>

// 普通列指针访问扁平化的一维序列
void avg(float *p, int n) {
	float sum = 0;
	for(int i=0; i<n; i++) sum += *(p + i);
	printf("%.2f\n", sum/n);
}

// 行指针访问二维结构(第n行)
void search(float (*p)[4], int row) {
	for(int col = 0; col < 4; col++) {
		// 相当于访问 p[row][col]
		printf("%.2f ", *(*(p + row) + col));
	}
}

int main() {
	float score[3][4] = {...}; // 数据略
	avg(*score, 12);       // 传入首行首地址(降维处理)
	search(score, 2);      // 传入二维数组名,定位第2行
	return 0;
}

以上就是C语言指针与数组操作技巧的详细内容,更多关于C语言多维数组、指针算法的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。