历史上,指针成为C语言中内存操作的基础,提供了一种灵活的机制来有效访问数组元素和动态结构。然而,数组指针和指针数组的语法和语义经常会引起混淆。
问题:初学者程序员经常混淆数组指针(pointer to array)和指针数组(array of pointers),这会导致内存使用不当、参数传递错误以及难以构造的语法错误。
解决方案:
声明和使用的示例:
// 指向10个int的数组的指针: int (*p)[10]; int arr[10]; p = &arr; // 一个包含10个int指针的数组 int *ap[10]; for (int i = 0; i < 10; ++i) { ap[i] = &arr[i]; } // 如何通过数组指针获取元素: (*p)[2] = 5; // arr的第三个元素 // 如何使用指针数组获取值: *ap[2] = 8; // 通过ap访问arr的第三个元素
关键特性:
**int p[10]和int (p)[10]是否相同?
不。int *p[10]是一个包含10个指向int的指针的数组。int (*p)[10]是指向一个包含10个int的数组的指针。没有括号就会产生很大的混淆!
代码示例:
int arr[10]; int *p[10]; // 指针数组 int (*q)[10] = &arr; // 数组指针
*可以随意将普通的int指针赋值给类型为int (p)[10]的变量吗?
不可以。普通的int *指向一个元素,而int (*p)[10]指向一个包含10个整数的数组;这些类型在没有显式转换的情况下是不兼容的。
如何正确传递二维数组给函数?
需要明确指定第二个维度的大小:
void foo(int a[][4], int n); // n行,每行4个元素
或者使用指向数组的指针:
void bar(int (*a)[4], int n);
工程师将变量声明为int *p[10],试图将其赋值为&arr,其中arr是int arr[10],并试图像数组一样访问,导致编译错误或无效行为。
优点:
缺点:
开发者仔细使用括号:int (*p)[10],清晰理解差异,正确传递数组给函数,使用typedef简化声明。
优点:
缺点: