2014 dxdy logo

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

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




Начать новую тему Ответить на тему
 
 Си, строки и что-то не так с программой
Сообщение03.11.2013, 22:16 


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

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

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

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

 Профиль  
                  
 
 Re: Си, строки и что-то не так с программой
Сообщение03.11.2013, 23:27 
Заслуженный участник
Аватара пользователя


27/04/09
27145
Господи, проставьте, пожалуйста, язык кода, пока можете редактировать: [​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: Си, строки и что-то не так с программой
Сообщение03.11.2013, 23:38 
Заслуженный участник
Аватара пользователя


06/10/08
6298
А Вы поработайте транслятором: возьмите эту свою 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: Си, строки и что-то не так с программой
Сообщение09.11.2013, 09:58 


24/05/09

2054

(Оффтоп)

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

Изображение

 Профиль  
                  
 
 Re: Си, строки и что-то не так с программой
Сообщение09.11.2013, 14:48 
Заслуженный участник
Аватара пользователя


27/04/09
27145

(Оффтоп)

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

 Профиль  
                  
 
 Re: Си, строки и что-то не так с программой
Сообщение09.11.2013, 17:38 


24/05/09

2054

(Оффтоп)

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

 Профиль  
                  
 
 Re: Си, строки и что-то не так с программой
Сообщение10.11.2013, 00:12 
Заслуженный участник
Аватара пользователя


27/04/09
27145

(Оффтоп)

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

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

 Профиль  
                  
 
 Re: Си, строки и что-то не так с программой
Сообщение10.11.2013, 00:17 
Админ форума
Аватара пользователя


19/03/10
8952
 !  Alexu007, arseniiv, замечание за оффтопик. Обернул.

 Профиль  
                  
 
 Re: Си, строки и что-то не так с программой
Сообщение10.11.2013, 09:36 


24/05/09

2054

(Оффтоп)

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

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

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

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

 Профиль  
                  
 
 Re: Си, строки и что-то не так с программой
Сообщение10.11.2013, 18:21 
Заслуженный участник
Аватара пользователя


27/04/09
27145

(Оффтоп)

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

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

 Профиль  
                  
 
 Re: Си, строки и что-то не так с программой
Сообщение10.11.2013, 19:08 


24/05/09

2054
код: [ скачать ] [ спрятать ]
Используется синтаксис 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 ] 

Модераторы: Toucan, maxal, PAV, Karan, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group