我试图制作一个基于数组的线性列表,然后我编译了这个:
char size = 0;
char testarray[10];
int main() {
add('a'); add('b'); add('c');
add('d'); add('e'); add('f');
add('g'); add('h'); add('i');
add('j'); add('k'); add('l');
add('m'); add('n'); add('o');
print();
return 0;
}
void add(char newchar) {
testarray[++size] = newchar;
}
void print() {
char i = 0;
for (i = 0; i <= size; i++) {
printf("%c ", testarray[i]);
}
}
用gcc arraytest.c
编译它,但数组运行正常。这是否意味着默认情况下数组是可变长度的?我认为这是一个仅限C99的功能。
它是在Gentoo(gcc version 4.5.3 (Gentoo 4.5.3-r2 p1.1, pie-0.4.7
)和Ubuntu(gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3
)下编译的。
哦,这不是有点危险吗?
答案 0 :(得分:7)
不,它们的大小不变。你只是写过数组的末尾并破坏其他一些内存。没有任何检查可以证明这一点。
答案 1 :(得分:5)
将C视为世界上最棒的汇编语言,它也是可移植的。它完全不同于专为内存安全而设计的语言。 (那将是大多数其他的。)
你可以回答这样的问题的一种方法(即“C实际上做什么”)是用cc -S ...
进行编译并检查生成的汇编代码。即使您不熟悉机器语言,也可以说它没有调用或检查下标范围。
C实际上无法真正做到这一点,因为x[i]
被定义为*(x + i)
,所以它确实是“高级汇编语言”就像他们说的那样。
答案 2 :(得分:4)
只要您在应用程序的分配范围内,就可以在任何地方使用指针/地址。继续走得太远,你要么丢弃你的程序,要么点击你分配的内存的边缘,并获得某种保护错误。运行时检查很昂贵,不管怎样都不想拥有它。
交换你的两个变量
char testarray[10];
char size = 0;
看看你跑的时候会发生什么......
然后这样做:
char size = 0;
char testarray[10];
char stuff[10];
在你开始向testarray添加东西之前,初始化东西,然后在你的东西打印出stuff []数组之后。你应该看到你的溢出。在C中,将非数组变量放在赋值列表中并且数组或数组最后,这是一个很好的规则,你有更好的调试机会。
答案 3 :(得分:2)
正如Vaugh所说,你只是“幸运”*因为数组中的内存是可写的。有可能出现分段错误。事实上,如果你稍微更改程序以便数组在堆栈中,那么通过valgrind运行它会向你发出大量的警告。
*“幸运”,因为程序没有崩溃。不幸的是......它会在以后发生。