错误显示: 严重性 代码 说明 项目 文件 行 禁止显示状态 错误(活动) E0028 表达式必须含有常量值
(Visual Studio 2022)
目录
此问题我将通过我写的一段关于 需要通过输入函数给数组定义大小 的代码来讲解。
问题代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <corecrt_malloc.h>
void test() {
int i,n;
scanf("%d", &n);
int arr[n];
for (i = 0; i < n; i++) {
arr[i] = i; //输入数组值
printf("%d ", arr[i]); //打印数组值
}
}
int main() {
test();
return 0;
}
问题现象:

出错原因:
在 C 语言中,数组的大小必须在使用前已知,并且这个大小在整个程序的运行过程中不能改变。因此,数组的大小通常由常量来定义,而不是变量。这是因为:
- 编译时分配内存:数组在内存中的存储是连续的,编译器需要在编译时知道数组的大小,以便为数组分配足够的连续内存空间。如果数组的大小在编译时未知,编译器就无法进行内存分配。
- 性能考虑:使用常量定义数组大小可以提高程序的运行效率。编译器 optimize 代码时,可以根据数组的大小进行优化,比如进行边界检查的优化。如果数组大小是变量,那么在每次访问数组时都需要进行检查,这将增加运行时的开销。
- 错误检查:使用常量可以避免在运行时因为数组越界而导致的错误。数组越界是一个常见的编程错误,如果数组的大小是变量,那么在运行时才检查数组边界,就可能会发生越界访问,导致未定义行为。
- 代码清晰性:常量使得代码的意图更加清晰。数组的大小是一个固定值,这在代码的阅读和维护中是非常有帮助的。如果使用变量,可能会让人误解数组的大小是可以变化的,从而导致错误。
解决方法:
在某些情况下,如果数组的大小需要在运行时动态决定,可以使用指针和动态内存分配(如 `malloc` 或 `new`)来实现。
但是,一旦分配了数组的大小,就不能再改变它。这是因为数组的大小必须是编译时已知的,以便正确地寻址和访问数组元素。
因此,我将上述代码中
int arr[n];
改为了动态分配内存
int* arr = (int*)malloc(n * sizeof(int));
解决代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <corecrt_malloc.h>
void test(int n) {
int i;
//int* arr = new int[n];
int* arr = (int*)malloc(n * sizeof(int));
for (i = 0; i < n; i++) {
arr[i] = i;//输入数组值
printf("%d ", arr[i]);//打印数组值
}
free(arr);// 释放分配的内存
}
int main() {
int n;
scanf("%d", &n);
test(n);
return 0;
}
解决结果:

关于为什么使用动态内存分配就可以?
使用动态内存分配可以解决静态数组的一些局限性,主要体现在以下几个方面:
- 灵活性:动态内存分配允许你在程序运行时根据需要分配内存,而不是在编译时。这意味着你可以根据用户的输入或其他运行时条件来决定分配的内存大小,从而使程序更加灵活。
- 效率:如果你事先知道数据的大小,使用动态内存分配可以避免为不必要的空间分配内存,从而节省内存资源。对于例如数组或链表这样的数据结构,动态分配可以确保它们只使用实际需要的空间。
- 避免内存浪费:静态数组的大小是固定的,如果分配的内存超过了实际需要,那么这部分内存就浪费了。动态内存分配可以根据实际需要分配和释放内存,从而避免这种浪费。
- 跨函数使用:静态数组的生命周期通常局限于函数调用栈中,这意味着一旦函数调用结束,静态数组占用的内存就会被释放。动态内存分配可以在程序的不同部分使用,跨多个函数调用保持数据。
- 避免数组越界:静态数组的大小在声明时就已确定,如果尝试访问超出这个大小的索引,会导致数组越界,从而产生未定义行为。动态内存分配可以动态扩展数组的大小,以防止越界。
- 内存管理:动态内存分配需要使用特定的函数(如C中的`malloc`和`free`,C++中的`new`和`delete`)来请求和释放内存。这使得内存管理更加明确,有助于避免内存泄漏和野指针的问题。
总之,动态内存分配提供了一种在程序运行时分配和释放内存的方法,这比编译时固定的静态内存分配更加灵活、高效,并且有助于避免内存浪费和管理问题。