可能重复:
数组名称是 C 中的指针吗?
如果我定义:
int tab[4];
tab 是一个指针,因为如果我显示选项卡:
printf("%d", tab);
上面的代码将显示内存中第一个元素的地址。
这就是为什么我想知道为什么我们不定义如下数组:
int *tab[4];
因为 tab 是一个指针。
感谢您的任何帮助!
可能重复:
数组名称是 C 中的指针吗?
如果我定义:
int tab[4];
tab 是一个指针,因为如果我显示选项卡:
printf("%d", tab);
上面的代码将显示内存中第一个元素的地址。
这就是为什么我想知道为什么我们不定义如下数组:
int *tab[4];
因为 tab 是一个指针。
感谢您的任何帮助!
tab 是一个指针
不,tab
是一个数组。一个int[4]
要具体。但是,当您将它作为参数传递给函数(以及在许多其他上下文中)时,数组将转换为指向其第一个元素的指针。您可以看到数组和指针之间的区别,例如当您调用sizeof array
vs.sizeof pointer
时,当您尝试分配给数组时(不会编译)等等。
int *tab[4];
声明一个由四个指向int
. 我看不出这与数组和指针之间的混淆有什么关系。
tab
不是指针,它是一个由 4 个整数组成的数组,当传递给函数时,它会衰减为指向第一个元素的指针:
int tab[4];
这是另一个数组,但它包含 4 个整数指针:
int *tab[4];
最后,为了完整起见,这是一个指向 4 个整数数组的指针,如果你取消引用它,你会得到一个 4 个整数数组:
int (*tab)[4];
你并没有完全错,这意味着你的陈述是错误的,但你离事实并不远。
C下的数组和指针共享相同的算法,但主要区别在于数组是容器,指针就像任何其他原子变量一样,它们的目的是存储内存地址并提供有关指向值类型的信息。
我建议阅读一些关于pointer arithmetic
考虑到Steve Jessop 的评论,我想添加一个片段,可以向您介绍指针运算的简单而有效的世界:
#include <stdio.h>
int main()
{
int arr[10] = {10,11,12,13,14,15,16,17,18,19};
int pos = 3;
printf("Arithmetic part 1 %d\n",arr[pos]);
printf("Arithmetic part 2 %d\n",pos[arr]);
return(0);
}
数组的行为可以像指针,甚至在您的情况下看起来像指针,您可以应用相同类型的算术,因为它们不是指针。
int *tab[4];
这个定义意味着tab
数组包含pointers of int
而不是int
来自C 标准
编码指南
数组对象到指向其第一个元素的指针的隐式转换对于尝试在 C 中为数组制定更强大的类型检查是一个很大的不便。在 C 语言中,缺乏经验的开发人员有时将数组和指针等同于比这允许的更接近要求(适用于表达式中的使用,而不是声明)。例如,在:
文件_1.c
extern int *a;
文件_2.c
extern int a[10];
开发人员有时错误地认为 a 的两个声明是兼容的。很难看出什么样的指南推荐会克服不正确的开发人员假设(或培训不足)。如果遵循指定单点声明的指南建议,则不会出现在一个文件中声明的 419.1 标识符。与函数指示符的用法不同,开发人员熟悉这样一个事实,即具有转换为 typetype 的数组函数指示符的对象会隐式转换为指向其第一个元素的指针。将一元 & 运算符应用于具有数组类型的操作数是否会为读者提供有用的视觉提示,或者让他们怀疑作者的意图(“那个冗余运算符在那里做什么?”)尚不清楚。
例子
static double a[5];
void f(double b[5])
{
double (*p)[5] = &a;
double **q = &b; /* This looks suspicious, */
p = &b; /* and so does this. */
q = &a;
}
如果数组对象具有寄存器存储类,则行为未定义
在大多数情况下,数组类型的表达式将被转换(“衰减”)为指针类型的表达式,表达式的值将是数组中第一个元素的地址。此规则的例外情况是数组表达式是 、 或一元运算符的操作数sizeof
,_Alignof
或者&
是用于在声明中初始化另一个数组的字符串文字。
int tab[4];
if定义tab
为 4 元素数组int
。在声明中
printf("%d", tab); // which *should* be printf("%p", (void*) tab);
表达式 tab
从类型“4 元素数组”转换为int
“指针int
”。