Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Программа магически вылетает при вызове функции


Автор: KasMP 9.12.2008, 21:13
Здравствуйте!

Пишу программу для сложения и умножения очень длинных целых чисел (>20 разрядов) с помощью строк.
Сложение работает отлично, поэтому от функции сложения оставлю только заголовок.
Умножение выполняется с помощью функции сложения (подробно описано в комментариях). Отмечу только, что 
  • в массиве 
    Код
    char mult[][100]
     хранятся результаты умножения s1*s2[i];
  • res - глобальная переменная
    Код
    char     res[100];
    .
По совершенно непонятным мне причинам после вызова функции умножения программа просто вылетает, просто закрывается окошечко DOS-a.
Надеюсь, вы поможете мне узнать, что такого особенного в моей функции умножения (пока незавершенной)...

Код

void Multiplication (char s1[], char ss2[], char mult[][100])
{
     int      i, j, k, t, sum=0;
     int      len1=strlen(s1), len2=strlen(ss2), lenres;
     char     s2[len1];
     
     // выравнивание столбцов 
     // создаем s2: значение(int) то же, что и у ss2, недостающие разряды заполняются '0'
     k=len1-len2;
     for (i=0; i<k; ++i) s2[i]='0';
     for (int j=0; i<=len1; ++i, ++j) s2[i]=ss2[j];
     // в итоге s2[len1]='\0'
     // в итоге в s1[i] и s2[i] находятся цифры, соответствующие одинаковым разрядам
     
     // заполняем массив строк mult строками-числами, содержащими результат умножение s1*s2[i]
     for (i=len1-1; i>=0; --i) {
         for (t=0; t<strlen(res); ++t) res[t]='0'; // очищаем res для s1*s2[i]
         for (j=1; j<int(s2[i])-48; ++j) Addition(s1,s1); // складываем s1 (j-1) раз, где j - цифра нужного разряда в s2
         lenres=strlen(res); // запоминаем длину res, чтобы знать, куда добавлять '\0'
         for (j=lenres, t=0; t<len1-i-1; ++j) res[j]='0'; // дописываем в res справа (len-i-1) нулей
         res[lenres+t]='\0'; // завершаем res нуль-символом
         for (t=0; t<=strlen(res); ++t) mult[i][t]=res[t]; // кладем res в массив (включая завершающий '\0')
     }
     
     /*
     для теста
     for (t=0; t<len; ++t) printf ("1: %s\n.", mult[t]);
     */


     // складываем строки-числа массива mult
    
}

Автор: J0ker 9.12.2008, 21:33
дебагеры уже не в почете?

Автор: KasMP 9.12.2008, 21:38
В почете, но при компиляции (Dev-C++) нет ни одной ошибки, ни одного предупреждения:
Цитата

Компилятор: Default compiler
Выполнение  g++.exe...
g++.exe "C:\ ..........
Выполнение завершено
Компиляция успешна

А отладкой у меня не получается пользоваться - переменные не заносятся в наблюдаемые...

Добавлено через 12 минут и 17 секунд
Возможно, остальной код тоже имеет значение smile ...

В главной функции ничего особенного нет: ввод строк, определение более длинной, создание массива для произведений s2[i]*s1, вызовы функций. Функция (точнее, процедура) сложения в итоге формирует переменную res (а она глобальная), поле чего res выводится уже в главной функции.
Не знаю, где может быть загвоздка smile smile...

Автор: KasMP 9.12.2008, 21:58
Сложение:
Код

