英文:
Allocating array after accepting size from user
问题
我在C语言中写了类似这样的代码:
#include <stdio.h>
int main() {
int x;
printf("enter no of elements/n");
scanf("%d", &x);
int arr[x];
return 0;
}
这个代码可以运行,但很多人说它不是一个好的做法,或者说是不合法的?有人能给出原因吗?
更新:除了可移植性或未定义大小之外,还有其他问题吗?
英文:
I was writing something like this in C.
#include<stdio.h>
int main() {
int x;
printf("enter no of elements/n");
scanf("%d",&x);
int arr[x];
return 0;
}
This works fine, but many said it's not a good practice or it is illegal? Can anybody give reasons for it?
Update: anything wrong other than
portability, or undefined size?
答案1
得分: 4
假设你的实际代码看起来像以下内容,它将会编译。
```c
#include <stdio.h>;
int main(void) {
int n;
printf("Enter number of elements:\n");
scanf("%d", &n);
int arr[n];
// 其他部分...
}
然而,存在一些问题。
- 不是所有编译器都支持可变长度数组(Variable length arrays,简称VLAs)。特别是MSVC不支持。依赖它们会影响代码的可移植性。
- 你没有验证输入。
scanf
可能没有读取有效的数字,即使它读取了,0
或负数都会导致未定义的行为。
对此你可以采取以下措施:
- 你可以动态分配数组的内存,而不是使用VLA。
- 你可以编写一个函数,检查用户的输入并验证它是正整数。它可以提示用户重新输入,或返回一个
main
可以检查然后优雅地退出程序的值。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINE_LENGTH 1024
int get_positive_int(void);
int main(void) {
int n = get_positive_int();
int *arr = malloc(sizeof(int) * n);
if (arr == NULL) {
printf("Array allocation failed.\n");
return 1;
}
// 其他部分...
}
int get_positive_int(void) {
char line[LINE_LENGTH] = "";
while (1) {
printf("Enter number of elements:\n");
int input = -1;
fgets(line, LINE_LENGTH, stdin);
if (sscanf(line, "%d", &input) == 1 && input > 0)
return input;
}
}
<details>
<summary>英文:</summary>
Assuming your actual code looks something like the following, it will compile.
#include <stdio.h>
int main(void) {
int n;
printf("Enter number of elements:\n");
scanf("%d", &n);
int arr[n];
// Other stuff...
}
However, there are a few issues.
- Variable length arrays (or VLAs) are not supported by all compilers. Notably MSVC. Relying on them will impact the portability of your code.
- You never validate the input. `scanf` may not have read a valid number, and even if it did, `0` or a negative number are going to lead to undefined behavior.
What can you do about these?
- You can dynamically allocate memory for your array rather than using a VLA.
- You can write a function which checks the input from the user and validates that it's a positive integer. It might prompt for repeat input or return a value that `main` can check and then gracefully exit the program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINE_LENGTH 1024
int get_positive_int(void);
int main(void) {
int n = get_positive_int();
int *arr = malloc(sizeof(int) * n);
if (arr == NULL) {
printf("Array allocation failed.\n");
return 1;
}
// Other stuff...
}
int get_positive_int(void) {
char line[LINE_LENGTH] = "";
while (1) {
printf("Enter number of elements:\n");
int input = -1;
fgets(line, LINE_LENGTH, stdin);
if (sscanf(line, "%d", &input) == 1 && input > 0)
return input;
}
}
</details>
# 答案2
**得分**: 3
> 但许多人说这不是一个好的做法,或者是非法的?
**合法?**
是的,但这取决于编译器版本和可选支持。
[可变长度数组](https://en.wikipedia.org/wiki/Variable-length_array)(VLA)如 `int Arr[x];` 在 C99 中得到支持,可选地在 C11 及以后版本中支持(请查阅 `__STDC_NO_VLA__` 进行研究)。
这会影响可移植性。
**良好的做法?**
* 不检查 `scanf("%d", &x);` 的返回值是不可取的。
* 对于 `int Arr[x];`,如果 `x <= 0`,会导致_未定义行为_(UB)。
* 如果 `x` 很大,我们有可能会面临内存耗尽,如堆栈溢出或其他 UB。
在以下情况下,VLAs是可以接受的:
* 大小为正且不太大
* 可移植性不是主要关注点
使用适合工作的正确工具。
VLAs 只在有限的情况下是最佳解决方案。
**更好的示例用法**
```c
#define VLA_LIMIT 42
printf("输入元素数量:");
int x;
if (scanf("%d", &x) != 1) {
处理输入错误(); // 待定的代码
}
if (x <= 0 || x > VLA_LIMIT) {
处理范围错误(); // 待定的代码
}
int Arr[x];
...
英文:
> but many said it's not a good practice or it is illegal?
Legal?
Yes, yet depends on the compiler version and optional support.
Variable length arrays (VLA) like int Arr[x];
are supported starting in C99 and optionally in C11 and later (research __STDC_NO_VLA__
).
This impacts portability.
Good practice?
-
Not checking the return value of
scanf("%d",&x);
is weak. -
With
int Arr[x];
, ifx <= 0
, we have undefined behavior (UB). -
If
x
is large, we risk memory exhaustion like stack overflow or other UB.
VLAs are OK when:
- The size is positive and not too large
- Portability is not a large concern.
Use the right tool for the job.
VLAs have limited cases when they are the best solution.
Better example usage
#define VLA_LIMIT 42
printf("enter no of elements ");
int x;
if (scanf("%d",&x) != 1) {
Handle_Input_Error(); // TBD code
}
if (x <= 0 || x > VLA_LIMIT) {
Handle_Range_Error(); // TBD code
}
int Arr[x];
...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论