我正在使用C,但我认为这是一个更低级别的问题,而不是语言特定的。
程序如何正确地使用数组[0]或数组[6]获取正确的数据,而不管它包含什么类型的数据?它是在内部存储长度还是有某种分隔符来查找?
答案 0 :(得分:13)
编译器知道sizeof
基础数据类型,并将正确的字节偏移量添加到指针。
a[10]
相当于*(a + 10)
,相当于*(10 + a)
,而10[a]
相当于{{1}},不开玩笑。
答案 1 :(得分:7)
编译器在编译时计算出大小,并在目标代码中硬编码大小。
答案 2 :(得分:6)
我想提供除直接答案之外的其他内容。
有一个interesting article on Dennis Ritchie's homepage on the history of C对数组,数组索引等有很多说法。
这可能不会直接回答你的问题,但它可能会进一步你对C数组的理解......这是一个有趣的读物。
答案 3 :(得分:5)
两者都没有: - )
对于数组,编译器知道:(a)数组起始的地址,以及(b)数组所包含的元素类型(int,float,double等),以及每个元素的长度元素是。
使用这两条信息,查找array[6]
是一个简单的算术问题:从基地址开始,并添加元素大小的6倍。
答案 4 :(得分:3)
编译器替换在编译时修复的数据类型的长度。
int getInt(void * memory, offset)
{
return *((int *)(sizeof(int)*offset + memory))
}
void * chunkOfMemory = malloc(0x1000);
int * intarray = (int *) chunkOfMemory;
printf("%d is equal to %d", getInt(chunkOfMemory, 9), intarray[9]);
答案 5 :(得分:2)
编译器在编译时知道数组的每个元素的大小。例如:
int64_t array[5];
...
int64_t a = array[3];
这将转换为伪汇编代码:
addr <- array
addr <- addr + 3 * sizeof(int64_t)
// ^^^^^^^^^^^^^^^ which the compiler knows is 8
// ^^^^^^^^^^^^^^^^^^^ which the compiler can replace with 24.
a <- *addr
阵列的长度无关紧要。
答案 6 :(得分:1)
编译魔术!
编译器知道数组元素的大小,并使用它来计算正确的地址。
答案 7 :(得分:0)
不,不。它只是在地址array + X*sizeof(TypeOfArrayEl)
获取/设置元素,因此您可以轻松地超出范围,当时没有人可能会给您错误。这就是array[6]
与6[array]
答案 8 :(得分:0)
假设数组的类型为int:
int array[12];
[]
运算符将括号中的任何值(数组类型的字节数)乘以括号外的值。实现将数组存储为指向其第一项的指针。因此上面的数组声明分配12 * sizeof(int)字节,并使array
指向第一个。这导致像3[array]
这样的不稳定的东西给你数组中的第三个元素。
无论如何,你的问题的答案是编译器在编译时查看数组的类型,并将[]中的东西乘以数组所持类型的大小。
答案 9 :(得分:0)
是的,你是对的它甚至是更低级别的问题,即使汇编程序有[]
运算符。 This回答说得很好,但我的解释是:
arr[x]
与*((void *)(&arr) + x * sizeof(arr[0]))
看起来有点复杂,但生成的代码很简单。这是因为编译器知道sizeof(arr[0])
并且它在编译的代码中是硬编码的,(void *)(&arr)
只是语言标准,它保护程序员免于愚蠢的错误,在编译的代码中没有类型转换。
还有一件事,正如我提到的低级语言,所以需要提一下。使用它们可以使操作员重载并使其做任何你想做的事。
答案 10 :(得分:-2)
根据我的记忆,如果索引超出范围,C不会给出编译时错误。 即使超出界限,指针也会为您提供下一个相邻的内存位置。 C唯一需要注意的是增加指针的字节数。如果它是一个整数数组,那么指针将为索引中的每个增量前进2个字节,对于char它将增加1字节。
您始终可以访问超出界限的位置,但这些是垃圾数据,而您作为程序员必须确保您访问的是正确的数据。
这就是我想的自由价格:)