Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




 Си, строки и что-то не так с программой
Всем участникам форума добрый вечер! Итак, на этот раз я погорел на программе по "подсчету ворон", которая должна приводить большое число к текстовому виду, согласуясь при этом в склонении со словом ворона. Например так: на ввод число 123 456 789, а программа должна выдать "Сто двадцать три миллиона четыреста пятьдесят шесть тысяч семьсот восемьдесят девять ворон". К слову, моя программа почти :D работает, и основная проблема состоит в склонении числительных, которое выполняется неправильно(не всегда правильно). Прошу навести меня на верный путь в исправлении этого вопроса. Для этого оставляю полный текст программы(она здоровая, но достаточно простая):
Код: [ скачать ] [ спрятать ]
  1. #include <stdio.h> 
  2. #include <locale.h> 
  3. #define MLN     1000000 
  4. #define MLRD    1000000000 
  5. #define TRLN    1000000000000 
  6. #define KVDRLN  1000000000000000 
  7.  
  8. void grammar_case(char A[], char B[], char C[], long long unsigned N, long long unsigned BASE) 
  9. { 
  10.     if((N%100)<10 || (N%100)>20) 
  11.     { 
  12.     if((N/BASE)%10==0 || (N/BASE)%10>4) 
  13.     puts(A); 
  14.     else if((N/BASE)%10==1) 
  15.     puts(B); 
  16.     else 
  17.     puts(C); 
  18.     } 
  19.     else 
  20.     puts(A); 
  21. } 
  22. void birds(long long unsigned N) 
  23. { 
  24.     char v1[]="ворон"; 
  25.     char v2[]="ворона"; 
  26.     char v3[]="вороны"; 
  27.     grammar_case(v1,v2,v3,N,1); 
  28. } 
  29. int gap(long long unsigned N, char D[]) //array gapping 
  30. { 
  31.     int i=0,j=0; 
  32.     while(i<N%10) 
  33.     { 
  34.          while(D[j]!=' ') 
  35.          { 
  36.             j++; 
  37.          } 
  38.     j++; 
  39.     i++; 
  40.     } 
  41.     return j; 
  42. } 
  43. void PA(int INDEX, char D[]) //printing 
  44. { 
  45.     do 
  46.     { 
  47.     printf("%c",D[INDEX++]); 
  48.     }while(D[INDEX]!=' '); 
  49. } 
  50. //HERE AND NEXT: MODE 0 - F, MODE 1 - M 
  51. void digit_writer(long long unsigned N, int MODE) 
  52. { 
  53.     char digits[]={"ноль одна две три четыре пять шесть семь восемь девять "}; 
  54.     char sdigits[]={"ноль один два три четыре пять шесть семь восемь девять "}; 
  55.     if(MODE==0) 
  56.     PA(gap(N, digits), digits); 
  57.     else 
  58.     PA(gap(N, sdigits), sdigits); 
  59.     printf(" "); 
  60. } 
  61. void teens_writer(long long unsigned N) 
  62. { 
  63.     char digits[]={"десять одиннадцать двенадцать тринадцать четырнадцать пятнадцать шестнадцать семнадцать восемнадцать девятнадцать "}; 
  64.     PA(gap(N, digits), digits); 
  65.     printf(" "); 
  66. } 
  67. void decs_writer(long long unsigned N) 
  68. { 
  69.     char decades[]={"ноль десять двадцать тридцать сорок пятьдесят шестьдесят семьдесят восемьдесят девяносто "}; 
  70.     PA(gap(N/10, decades), decades); 
  71.     printf(" "); 
  72. } 
  73. void hect_writer(long long unsigned N) 
  74. { 
  75.     char hundreds[]="ноль сто двести триста четыреста пятьсот шестьсот семьсот восемьсот девятьсот "; 
  76.     PA(gap(N/100, hundreds), hundreds); 
  77.     printf(" "); 
  78. } 
  79. void hmod(long long unsigned N, int MODE) 
  80. { 
  81.     if(N<10) 
  82.     digit_writer(N, MODE); 
  83.     else if(N<20) 
  84.     teens_writer(N); 
  85.     else if(N<100) 
  86.     { 
  87.     decs_writer(N); 
  88.     if(N%10!=0) 
  89.     digit_writer(N%10, MODE); 
  90.     } 
  91. } 
  92. void mod(long long unsigned N, int MODE) 
  93. { 
  94.     if(N<100) 
  95.     { 
  96.     hmod(N, MODE); 
  97.     } 
  98.     else if(N<1000) 
  99.     { 
  100.     hect_writer(N); 
  101.     if(N%100!=0) 
  102.     hmod(N%100, MODE); 
  103.     } 
  104. } 
  105. void thsc(long long unsigned N) 
  106. { 
  107.     char t1[]="тысяч"; 
  108.     char t2[]="тысяча"; 
  109.     char t3[]="тысячи"; 
  110.     grammar_case(t1,t2,t3,N,1000); 
  111. } 
  112. void ths(long long unsigned N) 
  113. { 
  114.     if(N<1000) 
  115.     mod(N,0); 
  116.     else if(N<MLN) 
  117.     { 
  118.     mod(N/1000,0); 
  119.     thsc(N); 
  120.     if(N%1000!=0) 
  121.     mod(N%1000,0); 
  122.     } 
  123. } 
  124. void mlnsc(long long unsigned N) 
  125. { 
  126.     char p1[]="миллионов"; 
  127.     char p2[]="миллион"; 
  128.     char p3[]="миллиона"; 
  129.     grammar_case(p1,p2,p3,N,MLN); 
  130. } 
  131. void mlns(long long unsigned N) 
  132. { 
  133.     if(N<MLN) 
  134.     ths(N); 
  135.     else if(N<MLRD) 
  136.     { 
  137.     mod(N/MLN,1); 
  138.     mlnsc(N); 
  139.     if(N%MLN!=0) 
  140.     ths(N%MLN); 
  141.     } 
  142. } 
  143. void mlrdsc(long long unsigned N) 
  144. { 
  145.     char p1[]="миллиардов"; 
  146.     char p2[]="миллиард"; 
  147.     char p3[]="миллиарда"; 
  148.     grammar_case(p1,p2,p3,N,MLRD); 
  149. } 
  150. void mlrds(long long unsigned N) 
  151. { 
  152.     if(N<MLRD) 
  153.     mlns(N); 
  154.     else if(N<TRLN) 
  155.     { 
  156.     mod(N/MLRD,1); 
  157.     mlrdsc(N); 
  158.     if(N%MLRD!=0) 
  159.     mlns(N%MLRD); 
  160.     } 
  161. } 
  162. void trlnsc(long long unsigned N) 
  163. { 
  164.     char p1[]="триллионов"; 
  165.     char p2[]="триллион"; 
  166.     char p3[]="триллиона"; 
  167.     grammar_case(p1,p2,p3,N,TRLN); 
  168. } 
  169. void trlns(long long unsigned N) 
  170. { 
  171.     if(N<TRLN) 
  172.     mlrds(N); 
  173.     else if(N<KVDRLN) 
  174.     { 
  175.     mod(N/TRLN,1); 
  176.     trlnsc(N); 
  177.     if(N%TRLN!=0) 
  178.     mlrds(N%TRLN); 
  179.     }    
  180. } 
  181. ///////////////end of library///////////////////////////// 
  182. int main(void) 
  183. { 
  184.     long long unsigned I; 
  185.     setlocale(LC_ALL, "rus"); 
  186.     printf("Введите, пожалуйста, количество ворон\n"); 
  187.     scanf("%llu", &I); 
  188.     if(I<KVDRLN) 
  189.     { 
  190.     trlns(I); 
  191.     birds(I); 
  192.     } 
  193.     else if(I>=KVDRLN) 
  194.     printf("Больше одного квадриллиона ворон, они повсюду ...\n"); 
  195.     return 0; 
  196. } 

