分配数组后从用户那里接受大小。

huangapple go评论148阅读模式
英文:

Allocating array after accepting size from user

问题

我在C语言中写了类似这样的代码:

  1. #include <stdio.h>
  2. int main() {
  3. int x;
  4. printf("enter no of elements/n");
  5. scanf("%d", &x);
  6. int arr[x];
  7. return 0;
  8. }

这个代码可以运行,但很多人说它不是一个好的做法,或者说是不合法的?有人能给出原因吗?

更新:除了可移植性或未定义大小之外,还有其他问题吗?

英文:

I was writing something like this in C.

  1. #include&lt;stdio.h&gt;
  2. int main() {
  3. int x;
  4. printf(&quot;enter no of elements/n&quot;);
  5. scanf(&quot;%d&quot;,&amp;x);
  6. int arr[x];
  7. return 0;
  8. }

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

  1. 假设你的实际代码看起来像以下内容,它将会编译。
  2. ```c
  3. #include <stdio.h>;
  4. int main(void) {
  5. int n;
  6. printf("Enter number of elements:\n");
  7. scanf("%d", &n);
  8. int arr[n];
  9. // 其他部分...
  10. }

然而,存在一些问题。

  • 不是所有编译器都支持可变长度数组(Variable length arrays,简称VLAs)。特别是MSVC不支持。依赖它们会影响代码的可移植性。
  • 你没有验证输入。scanf 可能没有读取有效的数字,即使它读取了,0 或负数都会导致未定义的行为。

对此你可以采取以下措施:

  • 你可以动态分配数组的内存,而不是使用VLA。
  • 你可以编写一个函数,检查用户的输入并验证它是正整数。它可以提示用户重新输入,或返回一个 main 可以检查然后优雅地退出程序的值。
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #define LINE_LENGTH 1024
  5. int get_positive_int(void);
  6. int main(void) {
  7. int n = get_positive_int();
  8. int *arr = malloc(sizeof(int) * n);
  9. if (arr == NULL) {
  10. printf("Array allocation failed.\n");
  11. return 1;
  12. }
  13. // 其他部分...
  14. }
  15. int get_positive_int(void) {
  16. char line[LINE_LENGTH] = "";
  17. while (1) {
  18. printf("Enter number of elements:\n");
  19. int input = -1;
  20. fgets(line, LINE_LENGTH, stdin);
  21. if (sscanf(line, "%d", &input) == 1 && input > 0)
  22. return input;
  23. }
  24. }
  1. <details>
  2. <summary>英文:</summary>
  3. 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);

  1. int arr[n];
  2. // Other stuff...

}

  1. However, there are a few issues.
  2. - Variable length arrays (or VLAs) are not supported by all compilers. Notably MSVC. Relying on them will impact the portability of your code.
  3. - 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.
  4. What can you do about these?
  5. - You can dynamically allocate memory for your array rather than using a VLA.
  6. - You can write a function which checks the input from the user and validates that it&#39;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);

  1. if (arr == NULL) {
  2. printf(&quot;Array allocation failed.\n&quot;);
  3. return 1;
  4. }
  5. // Other stuff...

}

int get_positive_int(void) {
char line[LINE_LENGTH] = "";

  1. while (1) {
  2. printf(&quot;Enter number of elements:\n&quot;);
  3. int input = -1;
  4. fgets(line, LINE_LENGTH, stdin);
  5. if (sscanf(line, &quot;%d&quot;, &amp;input) == 1 &amp;&amp; input &gt; 0)
  6. return input;
  7. }

}

  1. </details>
  2. # 答案2
  3. **得分**: 3
  4. > 但许多人说这不是一个好的做法,或者是非法的?
  5. **合法?**
  6. 是的,但这取决于编译器版本和可选支持。
  7. [可变长度数组](https://en.wikipedia.org/wiki/Variable-length_array)(VLA)如 `int Arr[x];` 在 C99 中得到支持,可选地在 C11 及以后版本中支持(请查阅 `__STDC_NO_VLA__` 进行研究)。
  8. 这会影响可移植性。
  9. **良好的做法?**
  10. * 不检查 `scanf("%d", &x);` 的返回值是不可取的。
  11. * 对于 `int Arr[x];`,如果 `x <= 0`,会导致_未定义行为_(UB)。
  12. * 如果 `x` 很大,我们有可能会面临内存耗尽,如堆栈溢出或其他 UB。
  13. 在以下情况下,VLAs是可以接受的:
  14. * 大小为正且不太大
  15. * 可移植性不是主要关注点
  16. 使用适合工作的正确工具。
  17. VLAs 只在有限的情况下是最佳解决方案。
  18. **更好的示例用法**
  19. ```c
  20. #define VLA_LIMIT 42
  21. printf("输入元素数量:");
  22. int x;
  23. if (scanf("%d", &x) != 1) {
  24. 处理输入错误(); // 待定的代码
  25. }
  26. if (x <= 0 || x > VLA_LIMIT) {
  27. 处理范围错误(); // 待定的代码
  28. }
  29. int Arr[x];
  30. ...
英文:

> 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(&quot;%d&quot;,&amp;x); is weak.

  • With int Arr[x];, if x &lt;= 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

  1. #define VLA_LIMIT 42
  2. printf(&quot;enter no of elements &quot;);
  3. int x;
  4. if (scanf(&quot;%d&quot;,&amp;x) != 1) {
  5. Handle_Input_Error(); // TBD code
  6. }
  7. if (x &lt;= 0 || x &gt; VLA_LIMIT) {
  8. Handle_Range_Error(); // TBD code
  9. }
  10. int Arr[x];
  11. ...

huangapple
  • 本文由 发表于 2023年8月5日 10:44:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76839960.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定