C 程序在 if/else 之后终止,或者如果我使用 fputs/fgets 则重复
我对 C 非常陌生,并且涉足过 Objective-C、AppleScript 和 HTML/CSS。我确信我的问题很容易解决。我正在尝试编写一些内容,允许我输入源数据并以某种方式将其排序作为输出(在本例中为引用)。基本上,我想将名称、标题、出版商等保存为变量并按一定顺序打印它们。
问题是:这里的代码终止得太早,当我将 fputs 和 fgets 与 stdout 和 stdin 一起使用时,它会卡住并永远询问相同的问题。我缺少什么?
int source_type;
int NumberofAuthors;
char AuthorName1[20];
char AuthorName2[20];
char AuthorName3[20];
char title[20];
char url[100];
char publishingCity[20];
char publisher[20];
char yearPublished[20];
char pageNumbers[20];
int valid;
printf("Welcome to Jackson's Chicago Manual of Style Auto-Footnoter.\n");
fputs("Choose source type:\n a.Book\n b.Journal\n c.Article\n d.Website\n ", stdout);
source_type = getchar();
if (source_type == 'a') {
valid = 1;
} else {
printf("Invalid source selection");
}
while ( valid == 1 && source_type == 'a' )
{
printf("Number of authors [1 or 2]: ");
scanf( "%d", &NumberofAuthors);
if ( NumberofAuthors > 0 && NumberofAuthors < 3 ) {
valid = 1;
printf("Got it, %d author(s).\n", NumberofAuthors);
}
else {
printf( "That's not enough people to write a book.\n" );
}
if ( NumberofAuthors == 1 ) {
printf( "Author's name: " );
scanf("%c", &AuthorName1);
}
if (NumberofAuthors == 2) {
printf("First author's name: " );
scanf("%c", &AuthorName2);
printf("Second author's name: " );
scanf("%c", &AuthorName3);
}
else {
valid = 0;
}
printf("Book title: " );
fgets(title, sizeof(title), stdin);
printf("Publication city: " );
fgets(publishingCity, sizeof(publishingCity), stdin);
}
return 0;
I am very new to C and have dabbled in Objective-C, AppleScript, and HTML/CSS. I'm sure that my problem is very easy to solve. I am trying to write something that will allow me to input source data and have it ordered in a certain way as output (in this case, citations). Basically, I want to save name, title, publisher, etc. as variables and print them in a certain order.
Here's the issue: The code here terminates too early and when I use fputs and fgets with stdout and stdin it gets stuck and asks the same question forever. What am I missing?
int source_type;
int NumberofAuthors;
char AuthorName1[20];
char AuthorName2[20];
char AuthorName3[20];
char title[20];
char url[100];
char publishingCity[20];
char publisher[20];
char yearPublished[20];
char pageNumbers[20];
int valid;
printf("Welcome to Jackson's Chicago Manual of Style Auto-Footnoter.\n");
fputs("Choose source type:\n a.Book\n b.Journal\n c.Article\n d.Website\n ", stdout);
source_type = getchar();
if (source_type == 'a') {
valid = 1;
} else {
printf("Invalid source selection");
}
while ( valid == 1 && source_type == 'a' )
{
printf("Number of authors [1 or 2]: ");
scanf( "%d", &NumberofAuthors);
if ( NumberofAuthors > 0 && NumberofAuthors < 3 ) {
valid = 1;
printf("Got it, %d author(s).\n", NumberofAuthors);
}
else {
printf( "That's not enough people to write a book.\n" );
}
if ( NumberofAuthors == 1 ) {
printf( "Author's name: " );
scanf("%c", &AuthorName1);
}
if (NumberofAuthors == 2) {
printf("First author's name: " );
scanf("%c", &AuthorName2);
printf("Second author's name: " );
scanf("%c", &AuthorName3);
}
else {
valid = 0;
}
printf("Book title: " );
fgets(title, sizeof(title), stdin);
printf("Publication city: " );
fgets(publishingCity, sizeof(publishingCity), stdin);
}
return 0;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在程序开始时:
如果
source_type
无效,valid
仍然包含垃圾值,并且使用未初始化的变量是未定义的行为。继续前进。您从未将
valid
重置为0
。您应该考虑对 while 循环的该部分使用switch()
。它使它更容易阅读。另外
我希望您意识到,如果
NumberofAuthors == 1
则else
部分将被执行并设置valid = 0
。这是因为 else 只粘在最接近的 if 上,且仅此而已。我猜你使用 fgets 等来避免溢出。好的。请参阅
scanf
上的技巧。在这里阅读更多信息: http://www.cplusplus.com/reference/clibrary/cstdio/ scanf/尝试一下:
On the beggining of the program:
In case
source_type
is invalid,valid
still contains garbage value, and using an uninitialized variable is undefined behaviour. Moving on.You never reset
valid
to0
. You should consider using aswitch()
for that part of the while loop. It makes it more easy to read.Also
I hope you realize that incase
NumberofAuthors == 1
theelse
part is going to executed and setvalid = 0
. That is because the else sticks on just the closest if, and only that.I guess you use fgets etc to avoid overflows. Good. See that trick on the
scanf
s. Read more here : http://www.cplusplus.com/reference/clibrary/cstdio/scanf/Try that:
您只能在
while
循环之外更改source_type
,因此一旦进入循环,退出循环的唯一方法就是将0
分配给有效
。每次NumberofAuthors != 2
时都会执行此操作,因为第一个if
不在if-else
链内。也许你想要这个:You only change
source_type
outside of thewhile
loop, so once entered the loop the only way to get out is by assigning0
tovalid
. This is done every timeNumberofAuthors != 2
, since the firstif
is not within theif-else
chain. Perhaps you want this instead:您正在使用
%c
读取名称;这不好。您传递的是数组的地址,而不是指向数组第一个元素的指针;这也不好。你到处践踏,给自己留下了不确定的行为问题。“显而易见”的修复方法是使用
%s
并放弃数组名称前面的&
,但您不能屈服于显而易见的事实,因为它是错误的。大多数作者的名字和姓氏(或姓名首字母和姓氏)之间有一个空格,并且%s
在第一个空格处停止。您需要使用 fgets() 来读取名称,但请记住删除尾随换行符。我不太清楚为什么“AuthorName1”中有一个作者的名字,但“AuthorName2”和“AuthorName3”中有双作者的名字;无论如何,我希望对第一作者使用“name 1”。事实上,最好有一系列作者姓名,这样更容易概括。
当我编译您的代码时(将其包装在
int main(void) {
和}
并包括
中,我得到编译警告:我重写了代码以使用函数来处理字符串的提示和读取,因此:
我保留了“有效”标志,但如果没有它,它确实不值得。
You are using
%c
to read names; this is not good. You're passing the address of an array, rather than the pointer to the first element of the array; this is also not good. You are trampling all over the place, and leaving yourself with undefined behaviour problems.The 'obvious' fix is to use
%s
and forego the&
in front of the array names, but you must not succumb to the obvious as it is wrong. Most authors have a space between the first and last name (or initials and surname), and%s
stops at the first space. You need to usefgets()
to read the names, but remember to remove the trailing newline.It is not quite clear to me why you have a single author's name in 'AuthorName1' but double authors go in 'AuthorName2' and 'AuthorName3'; I'd expect to use 'name 1' for the first author regardless. Indeed, it might be better to have an array of author names - that generalizes more readily.
When I compile your code (wrapping it in
int main(void) {
and}
and including<stdio.h>
, I get compilation warnings:I rewrote the code to use a function to handle the prompting for and reading of strings, thus:
I kept the 'valid' flag, but it really doesn't pay for itself. The code is simpler and shorter without it.