И обговорю место, в котором скорее всего ошибка. Это подфункция grammar_case:
  1. void grammar_case(char A[], char B[], char C[], long long unsigned N, long long unsigned BASE) 
  2. { 
  3.     if((N%100)<10 || (N%100)>20) 
  4.     { 
  5.     if((N/BASE)%10==0 || (N/BASE)%10>4) 
  6.     puts(A); 
  7.     else if((N/BASE)%10==1) 
  8.     puts(B); 
  9.     else 
  10.     puts(C); 
  11.     } 
  12.     else 
  13.     puts(A); 
  14. } 

В зависимости от введенного числа она выводит разные варианты склонения (их три) слов-разрядов и самого слова ворона. Например так:
  1. void birds(long long unsigned N) 
  2. { 
  3.     char v1[]="ворон"; 
  4.     char v2[]="ворона"; 
  5.     char v3[]="вороны"; 
  6.     grammar_case(v1,v2,v3,N,1); 
  7. } 

Теперь к фактам: программа работает с переменным успехом, например, на число 111 111 111 она реагирует верно, а вот на число 199220111165678 она отвечает неверно.
Да, и об эффективности программы речи не идет(я даже уверен в ее неэффективности, но сей пост не о том).
И я знаю про двумерные массивы.
И книгу Кернигана я открывал.

 Re: Си, строки и что-то не так с программой
Господи, проставьте, пожалуйста, язык кода, пока можете редактировать: [​syntax lang="cpp"]. Можно было ввести всё автоматически, выбрав язык из списка «Подсветка синтаксиса» над полем сообщения.

-- Пн ноя 04, 2013 02:33:21 --

shukshin в сообщении #784213 писал(а):
я даже уверен в ее неэффективности
Так почему бы не писать сразу правильно? :wink:

shukshin в сообщении #784213 писал(а):
//HERE AND NEXT: MODE 0 - F, MODE 1 - M
Вот это можно было и по-русски написать, было бы грамотнее; к тому же, что мешало вместо int mode написать bool f, например. Лучшим же вариантом будет enum Gender { GENDER_M, GENDER_F }.

По функции для тысяч, миллионов, миллиардов и квадриллионов — явный дефект. Если бы вам надо было увеличить величины обрабатываемых чисел, вы бы копировали и вставляли функции?

 Re: Си, строки и что-то не так с программой
Аватара пользователя
А Вы поработайте транслятором: возьмите эту свою grammar_case и построчно объяните, что будет происходить, когда он вызовется с аргументами A="миллионов", B="миллион", C="миллиона", N=111165678, BASE=1000000.

-- Пн ноя 04, 2013 00:48:54 --

Кроме того, разные замечания (не по эффективности)
1. Все, начиная с миллиона склоняется одинаково, и поэтому там достаточно только окончания менять. Это позволит при желании расширить область применимости функции.
2. Вместо трех одинаковых по смыслу параметров A, B, C лучше сделать массив const char * [3] и для понятности объявить enum {SINGULAR, DUAL, PLURAL} чтобы его индексировать.
3. Строки типа "ворон" и "миллионов", соответственно, сгруппировать в массивы и сделать статическими константами, чтобы не загромождать программу одинаковыми функциями. То же касательно числительных.
4. Так исторически сложилось, что большими буквами в C обозначают макросы. Я, например, секунды две искал, где там у Вас рядом с MLN, MLRD и проч. объявлено BASE, пока не понял, что это параметр. Лучше называйте параметры маленькими буквами или с нормальной капитализацией.

-- Пн ноя 04, 2013 00:50:02 --

Да, и еще:
shukshin в сообщении #784213 писал(а):
К слову, моя программа почти :D работает, и основная проблема состоит в склонении числительных, которое выполняется неправильно(не всегда правильно).
Если программа не делает то, что она должна делать, это значит, что она не работает :)

 Re: Си, строки и что-то не так с программой

(Оффтоп)

Скучно было вчера...

Изображение

 Re: Си, строки и что-то не так с программой

(Оффтоп)

Типо зачем этот скрин? Похвастаться?

 Re: Си, строки и что-то не так с программой

(Оффтоп)

Ну да. А так же продемонстрировать, что работает и без ошибок. Пусть автор темы завидует.

 Re: Си, строки и что-то не так с программой

(Оффтоп)

Это не доказательство существования у вас рабочего кода: (1) можно и без кода вообще нарисовать такую форму (и фон с кусками комментариев и операторов); (2) если допустить то, что код у вас есть, программа может правильно работать только на входе «321321321321321», а на остальных — нет.

Alexu007 в сообщении #786651 писал(а):
Пусть автор темы завидует.
Неграмотному тексту, отсутствию нормального имени у кнопки или ожидаемому качеству того неизвестного кода ему стоит завидовать?

 Re: Си, строки и что-то не так с программой
Аватара пользователя
 !  Alexu007, arseniiv, замечание за оффтопик. Обернул.

 Re: Си, строки и что-то не так с программой

(Оффтоп)

arseniiv в сообщении #786869 писал(а):
Это не доказательство существования у вас рабочего кода: (1) можно и без кода вообще нарисовать такую форму (и фон с кусками комментариев и операторов); (2) если допустить то, что код у вас есть, программа может правильно работать только на входе «321321321321321», а на остальных — нет.

Ну обижаете же... Я бы не стал так дёшево жульничать. Программа реально работает и ошибок в работе я не нашёл. Хотите exe-шник выложу, хотите исходник. Тока за исходники меня Toucan наказвает.

А вообще код довольно компактный и симпатичный (на мой взгляд) получился, я думал реализовать сложнее будет.

