Форум программистов, компьютерный форум, киберфорум
Наши страницы
C для начинающих
Войти
Регистрация
Восстановить пароль
 
koi
0 / 0 / 0
Регистрация: 04.04.2017
Сообщений: 6
1

Код не работает в 2008 версии visual studio, но работает в 2005

04.04.2017, 21:18. Просмотров 438. Ответов 16
Метки нет (Все метки)

Добрый день. Писала на университетском компьютере программу, считывающую данные из файла в список структур. Там стоит 2005 версия, и всё работало нормально. При перенесении кода в 2008 vs выдает ошибку Run-Time Check Failure #2 - Stack around the variable 'str' was corrupted при запуске. Компилятор не ругается.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Film
{
        char Name[50];
        int Year;
        char Genre[30];
        Film*next; 
};
Film*createList(FILE*F, Film*tail)  
{
        char str[50];
        while(fgets(str,sizeof(str)-1,F)!=NULL)     
        {
                Film*obj= new Film;
                tail->next = obj;
                str[strlen(str)-1]='\0';
                strcpy(obj->Name,str);
                fscanf(F,"%d",&obj->Year);
                fgetc(F);
                fgets(str,sizeof(str)-1,F);
                str[strlen(str)-1]='\0';
                strcpy(obj->Genre,str);
 
                obj->next=0;
                tail=obj;
        }
        return tail;
}
void pr(Film*head)   
{
        while (head!=0)
        {
                printf("%s\n%d\n%s\n",head->Name,head->Year,head->Genre);
                head=head->next;
        }
}
int main()
{
        Film*head=0;
        Film*tail=0;
        head=new Film; 
        tail=head;
        FILE*F=fopen("Ghibli.txt", "r");
        if (F == NULL) {printf ("errror\n"); return -1;}
        else printf ("ok\n\n");
        createList(F,tail);
        pr(head->next);
        fclose;
}
Файл выглядит примерно так:
the lion king
2003
drama
mulan
1998
adventure


Что не понятнее всего, на другом компьютере код работает в 2008 версии. Может ли быть дело в каких-либо настройках? Буду очень благодарна за помощь.
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
04.04.2017, 21:18
Ответы с готовыми решениями:

Работа с указателями - код не работает в Visual Studio 2012
Нужно помощь, дан код программы с указателями. Когда пишу код в Visual 2012, то при выводе на экран...

Не работает код С++ (Visual Studio 2008)
Вобщем нужно было составить программу для вычисления значения функции с использованием сложной...

WTF не работает простой код на Visual studio 2008(баг?)
Взял код из википедии....

Работает в Borland Developer Studio 2006 но не работает в Visual Studio 2008, почему?
Вводим строку и меняем в ней первый и последний символы. Всё хорошо в Borland Developer Studio, а...

Visual Studio 2005 и Visual Studio 2008 сильно ли они отличаются друк от друга?
привет ребята:) вот у меня есть Visual Studio 2005 и Visual Studio 2008 возник вопрос сильно ли...

16
h3mbr0
297 / 106 / 31
Регистрация: 12.03.2012
Сообщений: 433
04.04.2017, 21:26 2
Скорее всего и там была ошибка
Возможно, дело в копировании строк, попробуйте strcpy заменить на strncpy с 3 аргументом - размером целевого массива

Кстати,
C
1
 str[strlen(str)-1]='\0';
избыточно, и у вас код на Си вперемешку с C++
И
C
1
fclose;
=>
C
1
fclose(F);
Хотя ошибку это в данном контексте вызвать не может
1
koi
0 / 0 / 0
Регистрация: 04.04.2017
Сообщений: 6
04.04.2017, 21:52  [ТС] 3
Добавлено через 10 минут
h3mbr0, спасибо! strncpy не спасает, теперь программа просто прекращает работу, хотя не выдаёт прошлую ошибку. Если смотреть по отладке, цикл создания списка по какой-то причине не смотря на ограничение продолжает считывать пустые строки и что-то с ними делать.
Не могли бы вы пояснить, что значит str[strlen(str)-1]='\0' - избыточно? Я пыталась избавиться от \n в конце строк, которые считывались fgets, потому что они мешали дальше работать со структурами.
0
h3mbr0
297 / 106 / 31
Регистрация: 12.03.2012
Сообщений: 433
04.04.2017, 21:57 4
Скиньте txt файл который читаете

