编程C开发者

解释一下C语言中数组指针(pointer to array)和指针数组(array of pointers)的工作细节。如何正确声明、使用和区分它们?

用 Hintsage AI 助手通过面试

答案。

历史上,指针成为C语言中内存操作的基础,提供了一种灵活的机制来有效访问数组元素和动态结构。然而,数组指针和指针数组的语法和语义经常会引起混淆。

问题:初学者程序员经常混淆数组指针(pointer to array)和指针数组(array of pointers),这会导致内存使用不当、参数传递错误以及难以构造的语法错误。

解决方案:

  • 数组指针(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)[N]表示指向N个元素数组的指针(p只有一个内存)。
  • 类型int *a[N]表示一个包含N个指针的数组,每个指针指向某个地方(例如,一行)。
  • 括号的语法和优先级:int (*p)[N],而不是int *p[N]!

有陷阱的问题。

**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简化声明。

优点:

  • 安全且清晰的代码,没有类型错误。

缺点:

  • 冗长的语法,要求对细节保持关注。