Что неграмотного в коде? Зачем давать имя единственной кнопке, если на ней уже написано "нажми кнопку"?

 Re: Си, строки и что-то не так с программой

(Оффтоп)

Alexu007 в сообщении #786938 писал(а):
Зачем давать имя единственной кнопке, если на ней уже написано "нажми кнопку"?
«Нажми [ту, на которой это написано] кнопку» было бы «Push the button». «PushButton» — это очевидная camel-case-интерпретация push-button, т. е. написано там просто «кнопка», и в таком виде, который лучше не оставлять не только потому что НазваниеТипаТакогоСредиОбычногоТекстаКакТоНеСмотрится, но и потому что весь остальной текст на форме у вас по-русски. :?

Alexu007 в сообщении #786938 писал(а):
Что неграмотного в коде?
По обрывкам, конечно, ничего сказать нельзя, но на основе истории…

 Re: Си, строки и что-то не так с программой
Код: [ скачать ] [ спрятать ]
Используется синтаксис C++
// ***********************************************************************************
// функция обрабатывает по три цифры
QString ThreeDigitText(int xx)
{

    int y;

    QString str;

    QString e[] = {"", "один", "два", "три", "четыре", "пять",
                   "шесть", "семь", "восемь", "девять", "десять",
                   "одиннадцать", "двенадцать", "тринадцать",
                   "четырнадцать", "пятнадцать", "шестнадцать",
                   "семнадцать", "восемнадцать", "девятнадцать"
                  };

    QString d[] = {"двадцать", "тридцать", "сорок", "пятьдесят",
                   "шестьдесят", "семьдесят", "восемьдесят", "девяносто"};

    QString h[] = {"сто", "двести" ,"триста", "четыреста", "пятьсот",
                   "шестьсот", "семьсот", "восемьсот", "девятьсот"};




    y = xx / 100;

    if(y > 0) str = h[y-1];

    xx = xx % 100;
    y = xx / 10;

    if(xx > 19)
        {
        str += " " + d[y-2];

        xx = xx % 10;
        if(xx > 0) str += " " + e[xx];
        }

    else str += " " + e[xx];

    return str;
}




// ***********************************************************************************
// функция превращения числа в строку слов
QString OllDigitsText(QString inp)
{

    int y, z, Cx = 0;

    QString s1, s2, rez;

    QString g[] = {"", "тысяч", "миллион", "миллиард", "триллион"};

    __int64 xx = 0;




    // засовываем строку чисел в int64, toInt() отдыхает
    for(int i = 0; i < inp.length(); i++)
        {
        s1 = inp.at(i);

        if(s1 < "0" || s1 > "9") return "error";

        xx = xx * 10 + s1.toInt();
        }



    // return если ноль
    if(xx == 0) return "\nноль";




    // собсна процесс превращения числа в строку слов
    while(xx > 0)
        {

        if(xx % 1000)
            {

            y = xx % 10;
            z = xx % 100;

            s1 = ThreeDigitText(xx % 1000);
            s2 = g[Cx];


            // отсюда начинаются шаманские танцы с бубном
            // с целью изменения склонений и спряжений
            if(Cx == 1)
                {
                if((z < 10) || (z > 20))
                    {
                    if(y == 1) s2 += "а";
                    if((y > 1) && (y < 5)) s2 += "и";

                    if(y == 1) s1.replace(s1.length() - 2, 2, "на");
                    if(y == 2) s1.replace(s1.length() - 2, 2, "ве");
                    }
                }

            if(Cx > 1)
                {
                if((z > 10) && (z < 21)) s2 += "ов";

                else if((y > 1) && (y < 5)) s2 += "а";
                else if((y == 0) || (y > 4)) s2 += "ов";
                }
            // конец шаманских танцев с бубном


            rez = "\n" + s1 + " " + s2 + " " + rez;
            }

        Cx++;
        xx = xx / 1000;
        }




    // удаление "лишних" пробелов
    z = 0; s2 = "";

    for(int i = 0; i < rez.length(); i++)
        {
        s1 = rez.at(i);

        if(s1 == " " && z == 0) continue;

        if(s1 == " " || s1 == "\n") z = 0;
        else z = 1;

        s2 += s1;
        }



    return s2;
}







// ***********************************************************************************
// обработка нажатия кнопок
void Widget::MyEventHandler1()
{

    ui->label->setText(OllDigitsText( ui->lineEdit->text() ));

    return;
}

 [ Сообщений: 11 ] 


Соглашение о конфиденциальности | Общие правила

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group