UPD:
я вас обманул, все правильно =(
0
04.04.2017, 21:57
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
5101 / 2563 / 711
Регистрация: 18.10.2014
Сообщений: 4,465
04.04.2017, 22:07 5
Цитата Сообщение от h3mbr0 Посмотреть сообщение
a[strlen(str)-1] это элемент, который содержит этот самый нуль-байт, т.к. индексация массива нумеруется с 0
Таким образом, если вы хотите обрезать последний символ перед '\0', нужно вычесть еще 1: str[strlen(str)-2]='\0';
Нет. Нулевой терминатор входит в дину строки, поэтому нулевой терминатор - это именно str[strlen(str)].

Делать str[strlen(str)-1]='\0' - опрометчиво, ибо \n там может и не быть, но это уже другая история.

Цитата Сообщение от koi Посмотреть сообщение
Что не понятнее всего, на другом компьютере код работает в 2008 версии.
Что же тут непонятного? Там просто не было проверок на сохранность стека. То есть ошибка просто не обнаруживалась.

Вот чего не надо делать, так это вычитать 1 из размера буфера при вызове fgets

C
1
fgets(str, sizeof str, F)
0
h3mbr0
297 / 106 / 31
Регистрация: 12.03.2012
Сообщений: 433
04.04.2017, 22:11 6
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Нет. Нулевой терминатор - это именно str[strlen(str)].
Уже поправился, на сонную голову sizeof мысленно слился с strlen =)
Вот тут
C
1
fgets(str,sizeof(str)-1,F)
второй аргумент принимает размер учитывая нульбайт, но это, опять же, ошибку вызвать не может

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Что же тут непонятного? Там просто не было проверок на сохранность стека. То есть ошибка просто не обнаруживалась.
Откуда же сходу это понимать? =)
0
koi
0 / 0 / 0
Регистрация: 04.04.2017
Сообщений: 6
04.04.2017, 22:13  [ТС] 7
h3mbr0, вот!
Ещё раз спасибо за помощь)
0
Вложения
Тип файла: txt Ghibli.txt (143 байт, 3 просмотров)
h3mbr0
297 / 106 / 31
Регистрация: 12.03.2012
Сообщений: 433
04.04.2017, 22:20 8
А вот теперь у вас ошибка в txt =)
после последней строки, "drama" - несколько пустых строк
Признаком строки является перенос строки - '\n', так что они тоже считываются
Видимо, поскольку их нечетное количество, fgets, который внутри цикла, считывает пустую строку, ее strlen равен 0, и в str[strlen(str)-1] вы выходите за пределы переменной в обратную сторону, повреждая стек
1
koi
0 / 0 / 0
Регистрация: 04.04.2017
Сообщений: 6
04.04.2017, 22:20  [ТС] 9
TheCalligrapher,
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Что же тут непонятного? Там просто не было проверок на сохранность стека. То есть ошибка просто не обнаруживалась.
Спасибо, что объяснили! А непонятно то, что даже преподаватель не смог дать вразумительный ответ на мой вопрос.
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Вот чего не надо делать, так это вычитать 1 из размера буфера при вызове fgets
изначально вычитания там не было, это просто мои тщетные попытки исправить положение. Можно поинтересоваться к чему ведёт это вычитание?
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
5101 / 2563 / 711
Регистрация: 18.10.2014
Сообщений: 4,465
04.04.2017, 22:24 10
Цитата Сообщение от koi Посмотреть сообщение
вот!
У вас в конце файла - пустые строки. Ваш fscanf(F,"%d",&obj->Year); в поиске числовых данных "пробрасывает" весь файл и упирается в конец файла. Следующий fgets ничего прочитать уже не может. Строка str как была пустой, так и остается пустой. В результате ваше str[strlen(str)-1]='\0' делает запись по индексу -1. Получаем разрушение стека.
1
koi
0 / 0 / 0
Регистрация: 04.04.2017
Сообщений: 6
04.04.2017, 22:24  [ТС] 11
h3mbr0, ой и правда! Так глупо вышло... Теперь всё работает, спасибо огромное!
0
h3mbr0
297 / 106 / 31
Регистрация: 12.03.2012
Сообщений: 433
04.04.2017, 22:24 12
Цитата Сообщение от koi Посмотреть сообщение
А непонятно то, что даже преподаватель не смог дать вразумительный ответ на мой вопрос.
Это не так очевидно, как кажется на первый взгляд, но это первое, что приходит в голову
Цитата Сообщение от koi Посмотреть сообщение
Можно поинтересоваться к чему ведёт это вычитание?
Вы просто теряете 1 байт длины. ничего критичного, но и хорошего тоже мало
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
5101 / 2563 / 711
Регистрация: 18.10.2014
Сообщений: 4,465
04.04.2017, 22:25 13
Цитата Сообщение от koi Посмотреть сообщение
Можно поинтересоваться к чему ведёт это вычитание?
Ни к чему страшному не ведет. Просто предельное количество символов для чтения получается на 1 меньше, чем могло бы. Буфер вы сделали размером 50, а используете только 49.
0
koi
0 / 0 / 0
Регистрация: 04.04.2017
Сообщений: 6
04.04.2017, 22:30  [ТС] 14
TheCalligrapher,
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Ни к чему страшному не ведет. Просто предельное количество символов для чтения получается на 1 меньше, чем могло бы. Буфер вы сделали размером 50, а используете только 49.
Теперь всё ясно, спасибо!
0
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
5101 / 2563 / 711
Регистрация: 18.10.2014
Сообщений: 4,465
04.04.2017, 22:37 15
Вообще говоря, смешивание построчного ввода (fgets) и форматированного ввода (fscanf) - не самая лучшая идея. Особенно когда формат файла у вас организован построчно, ибо fscanf игнорирует окончания строк.

