2014 dxdy logo

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

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




 
 Си, строки и что-то не так с программой
Сообщение03.11.2013, 22:16 
Всем участникам форума добрый вечер! Итак, на этот раз я погорел на программе по "подсчету ворон", которая должна приводить большое число к текстовому виду, согласуясь при этом в склонении со словом ворона. Например так: на ввод число 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 
Господи, проставьте, пожалуйста, язык кода, пока можете редактировать: [​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 
Аватара пользователя
А Вы поработайте транслятором: возьмите эту свою 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 

(Оффтоп)

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

Изображение

 
 
 
 Re: Си, строки и что-то не так с программой
Сообщение09.11.2013, 14:48 

(Оффтоп)

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

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

(Оффтоп)

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

 
 
 
 Re: Си, строки и что-то не так с программой
Сообщение10.11.2013, 00:12 

(Оффтоп)

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

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

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

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

(Оффтоп)

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

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

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

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

 
 
 
 Re: Си, строки и что-то не так с программой
Сообщение10.11.2013, 18:21 

(Оффтоп)

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

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

 
 
 
 Re: Си, строки и что-то не так с программой
Сообщение10.11.2013, 19:08 
код: [ скачать ] [ спрятать ]
Используется синтаксис 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