在 C 中为数组初始化用户定义的参数值

Initialize User defined parameters value for Array in C

我在教科书上了解到,只有几种方法可以初始化数组。

方法一:

int ary[5] = {1,2,3,4,5};

方法二:

int ary[] = {1,2,3,4,5};

但是如果我想将用户定义的值输入到数组中怎么办?这段代码可以吗?谁能教我更好的方法吗?

#include<stdio.h>
#include<conio.h>

int main()
{
    int i, n;
    printf("Enter array parameter: \n");
    scanf("%d",&n);
    int a[n]; 
    int b[n];
    
    for(i=0;i<n;i++)
    {
        printf("Enter value for array a[%d]: \n",i+1);
        scanf("%d",&a[i]);
    }
    n -= 1; 
    for(i=0;i<=n;i++)
    {
        b[i]=a[n-i];
    }
    printf("Value of array b[] is: \n");
    for(i=0;i<=n;i++)
    {
        printf("%d ",b[i]);
    }
    for(i=0;i<=n;i++)
    {
        printf("\narray b[%d] = %d ",i,b[i]);
    }
    
    getch();
}

int ary[5] {1,2,3,4,5};

这不是有效的数组初始化。应该是

int ary[5] = {1,2,3,4,5};

注意等号。

否则,您的数组初始化对 C99 及更高版本有效。普通 c 不允许使用变量来初始化数组大小。

数组在 C 中初始化:

int ary[5] {1,2,3,4,5};

这是 c 中的无效语法(这在 c++ 中有效)。

有 3 种初始化 c 数组的方法:

  1. 像你一样使用大括号 {} (int ary[] = {1,2,3,4,5};)
  2. 在for循环中逐一迭代数组元素并初始化每一个元素。
  3. via : memset(void *str, int c, size_t n);,用相同的值填充整个数组。例如如果我想用 0x0 初始化数组,那么,memset 调用会像这样:memset(arr, 0x0, sizeof(arr));

关于您的代码:

  1. 对于代码中的每个 scanf(..),您必须检查和验证 scanf("%d",&n);、return/errors 以及 n 中的用户输入,然后才能在您的代码中取得任何进展。你怎么查?稍后再看。
  2. 在你的情况下,最好限制用户输入 n 并在定义的范围内验证 n (N_min <= n <= N_max),而不是在堆栈上分配大量数组如果 n 被用户设置为最大值!
if(scanf("%d",&n) == EOF){
    /*errors ocuured*/
    f_invoke_error_handling_rotuine(); 
}

f_invoke_error_handling_rotuine(..) 中,您可以执行您的代码需要执行的任何操作,也许 abort() 带有错误消息,也许将默认值设置为 n...等等

请参阅 man7.org 中 memsetscanf 的参考资料: scanf, memset

你有很多问题,未定义的行为 是最关键的:

n -= 1; 
for(i=0;i<=n;i++)
{
    b[i]=a[n-i];
}

i == n 时,索引超出了 b[] 数组的末尾。 C 中的所有数组都是零索引的,因此您的循环限制是 0 <= i < n。通过使用 i<=n 你循环了太多次。

您没有检查任何用户输入的 return。尝试输入“one”,或者不小心点击 'r' 而不是 4,看看会发生什么。您必须 检查每个用户输入的 return 并处理错误。如果用户输入 1, 2, 'r', 5 会发生什么?您还必须清空 stdin 任何无关字符,否则它们会在您下次输入时再次咬住您。

不要使用 conio.h。这使您的代码 100% 不可移植。您可以根据需要使用 stdio.h 中的功能。

就是说,当您需要执行重复性任务(例如获取整数输入)时,请编写一个简短的函数来执行此操作。您可以编写一个带有一个指向要填充的整数的指针,一个指向要显示的提示的指针,成功时 returns 0-1 如果用户通过生成一个取消输入在 Linux 上使用 Ctrl+d 或在 windows 上使用 Ctrl+z 手动 EOF。您可以向空的 stdin 添加辅助函数,例如

void empty_stdin (void)
{
    int c = getchar();
    
    while (c != '\n' && c != EOF)
        c = getchar();
}

int getint (int *n, const char *prompt)
{
    int rtn;
    
    for (;;) {
        fputs (prompt, stdout);
        rtn = scanf ("%d", n);
        if (rtn == EOF) {
            fputs ("  (user canceled input)\n", stderr);
            return -1;
        }
        else if (rtn == 0) {
            fputs ("  error: invalid integer input.\n", stderr);
            empty_stdin();
        }
        else
            break;
    }
    empty_stdin();
    
    return 0;
}

读取 a[] 中的数组并在 b[] 中反转它的程序的其余部分很简单:

