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;
3 ответа
В начале программы:
if (source_type == 'a') {
valid = 1;
} else {
printf("Invalid source selection");
}
В случае source_type
является недействительным, valid
все еще содержит значение мусора, и использование неинициализированной переменной является неопределенным поведением. Двигаемся дальше.
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);
}
//...
Вы никогда не сбрасываете valid
в 0
, Вы должны рассмотреть возможность использования switch()
для этой части цикла while. Это облегчает чтение.
Также
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;
}
Я надеюсь, что вы понимаете, что дело NumberofAuthors == 1
else
часть будет выполнена и установлена valid = 0
, Это потому, что остальное прилипает только к ближайшему if и только к этому.
Я полагаю, вы используете fgets и т.д., чтобы избежать переполнения. Хорошо. Посмотрите на этот трюк на scanf
s. Читайте больше здесь: http://www.cplusplus.com/reference/clibrary/cstdio/scanf/
Попробуй это:
int main(int argc, char* argv[])
{
char 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");
printf("Choose source type:\n a.Book");
scanf("%c" , &source_type);
if (source_type == 'a') {
valid = 1;
} else {
printf("Invalid source selection");
valid = 0;
}
while ( valid == 1 && source_type == 'a' )
{
//Reset
valid = 0;
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" );
continue;
}
switch( NumberofAuthors )
{
case 1:
printf( "Author's name: " );
scanf("%19s", AuthorName1);
break;
case 2:
printf("First author's name: " );
scanf("%19s", AuthorName2);
printf("Second author's name: " );
scanf("%19s", AuthorName3);
break;
default:
valid = 0;
break;
}
if(valid)
{
printf("Book title: " );
scanf("%19s" , title);
printf("Publication city: " );
scanf("%19s" , publishingCity );
}
}
return 0;
}
Ты используешь %c
читать имена; это не хорошо. Вы передаете адрес массива, а не указатель на первый элемент массива; это тоже не хорошо. Вы растоптаны повсюду и оставляете себя с неопределенными проблемами в поведении.
"Очевидное" решение заключается в использовании %s
и отказаться от &
перед именами массивов, но вы не должны поддаваться очевидному, поскольку это неправильно. У большинства авторов есть пробел между именем и фамилией (или инициалами и фамилией), и %s
останавливается на первом месте. Вам нужно использовать fgets()
читать имена, но не забудьте удалить завершающий перевод строки.
Мне не совсем понятно, почему у вас есть имя одного автора в "AuthorName1", но двойные авторы идут в "AuthorName2" и "AuthorName3"; Я бы предпочел использовать "имя 1" для первого автора независимо от. В самом деле, может быть, лучше иметь массив имен авторов, который будет легче обобщать.
Когда я компилирую твой код int main(void) {
а также }
и в том числе <stdio.h>
Я получаю предупреждения компиляции:
xx.c: In function ‘main’:
xx.c:43: warning: format ‘%c’ expects type ‘char *’, but argument 2 has type ‘char (*)[20]’
xx.c:43: warning: format ‘%c’ expects type ‘char *’, but argument 2 has type ‘char (*)[20]’
xx.c:48: warning: format ‘%c’ expects type ‘char *’, but argument 2 has type ‘char (*)[20]’
xx.c:48: warning: format ‘%c’ expects type ‘char *’, but argument 2 has type ‘char (*)[20]’
xx.c:50: warning: format ‘%c’ expects type ‘char *’, but argument 2 has type ‘char (*)[20]’
xx.c:50: warning: format ‘%c’ expects type ‘char *’, but argument 2 has type ‘char (*)[20]’
Я переписал код, чтобы использовать функцию для обработки запроса и чтения строк, таким образом:
#include <assert.h>
#include <stdio.h>
#include <string.h>
static int get_string(const char *prompt, char *buffer, size_t bufsiz)
{
char *nl;
printf("%s: ", prompt);
fflush(0);
if (fgets(buffer, bufsiz, stdin) == 0)
return EOF; /* Read error - EOF */
if ((nl = strchr(buffer, '\n')) == 0)
{
fprintf(stderr, "Overlong string entered!\n");
return EOF;
}
*nl = '\0';
return 0;
}
int main(void)
{
int source_type;
int NumberofAuthors;
char AuthorName1[20];
char AuthorName2[20];
char title[20];
char publishingCity[20];
int valid = 0;
int c;
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");
return(1);
}
/* Lucky that scanf() skips over the newline in search of digits! */
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 (or too many) people to write a book.\n");
break;
}
/* Gobble to newline */
while ((c = getchar()) != EOF && c != '\n')
;
if (NumberofAuthors == 1)
{
if (get_string("Author's name", AuthorName1, sizeof(AuthorName1)) == EOF)
{
valid = 0;
break;
}
}
else
{
assert(NumberofAuthors == 2);
if (get_string("First author's name", AuthorName1, sizeof(AuthorName1)) == EOF ||
get_string("Second author's name", AuthorName2, sizeof(AuthorName2)) == EOF)
{
valid = 0;
break;
}
}
if (get_string("Book title", title, sizeof(title)) == EOF ||
get_string("Publication city", publishingCity, sizeof(publishingCity)) == EOF)
{
valid = 0;
break;
}
printf("Author 1: %s\n", AuthorName1);
if (NumberofAuthors == 2)
printf("Author 2: %s\n", AuthorName2);
printf("Book title: %s\n", title);
printf("Publication city: %s\n", publishingCity);
}
return 0;
}
Я сохранил флаг 'valid', но он действительно не окупается. Код проще и короче без него.
Вы только меняете source_type
за пределами while
цикл, поэтому, как только вошел в цикл, единственный способ выйти из него, назначив 0
в valid
, Это делается каждый раз NumberofAuthors != 2
, так как первый if
не в пределах if-else
цепь. Возможно, вы хотите это вместо этого:
if ( NumberofAuthors == 1 ) {
printf( "Author's name: " );
scanf("%c", &AuthorName1);
} else if (NumberofAuthors == 2) {
printf("First author's name: " );
scanf("%c", &AuthorName2);
printf("Second author's name: " );
scanf("%c", &AuthorName3);
} else {
valid = 0;
}