2009-06-20 135 views
11

我一直在阅读K & R关于C的书,并发现C中的指针算术允许访问超出数组末尾的一个元素。我知道C允许用记忆做任何事情,但我只是不明白,这个特点的目的是什么?C元素超出数组的末尾

+1

另请参阅此问题:http://stackoverflow.com/questions/988158/take-the-address-of-a-one-past-the-end-array-element-via-subscript-legal-by- – 2009-06-20 14:07:03

回答

19

C不允许访问超出阵列末尾的内存。但是,它确实允许指针指向超出数组末尾的一个元素。区别很重要。

因此,这是确定:

char array[N]; 
char *p; 
char *end; 

for (p = array, end = array + N; p < end; ++p) 
    do_something(p); 

(做*end将是一个错误。)

和表示之所以这个功能是非常有用的:在(不存在的一个指针指向)元素在数组结束后可用于比较,比如在循环中。

从技术上讲,这是C标准允许的一切。但是,实际上,C实现(编译器和运行时)不会检查您是否访问超出数组末尾的内存,无论它是否是一个或多个元素。必须进行边界检查,这会减慢程序的执行速度。程序C的种类最适合(系统编程,通用库)比安全性和安全性边界检查更有利于速度。

这意味着C可能不是通用应用程序编程的好工具。

15

通常,它是表示“结束”的位置,这是一个过去的实际分配有用的,所以您可以编写代码:

char * end = begin + size; 
for (char * curr = begin; curr < /* or != */ end ; ++curr) { 
    /* do something in the loop */ 
} 

C标准明确地说,这个元素是一个有效的内存地址,但取消引用它仍然不是一个好主意。

它为什么有这个保证?假设您有一台内存为2^16字节的机器,地址为0000-FFFF,16位指针。假设你创建了一个16字节的数组。内存可以分配在FFF0吗?

有16个字节可用连续的,但:

begin + size == FFF0 + 10 (16 in hex) == 10000 

它包装为0000,因为指针的大小。现在环路条件:

curr < end == FFF0 < 0000 == false 

而不是遍历数组,循环将无所作为。这会破坏很多代码,所以C标准说分配是不允许的。

-1

,你可以远远超出过去1阵列 为example`

int main() 
{ 
     char *string = "string"; 
     int i = 0; 
     for(i=0; i< 10;i++) 
     { 
       printf("%c\n", string[i]); 
     } 
     return 0; 
} 

串词,无论是坐在内存前手结束后,将打印垃圾。

+6

它可能会打印垃圾,格式化硬盘,或导致恶魔飞出你的鼻子;这是未定义行为的性质。 – aib 2009-06-20 05:57:19