Раз уж вам нужен fgets, то файл лучше читать только fgets. А затем уже прочитанные строки переводить в числа при помощи strtol или sscanf. Тогда у вас не было бы вот этого сюрприза, когда fscanf вдруг пролетел через весь файл и уперся в конец файла.
0
CoderHuligan
773 / 554 / 203
Регистрация: 30.06.2015
Сообщений: 3,138
Записей в блоге: 23
05.04.2017, 13:36 16
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Нулевой терминатор входит в дину строки, поэтому нулевой терминатор - это именно str[strlen(str)].
Вобще-то нулевой терминатор, в длину строки вычисляемую при помощи функции strlen, не входит. А индекс - это индекс.
1
TheCalligrapher
С чаем беда...
Эксперт CЭксперт С++
5101 / 2563 / 711
Регистрация: 18.10.2014
Сообщений: 4,465
05.04.2017, 18:14 17
Цитата Сообщение от CoderHuligan Посмотреть сообщение
Вобще-то нулевой терминатор, в длину строки вычисляемую при помощи функции strlen, не входит. А индекс - это индекс.
У меня просто как-то оказалось пропущено "не". Разумеется, нулевой терминатор не входит в длину строки.
1
05.04.2017, 18:14
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.04.2017, 18:14

Конвертация(или сохранение) проектов Visual Studio 2008 c# в Visual Studio 2005 c#
Доброго времени суток =) Можно ли, конвертировать проект или же сохранить под другую версию...

SQL 2005 не работает с ms visual studio 2010 ?
Здравствуйте! Операционная система xp sp3,среда разработки Microsoft Visual Studio 2010, сервер...

Visual Studio C++ 2008 Express Edition не работает
Я скачал и установил компилятор Microsoft Visual Studio C++ 2008 Express Edition!!! (Вот ссылка с...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru