在 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 数组的方法:
- 像你一样使用大括号
{}
(int ary[] = {1,2,3,4,5};
)
- 在for循环中逐一迭代数组元素并初始化每一个元素。
- via :
memset(void *str, int c, size_t n);
,用相同的值填充整个数组。例如如果我想用 0x0
初始化数组,那么,memset 调用会像这样:memset(arr, 0x0, sizeof(arr));
关于您的代码:
- 对于代码中的每个
scanf(..)
,您必须检查和验证 scanf("%d",&n);
、return/errors 以及 n
中的用户输入,然后才能在您的代码中取得任何进展。你怎么查?稍后再看。
- 在你的情况下,最好限制用户输入
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
...等等
你有很多问题,未定义的行为 是最关键的:
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);
我在教科书上了解到,只有几种方法可以初始化数组。
方法一:
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 数组的方法:
- 像你一样使用大括号
{}
(int ary[] = {1,2,3,4,5};
) - 在for循环中逐一迭代数组元素并初始化每一个元素。
- via :
memset(void *str, int c, size_t n);
,用相同的值填充整个数组。例如如果我想用0x0
初始化数组,那么,memset 调用会像这样:memset(arr, 0x0, sizeof(arr));
关于您的代码:
- 对于代码中的每个
scanf(..)
,您必须检查和验证scanf("%d",&n);
、return/errors 以及n
中的用户输入,然后才能在您的代码中取得任何进展。你怎么查?稍后再看。 - 在你的情况下,最好限制用户输入
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
...等等
你有很多问题,未定义的行为 是最关键的:
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);