// сложение; 
void Addition (char s1[], char ss2[])
{
     int      mental=0; // кол-во единиц "в уме"
     int      i, k, t;
     int      len1, len2;
     
     len1=strlen(s1); len2=strlen(ss2);
    
     char     s2[len1];
     
     // выравнивание столбцов 
     // создаем s2: значение(int) то же, что и у ss2, недостающие разряды заполняются '0'
     k=len1-len2;
     for (i=0; i<k; ++i) s2[i]='0';
     for (int j=0; i<=len1; ++i, ++j) s2[i]=ss2[j];
     // в итоге s2[len1]='\0'
     // в итоге в s1[i] и s2[i] находятся цифры, соответствующие одинаковым разрядам
    
     res[len1]='\0';
     for (i=len1-1; i>=0; i--) {
         t=int(s1[i])+int(s2[i])+mental-96;
         res[i]=t%10+48;
         mental=t/10;
         }

     if (mental==1) {
                    for (i=len1-1; i>=0; --i) res[i+1]=res[i];
                    res[0]='1'; res[len1+1]='\0';
                    } 
}

(обещаю выравнивание столбцов вынести в отдельную процедуру, а не повторять каждый раз один и тот же код smile )

Глобальные переменные:
Код

char     res[100];
int      len;


Главная функция:
Код

int main()
{
    
    // ввод максимальной длины строки
    short int      length_max;
    printf ("Input maximum length.\n"); scanf("%d", &length_max);
    
    // ввод чисел-строк s1 и s2
    char   s1[length_max+1], s2[length_max+1];
    printf ("Input first number.\n"); scanf("%s", &s1);
    printf ("Input second number.\n"); scanf("%s", &s2);
    
    int    len1=strlen(s1), len2=strlen(s2); len=(len1>len2 ? len1 : len2);
    char   mult[len][100];
    
    
    if (len1>len2) {
                   Addition(s1,s2);
                   printf("Sum is equal to %s.\n", res);
                   Multiplication(s1,s2,mult);
                   printf("Multiplication is equal to %s.\n", res);
                   }
                   else {
                        Addition(s2,s1);
                        printf("Sum is equal to %s.\n", res);
                        Multiplication(s2,s1,mult);
                        printf("Multiplication is equal to %s.\n", res);
                        }  
      
      return(0);                           
}

(тоже можно оптимизировать... но это потом)

Функции как функции, ничего сверхъестественного... За выделенную область памяти вроде не вылезаю smile .

Автор: J0ker 9.12.2008, 22:28
Цитата(KasMP @  9.12.2008,  21:38 Найти цитируемый пост)
А отладкой у меня не получается пользоваться - переменные не заносятся в наблюдаемые...

надо дебаг версию скомпилить без оптимизации
не знаю как там в Dev это включается
поверьте, гораздо проще пройтись дебагером чем гадать в чем дело

Автор: KasMP 9.12.2008, 22:38
Цитата(J0ker @  9.12.2008,  22:28 Найти цитируемый пост)
не знаю как там в Dev это включается

А в Microsoft Visual C++ 2008 Expess version ?

Добавлено через 2 минуты и 4 секунды
Цитата(J0ker @  9.12.2008,  22:28 Найти цитируемый пост)
надо дебаг версию скомпилить без оптимизации

это как?
Цитата(J0ker @  9.12.2008,  22:28 Найти цитируемый пост)
поверьте, гораздо проще пройтись дебагером чем гадать в чем дело 

да я не только верю, я знаю это smile .
научил бы кто, как это делать smile ...

Автор: J0ker 9.12.2008, 23:16
Цитата(KasMP @  9.12.2008,  22:38 Найти цитируемый пост)
А в Microsoft Visual C++ 2008 Expess version ?

ну если там интерфейс тот-же как и в профешенел, то выбрать дебаг билд в тулбаре

Добавлено через 46 секунд
точки останова ставите просто слева от строки кода на полях кликнуть - появится метка

Автор: KasMP 10.12.2008, 00:33
Цитата(J0ker @  9.12.2008,  23:16 Найти цитируемый пост)
точки останова ставите просто слева от строки кода на полях кликнуть - появится метка 

Понятно smile .

К строчке 
Код
char     s2[len1];

такие ошибки (честно говоря, я не понимаю причин ни одной из них):
  • Цитата
    1>f:\вмп\... : error C2057: expected constant expression

    почему ожидается выражение-константа? я не обязана инициализировать массив строк сразу же, при объявлении;
  • Цитата
    1>f:\вмп\... : error C2466: cannot allocate an array of constant size 0

    что мешает разместить массив? в конце концов, если пока не задана конкретная константа, то можно просто выделить (len1) байт..;
  • Цитата
    1>f:\... : error C2133: 's2' : unknown size

    почему неизвестен размер, если черным по-белому написано "len1" (и это выражение вполне вычислимо к этому моменту)

Добавлено через 2 минуты и 12 секунд
Точно такие же ошибки везде, где объявляются массивы символов... В сумме 18 штук smile .

Автор: KasMP 10.12.2008, 01:29
Так, с объявлением массивов в Visual C++ (точнее, с тем, что такое объявление не поддерживается smile ) я разобралась: надо или объявлять динамический массив, или в случае статического должна быть четкая константа...

Автор: sergejzr 10.12.2008, 01:39
Цитата(KasMP @  9.12.2008,  23:33 Найти цитируемый пост)
К строчке 

Ты путаешь момент компиляции и момент исполнения программы. Откуда компилятору знать, какое значение будет у len1 в процессе выполнения программы?

Если нужна динамика, используй указатель.
Код

char*     s2;
с2=new char[len1];


Если мне память в С не изменяет.


Автор: KasMP 10.12.2008, 01:54
Цитата(sergejzr @  10.12.2008,  01:39 Найти цитируемый пост)
Ты путаешь момент компиляции и момент исполнения программы. Откуда компилятору знать, какое значение будет у len1 в процессе выполнения программы?
...

Спасибо, с этим я уже разобралась smile : http://www.cyberforum.ru/visual-cpp/thread8442.html хорошо описано, что это просто особенность именно Microsoft Visual C++,  которая не соответствует стандарту языка smile (в DevC++ с объявлением массивов все ок).
Основная проблема в том, что при вызове 
Код
void Multiplication (char s1[], char ss2[], char mult[][100])
 все просто вылетает smile . Но я скоро и до этого доберусь smile !!

Автор: J0ker 10.12.2008, 06:27
Цитата(KasMP @  10.12.2008,  01:54 Найти цитируемый пост)
что это просто особенность именно Microsoft Visual C++,  которая не соответствует стандарту языка

это соответствует стандарту C++
другие компиляторы могут поддерживать стандарт C99 - там разрешены массивы с динамическим размером - но это стандарт plain C

Цитата(KasMP @  10.12.2008,  00:33 Найти цитируемый пост)
1>f:\вмп\... : error C2466: cannot allocate an array of constant size 0

массивы нулевого размера по стандарту запрещены

Автор: sergejzr 10.12.2008, 08:24
KasMP, просто используй указатели.

Автор: mes 10.12.2008, 14:26
a почему бы не использовать std::string ? или другой подходящий контейнер , чем мучаться с выделениями памяти ?

Автор: KasMP 10.12.2008, 17:13
Спасибо smile, с массивами я вчера разобралась smile smile .
Посмотрим, будет ли прога вылетать при вызове функции умножения...

Автор: KasMP 11.12.2008, 19:09
Я нашла ошибку  smile smile  smile  smile (сегодня утром smile ) !

Любая адекватная программа, операционная система или человек не задумываясь отклонит того, кто пытается захватить все-все-все себе...
Код
for (j=lenres, t=0; t<len1-i-1; ++j) res[j]='0'; // дописываем в res справа (len-i-1) нулей
res[lenres+t]='\0'; // завершаем res нуль-символом

Надо же такое написать smile  smile  smile !
Ограничила по одному параметру, итерацию сделала по другому, приписала замечательный комментарий и поражаюсь, что же это оно вылетает smile  smile (магически smile smile)...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)