使用多个提示和scanf运行C代码的更好方法
我正在用C编写一个简单的程序,其中我需要计算平均值等。我的第一个功能是提示用户参数,这些参数(我假设)存储在全局变量中,以便我可以在其他功能中使用它们,如“计算MIPS”等使用多个提示和scanf运行C代码的更好方法,c,loops,printf,scanf,C,Loops,Printf,Scanf,我正在用C编写一个简单的程序,其中我需要计算平均值等。我的第一个功能是提示用户参数,这些参数(我假设)存储在全局变量中,以便我可以在其他功能中使用它们,如“计算MIPS”等 我的问题是,当我调用函数收集用户的输入时,程序在第一次提示后停止。总共有7个提示。有人知道我做错了什么吗?为了能够询问所有提示并存储值,我可以做些什么建议?我在考虑使用while循环,但我不确定当值都存储在全局变量中时如何终止循环。我肯定我把一个简单的问题复杂化了 您会遇到UB,因为这不是使用scanf的方法 scanf(“
我的问题是,当我调用函数收集用户的输入时,程序在第一次提示后停止。总共有7个提示。有人知道我做错了什么吗?为了能够询问所有提示并存储值,我可以做些什么建议?我在考虑使用while循环,但我不确定当值都存储在全局变量中时如何终止循环。我肯定我把一个简单的问题复杂化了 您会遇到UB,因为这不是使用
scanf
的方法
scanf(“%d”和&variable\u name)
用于整数,但使用的格式错误(“%s”
)+传递变量值(…variable\u name
)而不是变量adress(&variable\u name
请注意&)您会遇到UB,因为这不是使用scanf
的方法
scanf(“%d”和&variable\u name)
用于整数,但这样做时,您使用了错误的格式(“%s”
)+传递变量值(…variable\u name
)而不是变量adress(&variable\u name
请注意&)
这将有助于您了解scanf的工作原理。正如另外两个人所说,您应该使用%d
而不是%s
,并且在变量之前需要一个与。如果你已经学会了指针,你就会知道为什么你需要符号,如果没有,现在不要担心,以后你会学会的
我给你的链接也给了你其他数据类型的%命令。大多数数据类型都有不同的字母,例如%s
表示字符串(字符数组),而%lf
表示双精度
希望这有帮助
这将有助于您了解scanf的工作原理。正如另外两个人所说,您应该使用%d
而不是%s
,并且在变量之前需要一个与。如果你已经学会了指针,你就会知道为什么你需要符号,如果没有,现在不要担心,以后你会学会的
我给你的链接也给了你其他数据类型的%命令。大多数数据类型都有不同的字母,例如%s
表示字符串(字符数组),而%lf
表示双精度
希望这有帮助 对整数使用scanf(“%d”和&VariableName)
,对字符数组(字符串)使用scanf(“%s”和&arrCHar)
此外,在调用函数之前必须先声明函数原型。对于整数使用scanf(“%d”和&VariableName)
,对于字符数组(字符串)使用scanf(“%s”和&arrCHar)
此外,在调用函数之前,您必须先声明函数原型。虽然您发现格式说明符的错误使用以及在
scanf
中需要指向变量的指针是您的主要问题,但正确使用scanf
还有一个方面尚未解决
您不能简单地编写scanf(“%d”和&intr\u类)
在不验证返回值的情况下获取用户输入,以确保成功转换为整数。您必须这样做,才能确信intr\u class
持有有效值。(如果您有任何此类要求,在尝试使用intr\u class
之前,您还需要确保该值在可接受的范围内)
这适用于所有用户输入,不管您使用什么函数进行输入,但它特别适用于scanf
。如果用户在响应您的提示时输入了错误的内容,例如:
Enter the number of instruction classes: rabbits
然后呢?除非您检查返回,否则您永远不会知道intr\u class
未设置,如果未初始化,则任何访问该值的尝试都是未定义的行为
此外,scanf
在遇到错误时停止读取,stdin
中没有读取任何字符。那么当你尝试阅读其他东西时会发生什么呢?让我们考虑一个例子:
Enter the frequency of the machine (MHz): 800
这个条目成功还是失败?(答:失败)为什么stdin
仍然包含“rabbits\n800\n”
(每次用户按Enter键时都会添加'\n'
,并且每次输入都不会失败的唯一原因是'%d'
格式说明符使用前导空格),但“rabbits”
不是空格…)
因此,对于用户输入,您必须加倍小心使用scanf
,不仅要考虑转换是否成功,还要考虑输入缓冲区中剩余的任何字符(如果您的下一种输入类型不使用前导空格或转换失败后输入缓冲区中剩余的任何字符,请使用'\n'
)
管理此操作的一种方法是在每次调用scanf
后手动删除stdin
中保留的任何字符(注意:应该检查返回值是否不是EOF
)。在调用scanf
并检查返回值是否为EOF
后,您只需调用一个简单函数即可读取并丢弃所有剩余字符,如:
/* function to empty remaining characters in stdin before next input
* to help avoid the pitfalls associated with using scanf for user input.
*/
void emptystdin()
{
int c = getchar();
for (; c != '\n' && c != EOF; c = getchar()) {}
}
还应避免使用全局变量,以及使用struct
保存所有参数的非常好的建议。如果定义一个struct(称之为struct parameters\u t
),请在main()
中创建并声明它的实例(例如一个称为parameters
),则只需将参数的地址传递给参数()
#include <stdio.h>
#include <stdlib.h>
/* declare a struct to associate all the values */
typedef struct {
int intr_class,
freq,
class1,
cpi_1,
class2,
cpi_2,
class3,
cpi_3;
} parameters_t;
/* function to empty remaining characters in stdin before next input
* to help avoid the pitfalls associated with using scanf for user input.
*/
void emptystdin()
{
int c = getchar();
for (; c != '\n' && c != EOF; c = getchar()) {}
}
/* params takes pointer to (address of) a struct parameters_t and
* prompts for and fills each value. a tmp struct is used to avoid
* changing any values in 'p' in case of a partial fill. returns
* address of p on success, NULL otherwise indicating error.
*/
parameters_t *params (parameters_t *p){
parameters_t tmp = { .intr_class = 0 };
printf ("Enter the number of instruction classes: ");
if (scanf ("%d", &tmp.intr_class) != 1)
return NULL;
printf ("Enter the frequency of the machine (MHz): ");
if (scanf ("%d", &tmp.freq) != 1)
return NULL;
printf ("Enter CPI of class 1: ");
if (scanf ("%d", &tmp.cpi_1) != 1)
return NULL;
printf ("Enter instruction count of class 1 (millions): ");
if (scanf ("%d", &tmp.class1) != 1)
return NULL;
printf ("Enter CPI of class 2: ");
if (scanf ("%d", &tmp.cpi_2) != 1)
return NULL;
printf ("Enter instruction count of class 2 (millions): ");
if (scanf ("%d", &tmp.class2) != 1)
return NULL;
printf ("Enter CPI of class 3: ");
if (scanf ("%d", &tmp.cpi_3) != 1)
return NULL;
printf ("Enter instruction count of class 3 (millions): ");
if (scanf ("%d", &tmp.class3) != 1)
return NULL;
*p = tmp; /* assign temp values to struct p */
return p;
}
/* simple function to print values stored in p */
void prnparams (parameters_t *p)
{
if (!p || p->intr_class == 0) {
fprintf (stderr, "error: parameters empty or NULL\n");
return;
}
printf ("parameters:\n"
" instruction classes: %d\n"
" frequency (MHz) : %d\n"
" CPI of class 1 : %d\n"
" class 1 inst count : %d\n"
" CPI of class 2 : %d\n"
" class 2 inst count : %d\n"
" CPI of class 3 : %d\n"
" class 3 inst count : %d\n",
p->intr_class, p->freq, p->cpi_1, p->class1,
p->cpi_2, p->class2, p->cpi_3, p->class3);
}
int main (void) {
char menuchoice;
/* declare a struct & iniailize all values zero */
parameters_t parameters = { .intr_class = 0 };
for (;;) { /* loop until user quits */
/* print out menu list */
printf ("\nMenu of Options:\n"
"______________\n"
" a) Enter Parameters\n"
" b) Calculate average CPI of a sequence of instructions\n"
" c) Calculate total execution time of a sequence of "
"instructions\n"
" d) Calculate MIPS of a sequence of instructions\n"
" p) Print stored values\n"
" e) Quit\n\n"
"Enter selection: ");
if (scanf ("%c", &menuchoice) == EOF) { /* check user cancels input */
putchar ('\n'); /* tidy up before exit */
break;
}
if (menuchoice != '\n') /* make sure user didn't just hit [Enter] */
emptystdin(); /* remove all chars from stdin */
switch(menuchoice){
case 'a':
if (!params(¶meters))
fprintf (stderr, "error: params() failed.\n");
emptystdin(); /* critical here or menuchoice would be '\n' */
break;
case 'b':
//avgCPI();
break;
case 'c':
//calcExTime();
break;
case 'd':
//calcMIPS();
break;
case 'p':
prnparams (¶meters);
break;
case 'e':
exit(0);
default:
fprintf (stderr, "error: invalid menuchoice.\n");
break;
}
}
return 0;
}
$ ./bin/scanfparams
Menu of Options:
______________
a) Enter Parameters
b) Calculate average CPI of a sequence of instructions
c) Calculate total execution time of a sequence of instructions
d) Calculate MIPS of a sequence of instructions
p) Print stored values
e) Quit
Enter selection: a
Enter the number of instruction classes: 10
Enter the frequency of the machine (MHz): 20
Enter CPI of class 1: 30
Enter instruction count of class 1 (millions): 40
Enter CPI of class 2: 50
Enter instruction count of class 2 (millions): 60
Enter CPI of class 3: 70
Enter instruction count of class 3 (millions): 80
Menu of Options:
______________
a) Enter Parameters
b) Calculate average CPI of a sequence of instructions
c) Calculate total execution time of a sequence of instructions
d) Calculate MIPS of a sequence of instructions
p) Print stored values
e) Quit
Enter selection: p
parameters:
instruction classes: 10
frequency (MHz) : 20
CPI of class 1 : 30
class 1 inst count : 40
CPI of class 2 : 50
class 2 inst count : 60
CPI of class 3 : 70
class 3 inst count : 80
Menu of Options:
______________
a) Enter Parameters
b) Calculate average CPI of a sequence of instructions
c) Calculate total execution time of a sequence of instructions
d) Calculate MIPS of a sequence of instructions
p) Print stored values
e) Quit
Enter selection: e