英文:
When I compile my short and simple C code I get "stack smashing detected", while the same code in JavaScript runs fine, why is that?
问题
以下是翻译的部分:
这是一个更大项目的一部分,但我已经将错误的原因定位到了这个特定的代码片段,并对其进行了调整,使其能够独立运行(包括预定义了number的值)。
#include <stdio.h>
int main() {
unsigned number = 4;
int array[] = {};
for (int j = 0; j < number; j++) {
for (int i = number; i > j; i--) {
array[j] = i;
}
printf("%d ", array[j]);
}
return 0;
}
我刚开始学习C语言,所以为了检查是否是代码本身的问题,而不是特定于C语言的问题,我将其转换成了JavaScript:
var number = 4;
var array = [];
for (var j = 0; j < number; j++){
for (var i = number; i > j; i--){
array[j] = i;
}
console.log(array[j]);
}
它成功运行并给我了预期的结果。导致C代码出现错误的问题是什么?
我尝试运行C代码,期望得到打印出1、2、3和4的数字,但却收到了一个“stack smashing detected”错误消息。
英文:
This is part of a bigger project, but I isolated the culprit for the error as being this specific snippet and adapted it so it would run by itself (including having the value for number predefined).
#include <stdio.h>
int main() {
unsigned number = 4;
int array[] = {};
for (int j = 0; j < number; j++) {
for (int i = number; i > j; i--) {
array[j] = i;
}
printf("%d ", array[j]);
}
return 0;
}
I'm just starting to learn C, so to check if it was a problem with the code itself, and not specific to C, so I adapted it into JavaScript:
var number = 4;
var array = [];
for (var j = 0; j < number; j++){
for (var i = number; i > j; i--){
array[j] = i;
}
console.log(array[j]);
}
It ran and gave me the result I expected. What's the problem with the C code that's making me get the error?
I tried running the C code, expecting to get the numbers 1, 2, 3 and 4 printed.
I got a "stack smashing detected" error message instead.
答案1
得分: 4
以下是您要翻译的内容:
问题出在您的代码中,您在C语言中声明了一个数组,但没有指定数组的大小。C语言是一种古老的语言,其中的数组实际上是给定大小的内存盒子。您无法像Python等其他语言那样进行大小增加和向数组添加新元素等高级操作。纠正这段代码并使其可“运行”的一种方法是为数组指定大小为4:
unsigned number = 4;
int array[4]; // <----- 这里
for (int j = 0; j < number; j++) {
for (int i = number; i > j; i--) {
array[j] = i;
}
printf("%d ", array[j]);
}
return 0;
虽然这是正确的代码,因为您正在遍历与变量 number
相对应的列表,但您可能会认为修复它的一种方法是执行下面的操作:
unsigned number = 4;
int array[number]; // <----- 这里
for (int j = 0; j < number; j++) {
for (int i = number; i > j; i--) {
array[j] = i;
}
printf("%d ", array[j]);
}
return 0;
虽然这对某些数字可以正常工作,但对于较大的值可能会失败。要解释这一点,您需要知道在“堆栈”中分配的任何内容的大小(通常声明的任何变量或值)都是在编译时确定的,换句话说,在程序实际运行之前确定。因此,如果将变量 number
用作数组的大小,编译器应该如何知道数组的大小呢?变量的值是在编译后(在运行时)确定的。那么C编译器会做什么呢?它将给它一个随机的大尺寸,如80或800。
这就是为什么我们使用堆分配的原因。使用库 <stdlib.h>
和函数 malloc( size )
,您可以从堆中分配内存。堆中的内存分配是在运行时完成的,因此消除了手头的问题。您需要为 malloc
提供所需内存的大小,即int的大小 * 数组的大小
。需要记住的一件事是使用 free
函数释放使用 malloc
分配的任何数组。如果不这样做,将导致内存泄漏,这是另一个故事。
代码的最终和正确版本应该是:
unsigned number = 4;
int *array = malloc(sizeof(int) * number); // <--- 在运行时从堆中分配内存
for (int j = 0; j < number; j++) {
for (int i = number; i > j; i--) {
array[j] = i;
}
printf("%d ", array[j]);
}
free(array); // 释放分配的内存
return 0;
编辑:
正如Eric Postpischil指出的那样,我的说法:“在“堆栈”中分配的任何内容(通常声明的任何变量或值)在编译时确定”是不正确的。自从C99以来,引入了一种新的数组类型,称为VLA(可变长度数组),它不仅分配在堆栈中,而且其大小在运行时确定。尽管如此,仍然存在一些阻碍人们使用它们的缺点。请参阅此链接以获取更多信息:链接。
英文:
The problem with your code is that you are declaring an array in c, but not specifying what the size of the array is. c is an ancient language, and arrays in c mean literally a box of memory of that size given to you. You can't do anything fancy like size increasing and adding new elements to the array like in languages such as Python. One way to correct this code and make it "runnable", is to give your array a size of 4:
unsigned number = 4;
int array[4]; // <----- here
for (int j = 0; j < number; j++) {
for (int i = number; i > j; i--) {
array[j] = i;
}
printf("%d ", array[j]);
}
return 0;
while this is a correct code since you are iterating through the list corresponding to the variable number
, one way you might believe to fix it is to do what I've done below:
unsigned number = 4;
int array[number]; // <----- here
for (int j = 0; j < number; j++) {
for (int i = number; i > j; i--) {
array[j] = i;
}
printf("%d ", array[j]);
}
return 0;
while this will work for some numbers, it will fail for large values. to explain this you will need to know that the size of anything allocated in the "stack" (any variable or value you declare normally) is determined at compile time, in other words before the program actually runs.
so if you use the variable number
as the size of the array, how should the compiler know what the size of the array is? values of variables are determined after compile time (at run-time). so what does the c compiler do? it will give it a random large size like 80 or 800.
that is why we use something called heap allocation. using the library <stdlib.h>
and the function malloc( size )
you can allocate memory from the heap. memory allocations from the heap are done at run-time, thus getting rid of the problem at hand. you will need to give malloc
the size of memory that we want. so that is size of int * size of the array
. One thing to keep in mind is to free any array that you allocate with malloc
using the free
function. not doing that will result in a memory leak which is a whole other story in itself.
the final and correct version of the code should be:
unsigned number = 4;
int *array = malloc(sizeof(int) * number); // <--- allocate memory from heap at run-time
for (int j = 0; j < number; j++) {
for (int i = number; i > j; i--) {
array[j] = i;
}
printf("%d ", array[j]);
}
free(array); // free the allocated memory
return 0;
edit:
as Eric Postpischil pointed out, my statement: "Anything allocated in the "stack" (any variable or value you declare normally) is determined at compile time” is not correct. ever since C99, a new kind of array was introduced called VLA(variable length array) which is not only allocated in the stack but its size is determined at run-time. there are still drawbacks that discourage people from using them. please see this link
答案2
得分: 1
"Retired Ninja"理解得没错。我之前假设编译器在数组已经有值的情况下会自动定义数组的大小,但现在我想想当然它在代码已经运行时无法这样做。
英文:
Retired Ninja got it right. I assumed since the compiler automatically defines the size of the array when it already has values in it that it would do the same, but now that I think of it, of course it can't do that once the code is already running.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论