Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Ошибка при выполнении: "Stack ... was corrupted"


Автор: KasMP 10.12.2008, 17:59
Тем временем, у меня появилась еще одна простенькая программка, которая компилируется без одной ошибки, без единого предупреждения и отлично выполняется при запуске из DevC++.

Но в MS Visual C++ 2008 в самом конце выполнения возникает такая ошибка:
user posted image

Я совсем не понимаю, что может быть причиной ошибок такого рода в моем случае - у меня все переменные ограничены, все массивы ограничены, длины строк взяты с большим запасом, не в свои ячейки памяти я не лезу, т.п. и т.д..

Взгляните, пожалуйста (здесь совсем немного и несложно - перевод числа из арабской СС в римскую):
Код

#include <stdio.h>
#include <string.h>

int       arabian[13]={1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
char      roman[13][3]={"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};

void ArabianToRoman (short int number)
{
     char          res[20]="\0";
     char          tRoman[3];
     short int     i=0;
     short int     tArab;
     
     do {
         strcpy_s(tRoman,roman[i]);
         tArab=arabian[i];
         while (tArab<=number) {
             strcat_s(res,tRoman);
             number-=tArab;
         }
         i++;
     }
     while (number>0);
     printf("Roman=%s.\n", res);
}         

int main() {
    short int      number;

    printf("Input arabian number.\n");
    scanf_s("%d", &number);

    ArabianToRoman(number);
    
    return(0);   
}

Автор: bsa 10.12.2008, 18:31
%d требует указатель на int, а у тебя number типа short

Автор: KasMP 10.12.2008, 18:37
Цитата(bsa @  10.12.2008,  18:31 Найти цитируемый пост)
%d требует указатель на int, а у тебя number типа short 

Действительно, стоило изменить тип переменной number и тип формального параметра number, как все прошло smile !

Не думала, что эта разница столь принципиальна smile ... А у "short int" есть свой спецификатор smile ?

Автор: bsa 11.12.2008, 12:40
Цитата
      The following type modifier characters can appear in a conversion specification:

       h      Indicates that the conversion will be one of d, i, o, u, x, X, or n and the next pointer is  a
              pointer to a short int or unsigned short int (rather than int).
источник: http://linux.die.net/man/3/sscanf

Автор: KasMP 11.12.2008, 19:23
bsa, благодарю smile smile !
Теперь буду знать еще один спецификатор smile smile.

Пыталась понять, почему это так существенно smile...
По сути
Код
printf ("%[спецификатор]", variable);
 читается как "представить variable как тот тип, который соответствует спецификатору".

Т.е. конкретно в моем случае получается "представить переменную типа short int как int". В чем проблема? Множество значений вкладывается, недостающие до int биты можно заполнить нулями-единицами в зависимости от знака.
Вот если "представить переменную типа int как short int", то я бы тоже стала сопротивляться... А переход от большего к меньшему должен быть возможен, имхо (DevC++ со мной согласен smile !).

Автор: mes 11.12.2008, 20:59
Цитата(KasMP @  11.12.2008,  19:23 Найти цитируемый пост)
Пыталась понять, почему это так существенно smile...


Цитата(KasMP @  10.12.2008,  17:59 Найти цитируемый пост)
  scanf_s("%d", &number);

ты запихнула в стек переменную размером в два байта (short int), а scanf запишет туда 4 байта(%d),
в результате перезапишет чужие данные которые были в стеке. 

Цитата(KasMP @  11.12.2008,  19:23 Найти цитируемый пост)
DevC++ со мной согласен smile !)

Имхо DevCpp просто не проверяет стек на возможное повреждение, а Студийный компилятор вероятно на границах стека ставит свою сигнатуру и после операций со стеком проверяет ее - если затерта , значит стек разрушен...

Автор: bsa 11.12.2008, 22:20
KasMP, вообще-то смысл этих спецификаторов в том, что ими ты определяешь не только способ отображения, но еще и типы данных, с которыми должна работать функция. Ни компилятор, ни она сама не могут иначе определить их самостоятельно (почитай про функции с переменным числом аргументов и стандартный заголовочный файл stdarg.h). Например, чтобы избежать переполнения (выхода за границы) буфера при чтении строки с помощью scanf, нужно в спецификаторе указывать размер этого буфера: %20s - буфер на 20 символов. Таким образом, scanf считает в него только первые 20 букв.
Дальше, есть такая штука, как "выравнивание". Т.е. в стеке нельзя просто выделить память, не кратную какому-то числу (обычно, 4 байта). short int - это два байта. Т.е. чтобы разместить эту переменную в стеке, нужно выделить 4 байта. Компилятор gcc (который входит в состав Dev-Cpp), видимо, делает выравнивание без генерации какого-либо дополнительного кода проверки выхода за границы переменной, а Visual C++ делает.

Автор: mes 11.12.2008, 23:42
Цитата(bsa @  11.12.2008,  22:20 Найти цитируемый пост)
Дальше, есть такая штука, как "выравнивание".

мне кажется что выравнивание на стек не распространяется.. хотя точно не знаю..и даже не знаю где посмотреть )

Автор: KasMP 21.12.2008, 22:00
Цитата(mes @  11.12.2008,  20:59 Найти цитируемый пост)
ты запихнула в стек переменную размером в два байта (short int), а scanf запишет туда 4 байта(%d),
в результате перезапишет чужие данные которые были в стеке. 

Понятно smile smile .
Цитата(mes @  11.12.2008,  20:59 Найти цитируемый пост)
Имхо DevCpp просто не проверяет стек на возможное повреждение,

Эх... А я доверяла DevC++, считала его хорошим, умным и надежным.
(нередко он мне нравился больше VS, т.к. на нем больше программ запускается smile  smile )


bsa, спасибо за хорошее развернутое объяснение и ссылочки smile .

Автор: bsa 21.12.2008, 23:52
KasMP, в настройках компиляции DevCpp поставь -Wall и тебе он будет писать предупреждение при ошибке в спецификаторе. А надежность тут непричем.

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