我刚刚被介绍给C,我被分配编写一个程序,模仿杂货店的自助结账线。这涉及我必须根据用户输入用杂货的价格填充数组,并将它们相加并复制到文件中。
填充整数数组的最简单方法是使用 for 循环。但是对于浮点类型的数组来说,这会有所不同吗?
会不会像这样?还是不正确?
int size, i;
float items[size];
printf("How many items are you checking out today?");
scanf("%d", &size);
for(i=0;i<size;i++){
printf("Enter the price of an itemn");
scanf("%f", items[i]);
}
我是这个网站的新手,所以提前感谢
我建议在声明变量时始终初始化变量,以防止意外的"垃圾"值。另外,我真的不建议预先声明您的循环计数器。你可以在很多旧代码中看到它(由于编译器的限制,它曾经是必需的(,但现在我只是认为它是代码噪音。它看起来像这样:
for (int i = 0; i < size; i++) {
// stuff
}
此外,您的代码存在大问题。您正在使用所谓的可变大小数组,它们不是一个好主意。您通常希望在编译时声明数组大小,或使用malloc
为数组动态分配空间。
但是,回到初始化,这就是您在声明时设置堆栈分配数组中的每个元素的方式:
#define SIZE 4
int main(void)
{
float items[SIZE] = { 0 };
}
如果您动态分配数组,出于同样的原因,我建议使用calloc
或memset
将数组元素设置为默认值。
要回答您关于填充数组的问题,是的,您实际如何执行此操作没有区别。for 循环在这两种情况下都工作得很好。只要记得检查scanf
的返回值即可。
正如正确指出的那样,在size
被有效初始化为正整数值之前,您无法声明float items[size];
。您尝试在包含值之前声明items
size
会调用未定义的行为,因为您尝试访问未初始化的值。(此时代码的有效操作已结束,它可以执行从看起来正确运行到StackOverflow或SegFaulting的任何操作(
每次进行用户输入时,都必须考虑输入缓冲区中保留的每个字符(此处stdin
(。由于scanf
处理输入或匹配故障的方式,当使用scanf
(或系列(获取输入时尤其如此。当任何一种发生时,都不会再读取任何字符,并且任何有问题的字符都不会在输入缓冲区中读取 - 只是等待在下次尝试读取时再次咬您(如果您在循环中获取输入,通常会导致无限循环(
(这是建议使用面向行的函数(如fgets
(来接受用户输入的主要原因之一(
如果使用得当,可以使用scanf
。这意味着您有责任每次检查scanf
的退货。您必须处理三个条件
(return == EOF)
用户通过按 Ctrl+d 生成手动EOF
来取消输入(或在窗口上按 Ctrl+z,但请参阅 CTRL+Z 在 Windows 10 中不生成 EOF(;(return == expected No. of conversions)
指示读取成功 - 然后由您检查输入是否满足任何其他条件(例如正整数,正浮点数等(;和- 否则,必须处理匹配或输入失败,并且必须考虑输入缓冲区中可能保留的每个字符。(通常,您将在输入缓冲区中向前扫描,直到发现
'n'
或EOF
丢弃任何剩余的无关字符(
如果您完成工作,则可以根据需要成功使用scanf
。
接下来,一般警告不要使用浮点作为货币(当你由于四舍五入错误而开始亏损时,人们会非常生气(虽然这对你的示例程序来说很好 - 只要理解,在真正的货币处理程序中,你会将货币处理为无符号值乘以100
(或任何需要的东西(,以确保所有金额都可以准确表示。
将scanf
要求放在一起,您可以安全地执行以下操作:
#include <stdio.h>
/* function to empty extraneous characters from stdin
* (like the 'n' generated by pressing [Enter])
*/
void empty_stdin()
{
int c = getchar();
while (c != 'n' && c != EOF)
c = getchar();
}
int main (void) {
int size = 0, i;
float total = 0.0;
for (;;) { /* loop continually until valid size entered */
int rtn;
printf ("How many items are you checking out today?: ");
rtn = scanf ("%d", &size);
if (rtn == EOF) { /* handle EOF */
fprintf (stderr, "(user canceled input)n");
return 1;
}
else if (rtn == 1 && size > 0) { /* valid int received */
empty_stdin();
break;
} /* otherwise, handle error */
fprintf (stderr, "error: invalid input.nn");
empty_stdin (); /* remove any chars from stdin up to 'n' */
}
float items[size]; /* declare VLA of size floats */
for (i = 0; i < size; i++) {
items[i] = 0.0; /* initialize each (or memset VLA) */
for (;;) { /* loop continually until valid item price entered */
int rtn;
printf (" price of item[%2d]: ", i + 1); /* prompt for price */
rtn = scanf ("%f", &items[i]);
if (rtn == EOF) { /* handle EOF */
fprintf (stderr, "(user canceled input)n");
return 1;
}
else if (rtn == 1 && items[i] > 0) { /* valid price received */
empty_stdin();
break;
} /* otherwise, handle error */
fprintf (stderr, "error: invalid input.nn");
empty_stdin (); /* remove any chars from stdin up to 'n' */
}
total += items[i];
}
printf ("ntotal (%d items): $%.2fn", size, total);
}
示例使用/输出
(显示输入中故意错误(
$ ./bin/checkout
How many items are you checking out today?: what?
error: invalid input.
How many items are you checking out today?: 4
price of item[ 1]: free?
error: invalid input.
price of item[ 1]: 1.25
price of item[ 2]: 3.50
price of item[ 3]: discount?
error: invalid input.
price of item[ 3]: 2.25
price of item[ 4]: 3
total (4 items): $10.00
仔细查看,如果您有其他问题,请告诉我。
数组的使用在用法方面没有区别。但是代码中需要的更改很少。
#define MAX_SIZE (10)
int size=0, i=0; //It is always better to initialize the variables.
float items[MAX_SIZE] = {0.0f}; //Automatically the entire array will be initialized to zero.
printf("How many items are you checking out today?");
scanf("%d", &size);
if(size > MAX_SIZE)
size = MAX_SIZE;
for(i=0;i<size;i++){
printf("Enter the price of an itemn");
scanf("%f", &items[i]); //You need to pass address of variable to scanf
}
还有其他方法可以实现代码以处理数组大小。这是其中一种方法。