首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【C语言】指针进阶1:数组与指针

【C语言】指针进阶1:数组与指针

作者头像
苏兮
发布2026-01-13 17:04:01
发布2026-01-13 17:04:01
1360
举报

C语言学习

前言:

经过上篇文章【指针基础】,咱们对指针有了基础的了解,所以这文章就来深入学习指针。所以这篇文章适合有一定指针基础的学习。

一、字符指针

在指针的类型中我们知道有一种指针类型为字符指针 char* ; 一般我们这样用:

代码语言:javascript
复制
int main()
{
	char ch = 'c';
	char* pc = &ch;
	*pc = 'c';
	return 0;
}

咱们来看另外一种使用方式:

代码语言:javascript
复制
int main()
{
	const char* pstr = "hello world";//这里是把一个字符串放到pstr指针变量里了吗?
	printf("%s\n", pstr);
	return 0;
}

输出:

在这里插入图片描述
在这里插入图片描述

解释:

const char* pstr = "hello world"并不是将一整个字符串放到指针变量中,而是将常量字符串hello world的首字符的地址放到指针变量中。

有了这个理解,那咱们来看一下下面这串代码输出值为?

代码语言:javascript
复制
#include <stdio.h>
int main()
{
	char str1[] = "hello world";
	char str2[] = "hello world";
	const char* str3 = "hello world";
	const char* str4 = "hello world";

	if (str1 == str2)
		printf("str1 and str2 are same\n");
	else
		printf("str1 and str2 are not same\n");
	if (str3 == str4)
		printf("str3 and str4 are same\n");
	else
		printf("str3 and str4 are not same\n");
	return 0;
}

输出:

请添加图片描述
请添加图片描述

可能看到这里有点蒙,咱们来看一下详解吧: 对于str1str2:

这是两个独立的字符数组初始化 编译器会为每个数组在栈上分配新的内存空间 虽然内容相同,但 str1 和 str2 是不同的内存地址 所以 str1 == str2 比较的是地址,结果为假

对于str3str4

这是两个指向字符串常量的指针 编译器会将相同的字符串字面量合并存储(存储在只读数据段) str3 和 str4 都指向同一个内存位置 所以 str3 == str4 比较的是地址,结果为真

咱们再来看一下这个const的作用,去掉它可以吗?

答案是不推荐,虽然它有时可以通过编译,但是不建议这样做,原因:

  • 字符串常量的本质是只读的,修改字符串常量是未定义行为;
  • 违背编程意图,降低代码安全性
  • 失去编译器保护,可能引发运行时崩溃

二、指针数组

【指针基础】篇我们也学了指针数组,指针数组是一个存放指针的数组。 这里我们主要是再回顾一边, 看一下下面指针数组是什么意思?

代码语言:javascript
复制
int* arr1[10]; 
char* arr2[4]; 
char** arr3[5];

咱们依次来看:

代码语言:javascript
复制
int* arr1[10];//拆分

arr[10];//数组,且有10个元素
int* ;//数组中元素类型都为int*
int* arr1[10];//合起来为整形指针数组
代码语言:javascript
复制
char* arr2[4]; //拆分

arr2[4]//数组,且有4个元素
char* ;//数组中元素类型都为char*
char* arr2[4];//即为字符型指针数组
代码语言:javascript
复制
char** arr3[5]; //拆分

arr3[5]//数组,且有5个元素
char** ;//数组中元素类型都为char**
char** arr3[5];//即为二级字符型指针数组

三、数组指针

3.1、数组指针的定义

首先,明白一个点,数组指针是数组还是指针? 我的回答是:指针。 我们前面说过int*指向整型数据的指针…… 那数组指针就是指向数组的指针,那应该用代码字母表示呢:

代码语言:javascript
复制
int *p1[10];
int (*p2)[10];
//那个是数组指针呢?

解释

int (*p2)[10];是数组指针,因为p2先和结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p2是一个指针,指向一个数组,叫数组指针; int *p1[10];咱们前面已经见过了,指针数组嘛。但咱们也可以在分析一下,p1先于[10]结合,说明是大小为10个元素的数组,再于int*结合,说明数组里面的元素都为int类型的,故为整形指针数组; 还要知道一个点:[]的优先级要高于*号的,所以必须加上()来保证p2先和*结合。

3.2、&数组名VS数组名

对于

代码语言:javascript
复制
int arr[10];

来说,&arrarr,有什么区别呢,咱们直接来看代码:

代码语言:javascript
复制
#include<stdio.h>

int main()
{
	int arr[10];
	printf(" arr = %p\n", arr);
	printf("&arr = %p\n", &arr);
	return 0;
}

输出:

请添加图片描述
请添加图片描述

可见,两者在数值上是一样的,那么两者代表的意思也是一样的吗? 再看一串代码:

代码语言:javascript
复制
int main()
{
	int arr[10];
	printf("arr   = %p\n", arr);
	printf("arr+1 = %p\n", arr+1);

	printf("&arr  = %p\n", &arr);
	printf("&arr+1= %p\n", &arr+1);
	return 0;
}

输出:

请添加图片描述
请添加图片描述

看到这里,我们发现,其实&arr和arr,虽然值是一样的,但是意义应该不一样的。 数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40 总结: &arr 表示的是数组的地址,而不是数组首元素的地址。 那咱们再来看一下:本例中 &arr 的类型是

解释: int(*)[10] ,是一种数组指针类型:表示"指向包含 10 个整数的数组的指针"。

3.3、数组指针的使用

那数组指针是怎么使用的呢? 既然数组指针指向的是数组,那数组指针中存放的应该是数组的地址。 看代码:

代码语言:javascript
复制
#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
	//但是我们一般很少这样写代码,因为没有什么意义
	return 0;
}

咱们来看一个数组指针的使用吧:

代码语言:javascript
复制
#include<stdio.h>

void print_arr( , int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}

int main()
{
	int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
	print_arr(arr, 3, 5);
	return 0;
}

针对上面的代码,咱们来思考对于printf_arr函数的第一个参数怎么设置? 第一个肯定这样想的

代码语言:javascript
复制
void print_arr(int arr[3][5], int row, int col)//传的是二维数组的数组名,用二维数组接收

那另外的方法怎么想的,在这里,咱们要明白一个点:

数组名arr,表示首元素的地址 但是二维数组的首元素是二维数组的第一行 所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址 可以数组指针来接收

所以,咱们也可以这样写:

代码语言:javascript
复制
void print_arr(int (*arr)[5], int row, int col)

四、数组参数、指针参数

在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?

4.1、一维数组传参

咱们来看一下下面代码中test1test2函数参数有没有问题?

代码语言:javascript
复制
#include <stdio.h>
void test1(int arr[])
{
}
void test1(int arr[10])
{
}
void test1(int* arr)
{
}
void test2(int* arr[20])
{
}
void test2(int** arr)
{
}
int main()
{
	int arr[10] = { 0 };
	int* arr2[20] = { 0 };
	test1(arr);
	test2(arr2);
	return 0;
}

解释:

代码语言:javascript
复制
void test1(int arr[])//没问题,传什么用什么接收就行
{
}
void test1(int arr[10])//也没问题,这个10有没有都行(编译器忽略数组长度)
{
}
void test1(int* arr)//一维数组数组名就是首元素地址,用指针接受没什么问题
{
}
void test2(int* arr[20])//没问题
{
}
void test2(int** arr)//数组名就是首元素地址,首元素又是一级指针,所以没问题
{
}

4.2、二维数组传参

咱们来看一下下面代码中test2函数参数有没有问题?

代码语言:javascript
复制
void test(int arr[3][5])
{
}
void test(int arr[][])
{
}
void test(int arr[][5])
{
}
void test(int* arr)
{
}
void test(int* arr[5])
{
}
void test(int (*arr)[5])
{
}
void test(int** arr)
{
}
int main()
{
	int arr[3][5] = { 0 };
	test(arr);
}

解释:

代码语言:javascript
复制
void test(int arr[3][5])//没问题
{
}
void test(int arr[][])//错误
{
}
void test(int arr[][5])//没问题
{
}
//二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。

void test(int* arr)//错误
{
}
void test(int* arr[5])//错误
{
}
void test(int (*arr)[5])//没问题
{
}
void test(int** arr)//错误
{
}
//数组名arr,表示首元素的地址
//但是二维数组的首元素是二维数组的第一行
//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
//要用数组指针来接收,即int (*arr)[5]
int main()
{
	int arr[3][5] = { 0 };
	test(arr);
}

4.3、一级指针传参

主要看一下应用,看代码:

代码语言:javascript
复制
#include <stdio.h>
void print(int* p, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d\n", *(p + i));
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9 };
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	//一级指针p,传给函数
	print(p, sz);
	return 0;
}

4.4、二级指针传参

也是主要看一下应用,看代码:

代码语言:javascript
复制
#include <stdio.h>
void test(int** ptr)
{
	printf("num = %d\n", **ptr);
}
int main()
{
	int n = 10;
	int* p = &n;
	int** pp = &p;
	test(pp);
	test(&p);
	return 0;
}

总结

  • 数组名多数情况退化为指针(除 sizeof& 操作)
  • 理解 []* 的优先级差异(int* p[10] 是指针数组,int (*p)[10] 是数组指针)
  • 二维数组名是“行指针”,需用数组指针接收

附录

上文链接

《指针基础:为什么说指针是C语言的灵魂?》

下文链接

《指针进阶2:数组、指针、函数》

专栏

C语言专栏

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-08-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • C语言学习
  • 前言:
  • 一、字符指针
  • 二、指针数组
  • 三、数组指针
    • 3.1、数组指针的定义
    • 3.2、&数组名VS数组名
    • 3.3、数组指针的使用
  • 四、数组参数、指针参数
    • 4.1、一维数组传参
    • 4.2、二维数组传参
    • 4.3、一级指针传参
    • 4.4、二级指针传参
  • 总结
  • 附录
    • 上文链接
    • 下文链接
    • 专栏
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档