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

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

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&lt;stdio.h&gt;

int main() {
    int x;
    printf(&quot;enter no of elements/n&quot;);
    scanf(&quot;%d&quot;,&amp;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&#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);

if (arr == NULL) {
    printf(&quot;Array allocation failed.\n&quot;);
    return 1;
}

// Other stuff...

}

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

while (1) {
    printf(&quot;Enter number of elements:\n&quot;);

    int input = -1;

    fgets(line, LINE_LENGTH, stdin);
    if (sscanf(line, &quot;%d&quot;, &amp;input) == 1 &amp;&amp; input &gt; 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(&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

  #define VLA_LIMIT 42

  printf(&quot;enter no of elements &quot;);
  int x;
  if (scanf(&quot;%d&quot;,&amp;x) != 1) {
    Handle_Input_Error();  // TBD code
  } 
  if (x &lt;= 0 || x &gt; VLA_LIMIT) {
    Handle_Range_Error();  // TBD code
  } 
  int Arr[x];
  ...

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:

确定