C语言数组指针int(*x)[n]初始化与正确用法咨询
数组指针
int (*x)[N]用法说明 问题1解答
int (*x)[10]声明的x是一个指针变量,未初始化时它是存储随机值的野指针,不会自动指向任何含10个整数的数组,更不会自动指向数组首元素。
它和int x[10]的核心差异是类型完全不同:
int x[10]声明的x是长度为10的int数组,内存中直接分配10个连续int的存储空间(通常40字节)。数组名在多数表达式中会隐式转换为int*类型的指针,指向数组第一个int元素,步长为单个int的长度(通常4字节)。int (*x)[10]声明的x是专门指向「长度为10的int数组」的指针,本身仅占一个指针的存储空间(32位系统4字节,64位系统8字节),不会自动分配存储数组元素的内存。它的步长为所指数组的总长度(通常40字节),做+1运算时会直接跨过一整个长度为10的int数组。
问题2解答
两者的具体区别可归纳为三点:
- 内存占用不同:数组声明直接分配元素存储的内存;数组指针仅分配指针本身的存储,不包含数组元素空间。
- 可修改性不同:数组名是常量左值,不能被重新赋值;数组指针是变量,可以随时指向其他同长度的int数组。
- 指向目标不同:数组名退化后得到的指针指向单个int元素;数组指针指向的是一整个int数组。
数组指针的常见使用场景:
- 二维数组传参:C语言中二维数组作为函数形参时,标准写法就是数组指针,比如
void func(int (*arr)[10])可以直接接收int a[5][10]这类列数固定为10的二维数组,编译器会自动把二维数组名转换为指向第一行(长度为10的一维数组)的指针传入。 - 连续内存二维数组动态分配:用数组指针可以一次性申请行优先、内存连续的二维数组,比如
int (*arr)[10] = malloc(5 * sizeof(*arr));直接得到5行10列的二维数组,内存连续性好、缓存命中率高,释放时仅需一次free即可,比二级指针逐行申请的写法更简洁高效。
问题3解答
你遇到段错误的核心原因是:只声明了数组指针x,但从未给它赋值合法的内存地址——x是野指针,内部存储的是随机垃圾值,你向这个随机地址指向的内存写入数据,必然触发内存访问错误,和你访问的元素个数没有关系。
你用(*x)[i] = i的访问语法本身是正确的:x指向长度为12的int数组,对x解引用得到它指向的一维数组,数组名隐式转换为首元素指针后,配合下标[i]就能访问第i个元素,语法逻辑完全成立。
修正代码的核心是先让x指向一块合法的、足够存储12个int的内存,两种标准写法如下:
写法1:指向栈上已存在的数组
#include <stdio.h> int main() // 标准C规定main函数返回值为int,不要写void main { int arr[12]; int (*x)[12] = &arr; // 对整个数组取地址,类型和x完全匹配 int i; for(i = 0; i <= 11; i++) { (*x)[i] = i; printf("%d\n", (*x)[i]); } return 0; }
写法2:动态申请堆内存
#include <stdio.h> #include <stdlib.h> int main() { int (*x)[12] = malloc(sizeof(*x)); // 申请刚好存12个int的连续内存 if (x == NULL) return 1; // 检查内存申请是否成功 int i; for(i = 0; i <= 11; i++) { (*x)[i] = i; printf("%d\n", (*x)[i]); } free(x); // 释放堆内存 return 0; }
除了(*x)[i]之外,还有两种等价访问方式,但可读性更差,日常开发不推荐:
- 指针偏移解引用:
*(*x + i) = i,本质是对首元素地址偏移i个int长度后解引用。 - 强转偏移:
*((int*)x + i) = i,把数组指针强转为int类型指针后再偏移访问。
注意避坑:不要直接把数组名赋值给数组指针,比如int arr[12]; int (*x)[12] = arr;是类型不匹配的错误写法,正确赋值需要取整个数组的地址:x = &arr;。
内容的提问来源于stack exchange,提问作者limbo1927
相关产品推荐
相关产品推荐

