我正在努力完成一项任务。我是C的新手,事情并没有像我希望的那样好。
我们的任务是编写一个小程序,通过命令行从用户那里获取输入,询问他们的名字,然后猜测幻数。我们有一个.txt文档,其中包含三个带有关联数字的名称。它的三行,每行都有一个名字,后跟一个空格,然后是数字。如果用户名不等于这三个中的一个,则幻数默认为12345.
每次猜测后,程序应该说出数字是太高还是太低,然后退出(是的,我不知道为什么)。
我一直在调试printf语句,但无法弄清楚为什么它不会进入代码的比较部分。
非常感谢任何帮助或提示!
#include <stdio.h>
#include <string.h>
typedef struct {
char list_name[20];
int list_num;
}list;
char user_name[20];
int user_magic_num;
main(){
FILE *fp;
int i;
list answers;
//
fp = fopen("answers.txt", "rb");
if(fp == NULL)
{
perror("Error opening file");
return(-1);
}
printf("\n Hi, what's your name? \n \n");
scanf("%s",user_name);
printf("\n Hello, %s! \n \n What's the magic number? \n \n",user_name);
scanf("%d", &user_magic_num);
printf("You guessed %d.\n\n", user_magic_num);
for (i=0; i<=4;i++)
{
fgets(answers.list_name, 20, fp);
puts(answers.list_name);
if (strcmp(answers.list_name,user_name)==0)
{
printf("entered first if statement");
if(user_magic_num==answers.list_num)
{
printf("You guess correctly! %d is the magic number!",
answers.list_num);
break;
}
else if(user_magic_num>answers.list_num)
{
printf("Too high.");
}
else if(user_magic_num<answers.list_num)
{
printf("Too low");
}
}
else
{
user_magic_num = 12345;
}
}
return 0;
}
*********编辑: #包括 #include
typedef struct list{
char list_name[20];
int list_num;
}list;
char user_name[20];
int user_magic_num;
main(){
FILE *fp;
int i;
list answers;
//
fp = fopen("answers.txt", "rb");
if(fp == NULL)
{
perror("Error opening file");
return(-1);
}
printf("\n Hi, what's your name? \n \n");
scanf("%s",user_name);
printf("\n Hello, %s! \n \n What's the magic number? \n \n",user_name);
scanf("%d", &user_magic_num);
printf("You guessed %d.\n\n", user_magic_num);
while (fscanf(fp, "%s %d",answers.list_name, &answers.list_num) != EOF)
{
//printf("%s\n", answers.list_name);
if(strcmp(user_name, answers.list_name)==0)
{
if (user_magic_num == answers.list_num)
{
printf("\nYes! %d is the magic number!\n", user_magic_num);
break;
}
else if (user_magic_num > answers.list_num)
{
printf("\nNope. Too high.\n");
break;
}
else
{
printf("\nNope. Too low.\n");
break;
}
}
else
{
answers.list_num = 12345;
printf("\nUser not recognized. Default magic number set.\n");
if (user_magic_num == answers.list_num)
{
printf("Yes! %d is the magic number!", user_magic_num);
break;
}
else if (user_magic_num > answers.list_num)
{
printf("\nNope. Too high.\n");
break;
}
else
{
printf("\nNope. Too low.\n");
break;
}
}
}
返回0; }
我刚刚这样做了。它现在可以工作,但仅适用于txt文件中的第一个名称。文本文件如下所示:
Bob 123
Mike 23
Rachel 345
但是只有当我输入Bob然后输入123时它才有效。但是如果我尝试Mike或者Rachel,它就像未知的那样对待它并将幻数重置为12345.我假设这是fscanf的东西,我'我做错了。
答案 0 :(得分:0)
loop
块中存在一些错误,请先单独阅读name
和magic_number
。然后你额外else if
检查了你的最后一次
else if 声明。
else if(user_magic_num<answers.list_num)
{
printf("Too low");
}
应该是
else
printf("Too low");
for循环中的一些修改:
for (i=0; i<2;i++)
{
fscanf(fp,"%s %d",answers.list_name,&answers.list_num);
puts(answers.list_name);
if (strcmp(answers.list_name,user_name)==0)
{
if(user_magic_num==answers.list_num)
{
printf("You guess correctly! %d is the magic number!\n",
answers.list_num);
break;
}
else if(user_magic_num>answers.list_num)
{
printf("Too high.\n");
}
else
{
printf("Too low\n");
}
}
else
user_magic_num = 12345;
}
答案 1 :(得分:0)
你可以这样做:
#include <stdio.h>
#include <string.h>
typedef struct {
char list_name[20];
int list_num;
}list;
char user_name[20];
int user_magic_num;
int main(){
FILE *fp;
int i;
list answers;
int matched = 0;
fp = fopen("answers.txt", "rb");
if(fp == NULL)
{
perror("Error opening file");
return -1;
}
printf("\n Hi, what's your name? \n \n");
scanf("%s",user_name);
printf("\n Hello, %s! \n \n What's the magic number? \n \n",user_name);
scanf("%d", &user_magic_num);
printf("You guessed %d.\n\n", user_magic_num);
/*
* i<3 - as per your description, your text document suppose to
* 3 names associated with numbers.
* You can change it as per your requirement.
*/
for (i=0; i<3; i++)
{
fscanf (fp, "%s %d", answers.list_name, &answers.list_num);
if(feof(fp))
{
puts("EOF");
break;
}
if (strcmp(answers.list_name,user_name)==0)
{
if(user_magic_num==answers.list_num)
{
printf("You guess correctly! %d is the magic number!\n", answers.list_num);
matched = 1;
break;
}
else if(user_magic_num>answers.list_num)
{
printf("Too high.\n");
}
else
{
printf("Too low.\n");
}
}
}
if (!matched)
{
user_magic_num = 12345;
printf ("Not matched\n");
/*
* Considering not matched as error and returning -1
*/
return -1;
}
return 0;
}
答案 2 :(得分:0)
char user_name[20]; /* avoid global variables unless absolutely */
int user_magic_num; /* required (that is almost never) */
在main
中声明您的变量,并根据需要将它们作为参数传递给任何函数。声明全局变量会增加名称冲突和变量阴影的风险,随着代码的增长,它们很难调试。
main(){
main
是int
类型的函数。它有两个C标准认可的有效声明:
int main (void) /* passes no arguments to main */
和
int main (int argc, char *argv[]) /* passes argc arguments in argv - use them */
(您还会看到等效的int main (int argc, char **argv)
)
有关main
的进一步讨论,请参阅:C11 Standard §5.1.2.2.1 Program startup (draft n1570)。另见:What should main() return in C and C++?
下一步:
return(-1); /* don't return negative values to the shell */
C为main
,
EXIT_SUCCESS /* 0 */
EXIT_FAILURE /* 1 */
(虽然它依赖于shell,但应避免返回负值)
验证所有输入 - 期间。特别是如果它来自用户(你知道猫可能只是踩在键盘上)。所有输入函数都有返回。至少,您必须验证返回以了解是否已成功接收输入。如果不这样做是邀请未定义的行为(这是一件非常糟糕的事情......)另外,如果您需要某个范围内的输入值,请验证输入是否在范围。
现在你的问题。所有面向行的输入函数(例如fgets
和POSIX getline
)都会读取和包括尾随'\n'
。它包含在它们填充的缓冲区中。使用fgets
是正确和推荐的方式来获取输入行(包括用户输入)。虽然scanf
家族有它的位置,但它是完整的或陷阱,只是等待陷阱新的C程序员。一次读一行到缓冲区,并从缓冲区中解析所需的值。 (为此目的使用sscanf
很好)
您的比较失败了,因为您没有认识到您使用fgets
正在将整行(或至少最多19
个字符)读入answers.list_name
,例如< / p>
fgets(answers.list_name, 20, fp);
不要对缓冲区吝啬。当然要让它们合理,但我更喜欢256-chars to big,而不是1-char太短......(下面我简单地声明一个128-byte
缓冲区来读取文件的每一行。)
逻辑。快速逻辑图表示您将如何获得输入,需要对每个变量进行哪些测试,何时要求其他输入,如何响应输入等等。使用铅笔在8.5x11上勾画出来可以节省您几小时的凝视时间在屏幕上希望灵感来袭。 (当你只是坐在屏幕上猜测变化并反复重新编译时,很少会这样做 - 只是让它再次失败)。清晰的逻辑和清晰的路线图表明您需要完成的工作将为您节省时间。
将上述内容放在一起,并抓住可靠的8.5x11和一支铅笔,看来你正试图:
将用户名作为用户输入
打开并读取您的文件以匹配用户名,然后阅读 幻数(如果找不到名字,则出错)
将一个幻数作为用户输入
提示用户最多猜5次猜测数字
为下一次猜测提供过高和过低的提示
如果找不到这个名字该怎么办?
以下是对我的意图的抨击。仔细查看代码,了解每一行,如果你没有 - 然后问。 注意:程序希望文件名作为程序的第一个参数读取。利用该能力而不是在代码中对路径/文件名进行硬编码。
另请注意下面使用常量。切勿在代码中对值进行硬编码(具有讽刺意味的是 magic-numbers )。定义一个常量或两个向上的顶部提供了一个方便的位置,可以根据需要进行更改 - 无需选择所有变量和循环声明来进行必要的更改。
对于scanf
字段宽度限制(注意:),您只是被卡住了 - 这些必须是硬编码的,这是另一个原因{{1} }(或fgets
)是首选)
( note2:我故意在您的代码中留下一行评论getline
并提出问题以便您回答)
//
示例使用/输出
#include <stdio.h>
#include <string.h>
#define MAXC 20 /* define constants when you need one */
#define MAX_TRIES 5
#define BUFSZ 128
typedef struct {
char list_name[MAXC];
int list_num;
} list;
int main (int argc, char **argv) {
int i = 0, /* always good to initialize variables */
name_found = 0,
user_magic_num = 0;
char user_name[MAXC] = "",
buf[BUFSZ] = "";
size_t len = 0;
list answers = { "", 0 };
FILE *fp = NULL;
if (argc != 2) { /* validate argument given on command-line */
fprintf (stderr, "error: insufficient input.\n"
"usage: %s filename\n", argv[0]);
return 1;
}
/* open / validate file open for reading */
if (!(fp = fopen (argv[1], "r"))) {
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
printf ("\n Hi, what's your name?: ");
if (scanf ("%19s", user_name) != 1) { /* validate ALL input */
fprintf (stderr, "error: invalid input or EOF - user_name.\n");
return 1;
}
while (fgets (buf, BUFSZ, fp)) { /* read each line from file into buf */
/* fgets reads and *includes* the trailing '\n' in buf, remove it */
len = strlen (buf); /* get length */
if (len && buf[len - 1] == '\n') /* check trailing '\n' */
buf[--len] = 0; /* overwite with nul-char */
else {
/* handle error - string too long */
}
/* separate buffer into answers.list_name and answers.list_num */
if (sscanf (buf, "%19s %d", answers.list_name, &answers.list_num) != 2) {
fprintf (stderr, "error: failed to parse name and num from line.\n");
return 1;
}
if (strcmp (answers.list_name, user_name) == 0) {
name_found = 1; /* flag - name found in file */
break;
}
}
fclose (fp); /* close file - you are done with it */
if (!name_found) {
fprintf (stderr, "error: name '%s' not found in file.\n", user_name);
return 1;
}
printf ("\n Hello, %s! \n \n What's the magic number?: ",user_name);
if (scanf ("%d", &user_magic_num) != 1) { /* ditto */
fprintf (stderr, "error: invalid input or EOF - user_magic_num.\n");
return 1;
}
printf (" You guessed: %d\n\n", user_magic_num);
for (i = 0; i < MAX_TRIES; i++) /* avoid <= (unless required) */
{
if (user_magic_num == answers.list_num) {
printf ("You guessed correctly! %d is the magic number!\n",
answers.list_num);
return 0;
}
else if (user_magic_num > answers.list_num)
printf ("Too high.\n\n");
else
printf ("Too low.\n\n");
printf (" What's your next guess %s?: ", user_name);
if (scanf ("%d", &user_magic_num) != 1) {
fprintf (stderr, "error: invalid input - user_magic_num\n");
return 1;
}
putchar ('\n');
}
fprintf (stderr, "Oops: tries exceed max (%d)\n", MAX_TRIES);
return 0;
}
如果user_name不在文件中怎么办?
$ ./bin/magicnum2 dat/magicnum.txt
Hi, what's your name?: Mike
Hello, Mike!
What's the magic number?: 100
You guessed: 100
Too high.
What's your next guess Mike?: 10
Too low.
What's your next guess Mike?: 20
Too low.
What's your next guess Mike?: 25
Too high.
What's your next guess Mike?: 23
You guessed correctly! 23 is the magic number!
如果我没有从问题中收集你的意图,请告诉我,我很乐意进一步提供帮助。
最后,每次编译时都不要忘记启用编译器警告。这意味着$ ./bin/magicnum2 dat/magicnum.txt
Hi, what's your name?: Frank
error: name 'Frank' not found in file.
至少-Wall -Wextra
或gcc
(或/W3
)至/W4
(windoze上的VS)至少cl.exe
。要获得更全面的警告,您可以-pedantic
添加gcc
或/Wall
使用cl.exe
。在没有警告的情况下完全编译之前,请不要接受代码。你可以通过阅读和理解编译器告诉你的内容来学习更多的C,而不是大多数教程......