2013-11-23 6 views
0

Мне нужно получить одну строку символов и преобразовать их из базы, на которой они записаны, в десятичную базу, , как только набирается символ.Проблемы с getchar C

Я сделал это с помощью следующей функции:

int inToDec(int base) //My assumption is that Enter will not be pressed as the first character - if it is, I am not sure what to do in that case 
{ 
    int numdec=0, c;//decimalized number, a variable for character inpu 
    while((c = getchar()) != '\n' && c != EOF) 
    { 
     if(c >= 97)//Checks if the char is an actual char 
      c = c - 'a' - 1; 
     else//or a digit char 
      c = c; 
     numdec += numdec * base + c;//every time another char is inputted, it multiplies the numdec by the base and adds the char's value in decimal base - which is essentially the algorithm for conversion to decimal base. 
    } 
    return numdec; 
} 

Мой главный():

#include <stdio.h> 
#include "funcs.h" 

int main() 
{ 
    int option, fbase, tbase, num1, num2; 
    do 
    { 
     scanf("%d",&option); 
     switch(option) 
     { 
     case 1: 
      scanf("%d",&fbase); 
      num1 = inToDec(fbase); 
      num2 = inToDec(fbase); 
      outFromDec(num1+num2,fbase); 
      break; 
     case 2: 
      scanf("%d",&fbase); 
      num1 = inToDec(fbase); 
      num2 = inToDec(fbase); 
      if(num1>=num2) 
       outFromDec(num1-num2,fbase); 
      else 
       outFromDec(num2-num1,fbase); 
      break; 
     case 3: 
      scanf("%d",&fbase); 
      scanf("%d",&tbase); 
      num1 = inToDec(fbase); 
      outFromDec(num1,tbase); 
      break; 
     } 
    }while(option != 4); 
    return 0; 
} 

исключением того, что, когда я ввести номер (после параметра и требуемое основание) и типа Войдите, чтобы перейти к следующему, внезапно он начинает печатать символ время за раз, без конца. Что я сделал не так, и как мне это исправить? Или, если вы не хотите объяснять какой-то очевидный факт для noob, где я читаю об этом (желательно без слишком тяжелых технических разговоров, поскольку я относительно новичок в программировании).

outFromDec() -

void outFromDec(int num, int base) //converts num into the base given and prints 
{ 
    int count = 0 , temp = num, i; 
    char c; 
    while(temp != 0) 
    { 
     temp /= base; 
     count++; 
    } 
    temp = num; 
    do 
    { 
     for(i=1;i<count;i++) 
      temp /= base; 
     if(temp<=9) 
      c = '0' + temp; 
     else 
      c = 'a' + temp - 1; 
     putchar(c); 
     count--; 
     temp = num/temp; 
    }while(temp != 0); 
} 
+0

Вы ничего не печатаете и на какой платформе вы находитесь? – haccks

+1

Платформа? Не получите то, что вы просите, но если вы имеете в виду ОС и программное обеспечение, то я использую Visual C++ 2010 в Windows 7. – Sunspawn

+0

Я спрашивал об ОС. Теперь опубликуйте функцию 'outFromDec', это поможет нам отладить ваш код. :) – haccks

ответ

3

Этот код имеет проблемы:

while(c = getchar() != '\n' && c != EOF) 

достаточно не круглые скобки - назначение оператора низкий приоритет. Оно должно быть:

while ((c = getchar()) != '\n' && c != EOF) 

Другой набор проблем в коде преобразования в теле цикла:

if (c >= 97) 
     c = c - 'a' - 1; 
    else 
     c = c; 
    numdec += numdec * base + c; 

Выбор 97 является предположительно ASCII или ISO 8859- п или Кодовая точка Unicode для a. Это игнорирует буквы верхнего регистра, знаки пунктуации и обрабатывает цифры 0 до 9, как будто они 48..57. Вероятно, вам нужно использовать #include <ctype.h>. Он также не подтверждает, что «цифра» действительна для базы.

Однако при первом обращении к intToDec() первый символ, прочитанный символом, является символом новой строки, оставленным scanf(), поэтому первое число всегда равно нулю, если вы вводите цифры по одному в строке, как вам сказали.

Когда вы наконец доберетесь до outToDec(), у вас есть интересная нумерология. Я добавил printf() заявление для отслеживания входа функции и выхода, а также для ключевых точек в цикле:

void outFromDec(int num, int base) 
{ 
    printf("-->> %s: %d %d\n", __func__, num, base); 
    int count = 0, temp = num, i; 
    char c; 
    while (temp != 0) 
    { 
     temp /= base; 
     count++; 
    } 
    printf("Count: %d\n", count); 
    temp = num; 
    do 
    { 
     printf("count: %d; temp = %d\n", count, temp); 
     for (i = 1; i < count; i++) 
      temp /= base; 
     if (temp <= 9) 
      c = '0' + temp; 
     else 
      c = 'a' + temp - 1; 
     putchar(c); 
     count--; 
     temp = num/temp; 
    } while (temp != 0); 
    printf("<<-- %s\n", __func__); 
} 

__func__ является предопределенным идентификатором в C99, содержащее имя функции. Он может быть недоступен для вас в MSVC; если нет, замените его именем функции.

Для входов 1, 9, 9, выход из программы был:

-->> inToDec: 9 
<<-- inToDec: 0 
-->> inToDec: 9 
<<-- inToDec: 57 
-->> outFromDec: 57 9 
Count: 2 
count: 2; temp = 57 
6count: 1; temp = 9 
9count: 0; temp = 6 
6count: -1; temp = 9 
9count: -2; temp = 6 

И граф продолжал уменьшаться, а 6-х и 9-х продолжали чередовать.Кажется, вы пытаетесь изолировать цифры с самой значащей цифрой (MSD), обнаруженной в первую очередь. Петля, определяющая count, верна; цикл печати цифр явно нет. Вы должны быть в состоянии взять это оттуда; это обычная отладка. Обратите внимание, как я использовал заявления печати, чтобы узнать, что происходит. Если вы не можете решить проблему, просто просмотрев код, при необходимости распечатайте результат каждого выражения.

Я заметил, что для печати 57 в базе 10 вы обнаружили, что для печати есть 2 цифры (count == 2). Первая цифра будет найдена путем деления на основание (10) count-1 раз; это даст вам 5 для печати. Вероятно, вам нужно вычесть 5 * 10 из числа, так что следующее (в данном случае, последнее) время вокруг цикла, вы начнете с 7, которые вы будете печатать. Цикл остановится. Вы должны обеспечить разрывы цикла, если count когда-либо будет отрицательным.

Это дорогой способ форматирования 10-значного 32-разрядного номера (или, что еще более важно, 19-разрядного 64-битного номера). Однако его можно заставить работать. Стандартная процедура собирает цифры в обратном порядке и организует их распечатку в обратном порядке. (number % base дает цифру, которая будет напечатана, number /= base уменьшает количество цифр слева обрабатывать.)


Как происходит довольно часто, то ФП в искусственных ограничений и не может использовать строки. Тьфу!

Вот функция «читать целое число», которая является правдоподобной. Это предполагает арифметику дополнения 2; он содержит утверждение, которое должно срабатывать, если оно когда-либо запускалось на машине, которая была знаковой величиной или дополнением 1 (но я ее не тестировал, у меня нет таких машин, доступных для тестирования).

Обратите внимание, что код накапливает число как отрицательное число и делает его положительным в конце, если он должен быть положительным. Это облегчает работу с INT_MIN, чем попытка накопить его как положительный int.

Для целей упражнения я рассматриваю систему как бы sizeof(intmax_t) == sizeof(int) (и, следовательно, sizeof(int) == sizeof(long) и sizeof(int) == sizeof(long long)); этот метод будет работать, если целочисленный тип был intmax_t вместо int. Обратите внимание, что стандарт C не исключает эту предполагаемую конфигурацию (но для стандарта требуется, чтобы CHAR_BIT * sizeof(int) >= 64 соответствовала реализации).

#include <assert.h> 
#include <ctype.h> 
#include <limits.h> 
#include <stdio.h> 

/* Read an integer from stdin without prompt: code is not allowed to use strings! */ 
enum { E_OK = 0, E_EOF = -1, E_INVCHAR = -2, E_OVERFLOW = -3 }; 

extern int read_an_int(int *value); 

int read_an_int(int *value) 
{ 
    int number = 0; 
    int c; 
    int pos_neg = +1; 

    assert(-INT_MAX != INT_MIN); // Probably 2's complement 

    while ((c = getchar()) != EOF && isspace(c)) 
     ; 
    if (c == '-') 
    { 
     pos_neg = -1; 
     c = getchar(); 
    } 
    else if (c == '+') 
    { 
     pos_neg = +1; 
     c = getchar(); 
    } 
    if (c == EOF) 
     return E_EOF; 
    if (!isdigit(c)) 
     return E_INVCHAR; 

    number = '0' - c; /* Negated digit */ 

    while ((c = getchar()) != EOF && isdigit(c)) 
    { 
     int d = '0' - c; /* Negated digit */ 
     if (number < INT_MIN/10 || (number == INT_MIN/10 && d < INT_MIN % 10)) 
      return E_OVERFLOW; 
     //printf("N1 %d; d %d; ", number, d); 
     number = number * 10 + d; 
     //printf("N2 %d\n", number); 
    } 
    if (c != EOF) 
     ungetc(c, stdin); 

    if (pos_neg != -1) 
    { 
     //printf("Should be switched (%d)(%d)\n", pos_neg, number); 
     if (number == INT_MIN) 
      return E_OVERFLOW; 
     number = -number; 
     //printf("Should be positive (%d)(%d)\n", pos_neg, number); 
    } 

    *value = number; 
    return E_OK; 
} 

static void gobble_input(void) 
{ 
    int c; 
    while ((c = getchar()) != EOF) 
    { 
     if (isdigit(c) || c == '+' || c == '-') 
     { 
      ungetc(c, stdin); 
      break; 
     } 
     printf("Skip %c\n", c); 
    } 
} 

int main(void) 
{ 
    int rc; 
    int number; 

    while ((rc = read_an_int(&number)) != E_EOF) 
    { 
     switch (rc) 
     { 
     case E_INVCHAR: 
      printf("Invalid character spotted\n"); 
      gobble_input(); 
      break; 
     case E_OVERFLOW: 
      printf("Input would have overflowed integer range %d..%d\n", INT_MIN, INT_MAX); 
      break; 
     case E_OK: 
      printf("Input number: %d\n", number); 
      break; 
     default: 
      assert(0); 
      break; 
     } 
    } 

    return 0; 
} 

Файл тестовых данных я использовал:

0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
11 
+123 
1234 
56789 
+123456789 
2147483647 
2147483648 
+00000
00000
-0000 
+0000 
-1 
-2 
-9 
-21 
-321 
-4321 
-2147483647 
-2147483648 
-2147483649 
# Bogus data or partially bogus data 
- 
+ 
-213a 
+213a 
+.213 
3.14159E+23 

Выход был:

Input number: 0 
Input number: 1 
Input number: 2 
Input number: 3 
Input number: 4 
Input number: 5 
Input number: 6 
Input number: 7 
Input number: 8 
Input number: 9 
Input number: 11 
Input number: 123 
Input number: 1234 
Input number: 56789 
Input number: 123456789 
Input number: 2147483647 
Input would have overflowed integer range -2147483648..2147483647 
Input number: 123456789 
Input number: 123456789 
Input number: 0 
Input number: 0 
Input number: -1 
Input number: -2 
Input number: -9 
Input number: -21 
Input number: -321 
Input number: -4321 
Input number: -2147483647 
Input number: -2147483648 
Input would have overflowed integer range -2147483648..2147483647 
Invalid character spotted 
Skip 
Skip B 
Skip o 
Skip g 
Skip u 
Skip s 
Skip 
Skip d 
Skip a 
Skip t 
Skip a 
Skip 
Skip o 
Skip r 
Skip 
Skip p 
Skip a 
Skip r 
Skip t 
Skip i 
Skip a 
Skip l 
Skip l 
Skip y 
Skip 
Skip b 
Skip o 
Skip g 
Skip u 
Skip s 
Skip 
Skip d 
Skip a 
Skip t 
Skip a 
Skip 

Invalid character spotted 
Invalid character spotted 
Input number: -213 
Invalid character spotted 
Skip 

Input number: 213 
Invalid character spotted 
Skip 

Invalid character spotted 
Input number: 213 
Input number: 3 
Invalid character spotted 
Input number: 14159 
Invalid character spotted 
Input number: 23 

Обратите внимание, что последняя строка при условии, 3 действительных чисел (и два недопустимых символов, . и E).

Это не особенно легко; поэтому эти вещи закодированы в библиотечных функциях. Кроме того, требование «нет строк» ​​означает, что я не могу выполнять достойную отчетность об ошибках при наличии недопустимых символов или переполнений.

+0

После того, как я опубликовал это, я изменил это из-за других сообщений, которые я видел. Но да, как сказал хак, это не дело печально. – Sunspawn

+1

Код даже не скомпилировался для меня, пока я не исправил это (я компилирую с очень строгими предупреждениями и '-Werror', поэтому любое предупреждение рассматривается как ошибка). Теперь я воспроизвел проблему с типизацией '1',' 5' и '6' на отдельных строках (получив экран, полный пар' 5j'). Я буду отлаживать дальше. Если ваш компилятор не жаловался на эту ошибку, вы должны взломать предупреждения компилятора, чтобы это произошло; если он все еще не может, получите лучший компилятор. –

+0

Полная процедура отладки. Ницца. – haccks

0

Если вы работаете в Windows, добавьте fflush (stdin) только перед циклом, в котором getchar() есть. То есть:

int inToDec(int base) //My assumption is that Enter will not be pressed as the first character - if it is, I am not sure what to do in that case 
{ 
    int numdec=0, c;//decimalized number, a variable for character inpu 
    fflush (stdin); /* flushes input buffer */ 
    while(c = getchar() != '\n' && c != EOF) 
    { 
     if(c >= 97)//Checks if the char is an actual char 
      c = c - 'a' - 1; 
     else//or a digit char 
      c = c; 
     numdec += numdec * base + c;//every time another char is inputted, it multiplies the numdec by the base and adds the char's value in decimal base - which is essentially the algorithm for conversion to decimal base. 
    } 
    return numdec; 
} 
+3

'fflush (stdin)' вызовет ** неопределенное поведение **, если не на MS-DOS. – haccks