int main (void) {
    
    int i = 0, n;
    
    if (getint (&n, "Enter array parameter: ") == -1)
        return 0;
    
    int a[n], b[n];
    
    for (i = 0; i < n; i++) {
        char buf[128];
        sprintf (buf, "enter value for a[%d]: ", i+1);
        if (getint (&a[i], buf) == -1)
            return 0;
    }
    for (i = 0; i < n; i++)
        b[i] = a[n - 1 - i];
    
    puts ("\nvalue of array b[]:");
    for (i = 0; i < n; i++)
        printf (" %d", b[i]);
    putchar ('\n');

#if defined (_WIN32) || defined (_WIN64)
    getchar();  /* hold terminal open on windows - type any char, hit return */
#endif
}

例子Use/Output

所有有效输入:

$ ./bin/getarray
Enter array parameter: 5
enter value for a[1]: 5
enter value for a[2]: 4
enter value for a[3]: 3
enter value for a[4]: 2
enter value for a[5]: 1

value of array b[]:
 1 2 3 4 5

输入错误:

$ ./bin/getarray
Enter array parameter: foo
  error: invalid integer input.
Enter array parameter: 5
enter value for a[1]: 5
enter value for a[2]: four
  error: invalid integer input.
enter value for a[2]: 4
enter value for a[3]: 3
enter value for a[4]: I'm getting tired of this game...
  error: invalid integer input.
enter value for a[4]: 2
enter value for a[5]: 1

value of array b[]:
 1 2 3 4 5

用户取消输入:

$ ./bin/getarray
Enter array parameter: 5
enter value for a[1]: 5
enter value for a[2]: 4
enter value for a[3]: 3
enter value for a[4]:   (user canceled input)

检查一下,如果您还有其他问题,请告诉我。

正如有人指出的那样,第一种方法在 C 中不起作用。但它是有效的 C++。

第二种方法 int ary[] = {1,2,3,4,5}; 工作,数组 ary 在编译时用 5 个项目初始化(甚至在 运行 程序之前)。内存分配在栈上。

您也可以这样做 int ary[6] = {1,2,3,4,5};,您可以在其中指定数组的长度。然后您可以访问 ary[5] 并将其更改为您想要的任何值(默认情况下为 0)。

注意ary[6] 超出范围,因为数组的元素从 0 到 5。

在您的代码中,您使用了一种称为可变长度数组 (VLA) 的东西,并且如 Wikipedia 所述,它们在堆栈上分配了自动存储持续时间。这意味着当您声明它们的函数结束时,它们的生命周期也结束(它们在您声明它们的函数范围内是本地的)。要理解为什么这很重要,请考虑这段代码:

int *func(int n) {
   int v[n]; // variable length array

   v[0] = 1;
   v[1] = 2;
   v[2] = 3;

   return v;   // this will not work, variable length arrays will be destroyed
               // when the function they belong to goes out of scope
}

int main() {
   int *v;
   v = func(3);  // when you will try to access the memory in v, it will be undefined 
                 // behaviour (can seg fault, the memory is not yours anymore)
   // print values in v
   return 0;
}

要解决此问题,您需要使用 stdlib.h 中定义的 malloc

int *func(int n) {
   int *v = malloc(sizeof(int) * n); // allocate memory for n elements

   v[0] = 1;
   v[1] = 2;
   v[2] = 3;

   return v;   // this will now work
}

int main() {
   int *v;
   v = func(3); // this will work
   // print values in v
   free(v);
   return 0;
}

之所以可行,是因为使用 malloc 分配的内存是在堆上分配的,这意味着它在程序的整个持续时间内都存在,除非您自己解除分配(这意味着您需要释放内存最后使用函数 free).

"Would this code be ok? Can anyone teach me a better way to do this?"

从句法的角度来看,这段代码是可以的(您更正了错误的初始化),但不可移植,因为您使用了 可变长度数组 (VLA),这可能不受任何实现的支持(它们由我的编译器扩展提供)并且仅完全符合 C99 标准。

更好的方法是使用 malloc() 并在堆上为数组分配内存。

这还有一个好处,您可以根据需要调整数组的大小(使其变大 f.e。)并且 free() 数组不再需要时的内存。

相关资料:

  • Is it a good idea to use C99 VLA compared to malloc/free?

  • Is there any overhead for using variable-length arrays?

  • When to use variable length array in C, but when a dynamic allocation?


int i, n;

printf("Enter amount of array elements: \n");
if (scanf("%d",&n) != 1)
{ 
    fputs("Error at input!", stderr);
    return EXIT_FAILURE;
}

int* a = malloc ( sizeof(*a) * n );
if (!a)
{ 
    fputs("Error at allocation for a!", stderr);
    return EXIT_FAILURE;
}

int* b = malloc ( sizeof(*b) * n );
if (!b)
{ 
    fputs("Error at allocation for b!", stderr);
    return EXIT_FAILURE;
}

for (i = 0; i < n; i++)
{
    printf("Enter value for array a[%d]: \n", i);
    if (scanf("%d", &a[i]) != 1)
    { 
       fprintf(stderr, "Error at input for a[%d]!", i);
       return EXIT_FAILURE;
    }
}

...

free(a);
free(b);