Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Архив форумов ЦИТФорума
Море(!) вопросов - Море(!) ответов
 
 FAQFAQ   ПоискПоиск   ПользователиПользователи   ГруппыГруппы   РегистрацияРегистрация 
 ПрофильПрофиль   Войти и проверить личные сообщенияВойти и проверить личные сообщения   ВходВход 
Как правильно задавать вопросы

Почему вылетает? (знатокам Си)

 
Перейти:  
Этот форум закрыт, вы не можете писать новые сообщения и редактировать старые.   Эта тема закрыта, вы не можете писать ответы и редактировать сообщения.    Список форумов Архив форумов ЦИТФорума -> Программирование
Предыдущая тема :: Следующая тема  
Автор Сообщение
Владимир И.



Зарегистрирован: 29.11.2007
Сообщения: 3
Откуда: Россия, г.Липецк

СообщениеДобавлено: Чт Ноя 29 2007 08:26    Заголовок сообщения: Почему вылетает? (знатокам Си) Ответить с цитатой

Код:

Здравствуйте!
Пожалуйста, скажите где ошибка.
После запуска EXE - "вылетает", см. код ниже.
Компилятор - VC6, ОС - XP.

//
// Problem.c
//

#include <stdio.h>
#include <stdlib.h>

typedef struct
{   unsigned char* text;
   unsigned long int len;//Количество символов в text, включая символ окончиня строки - '\0';
} strtext_t;

typedef struct
{   strtext_t *s;
} table_string_t;             // Строка таблицы (строка ячеек).

typedef struct
{   unsigned char nc;     // Количество колонок в таблице.
   unsigned long int ns; // Количество строк в таблице.
   table_string_t *sl;   // Список табличных строк (кол-во = ns).
   table_string_t c_name;// Строка таблицы. Названия колонок (кол-во = nc).
} table_t;

table_t tt;

int main()
{
   char i;

   tt.sl = NULL;
   tt.c_name.s = NULL;
   tt.nc = 0;
   tt.ns = 0;

/* ХАРАКТЕР ПРОБЛЕМЫ
Если выделять память при помощи malloc - все нормально.
Если выделять и _изменять_ при помощи realloc и при этом еще что-то
записывать в tt.c_name.s[х].x - то происходит "вылет".
Если запись в tt.c_name.s[х].x производить как ниже, то вылетает на 6
"проходе" цикла, а если записывать более активно (выделять для .text память
и туда писать) - то вылетает уже на 3-ем проходе.
*/
   for (i=0; i<8; i++)
   {
      tt.c_name.s = (table_string_t*) realloc (tt.c_name.s, sizeof (table_string_t) * i+1);
      tt.c_name.s[i].text = NULL;
   }

   return 0;
}
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
vir



Зарегистрирован: 17.05.2007
Сообщения: 24

СообщениеДобавлено: Чт Ноя 29 2007 17:16    Заголовок сообщения: Ответить с цитатой

Код:

   for (i=0; i<8; i++)
   {
      tt.c_name.s = (table_string_t*) realloc (tt.c_name.s, sizeof (table_string_t) * i+1);
      /* Во первых в Си так нехорошо делать. (void *) может приводится к любому типу указателя, поэтому каст в начале делать нехорошо, лишний раз писать тип значит, что при переименовании будет ошибка, можно не тот тип написать, строка становится заметно длиннее */
      /* Во вторых тип tt.c_name.s --- (strtext_t *), а не (table_string_t*) и блоки надо выделять размером с sizeof strtext_t, а не table_string_t */
      /* В третьих вы опять же зашиваетесь на тип, в то время, как можно написать: sizeof (tt.c_name.s[0]) */

      tt.c_name.s[i].text = NULL;
   }

В результате получаем:
Код:

      tt.c_name.s = NULL;
      for (i = 0; i < 8; i++) {
          tt.c_name.s = realloc (tt.c_name.s, sizeof (tt.c_name.s[0]) * i+1);
          /* Не производится проверка на NULL и в случае
              необходимости мы не сможем сделать free, т. к.
              realloc вернёт NULL, а tt.c_name.s будет указывать на
              выделенный в памяти объект. Но мы тут же потеряем
              этот объект перезаписав указатель в tt.c_name.s */
          tt.c_name.s[i].text = NULL;
      }

[/code]
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Владимир И.



Зарегистрирован: 29.11.2007
Сообщения: 3
Откуда: Россия, г.Липецк

СообщениеДобавлено: Чт Ноя 29 2007 18:00    Заголовок сообщения: Ответить с цитатой

vir писал(а):

/* Во первых в Си так нехорошо делать. (void *) может приводится к любому типу указателя, поэтому каст в начале делать нехорошо, лишний раз писать тип значит, что при переименовании будет ошибка, можно не тот тип написать, строка становится заметно длиннее */


Спасибо за науку. В книжках тип приводят, вот и я приводил, теперь небуду.

vir писал(а):

/* Во вторых тип tt.c_name.s --- (strtext_t *), а не (table_string_t*) и блоки надо выделять размером с sizeof strtext_t, а не table_string_t */


Вот где она была! Так вот всегда: просматривал много раз и не видел.

vir писал(а):

/* В третьих вы опять же зашиваетесь на тип, в то время, как можно написать: sizeof (tt.c_name.s[0]) */


Никогда не догадывался писать "sizeof (tt.c_name.s[0])". Буду знать.

vir писал(а):

В результате получаем:
/* Не производится проверка на NULL и в случае
необходимости мы не сможем сделать free, т. к.
realloc вернёт NULL, а tt.c_name.s будет указывать на
выделенный в памяти объект. Но мы тут же потеряем
этот объект перезаписав указатель в tt.c_name.s */

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

Благодарю сердечно за помощь и науку, спасиБог.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
vir



Зарегистрирован: 17.05.2007
Сообщения: 24

СообщениеДобавлено: Чт Ноя 29 2007 19:01    Заголовок сообщения: Ответить с цитатой

Владимир И. писал(а):

Спасибо за науку. В книжках тип приводят, вот и я приводил, теперь небуду.

Заметь, что это в Си не надо приводить, а в Си++ это необходимо. Другое дело, что в Си++ нехорошо использовать malloc для этого есть new и стандартный класс vector. Следует отличать эти два языка: я например не любли Си++, а Си уважаю. В хороших книжках пишут правильно, в других так пишут скорее всего для того, чтобы пример работал и в Си и в Си++.

Владимир И. писал(а):

vir писал(а):

/* Во вторых тип tt.c_name.s --- (strtext_t *), а не (table_string_t*) и блоки надо выделять размером с sizeof strtext_t, а не table_string_t */


Вот где она была! Так вот всегда: просматривал много раз и не видел.

vir писал(а):

/* В третьих вы опять же зашиваетесь на тип, в то время, как можно написать: sizeof (tt.c_name.s[0]) */


Никогда не догадывался писать "sizeof (tt.c_name.s[0])". Буду знать.

Идея в том, что если писать так как я сказал, то твоя ошибка просто не возникнет. На тип нехорошо ссылаться просто потому, что определение типа оно в коде вон как далеко, а определение переменной прям под рукой, в нём очень трудно ошибиться.
[/quote]

Владимир И. писал(а):

vir писал(а):

В результате получаем:
/* Не производится проверка на NULL и в случае
необходимости мы не сможем сделать free, т. к.
realloc вернёт NULL, а tt.c_name.s будет указывать на
выделенный в памяти объект. Но мы тут же потеряем
этот объект перезаписав указатель в tt.c_name.s */

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

Обычно, просто выходить --- это самое грамотное поведение. Но может когда-нибудь придётся поразбираться с утечкой памяти.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Владимир И.



Зарегистрирован: 29.11.2007
Сообщения: 3
Откуда: Россия, г.Липецк

СообщениеДобавлено: Пт Ноя 30 2007 10:30    Заголовок сообщения: Ответить с цитатой

vir писал(а):

Заметь, что это в Си не надо приводить, а в Си++ это необходимо. Другое дело, что в Си++ нехорошо использовать malloc для этого есть new и стандартный класс vector. Следует отличать эти два языка: я например не любли Си++, а Си уважаю. В хороших книжках пишут правильно, в других так пишут скорее всего для того, чтобы пример работал и в Си и в Си++.

Про С++ не знаю, на прошлой неделе только стал читать о нём, не нравится он мне, но надо. Без него на желаемую работу не возьмут (3D "движки" игр пишутся на С++, почти все). Сам-то я уже который год на Си пишу. Нравится он мне за трезвость. Но вот, чтобы написать plugin к 3DS Max - нужно знать С++ или чтобы в своем движке популярную физическую библиотеку использовать. А приведение типа (при выделении памяти функциями malloc/realloc) - это делается в книжке "Программирование на языке Си" В.В.Подбельского.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
vir



Зарегистрирован: 17.05.2007
Сообщения: 24

СообщениеДобавлено: Пт Дек 14 2007 20:12    Заголовок сообщения: Ответить с цитатой

Кстати в Подбельском, по-моему, видел ещё ошибку. Что-то вроде:

Код:

FILE *fp;
char c;
fp = fopen (name, "r");
while ((c = fgetc (fp)) != EOF) {
  /*...*/
}


здесь "c" объявлено как "char", что неверно, должен быть "int". "fgetc", по стандарту, если не конец файла, возвращает значе типа "int" содержащее неотрицательное число от 0 до "UCHAR_MAX" (обычно 255). А в случае ошибки или конца файла возвращает "EOF" (обычно -1). В этой же программе совершенно обычный символ с кодом 255 можно принять за конец файла, что неверно.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение
Показать сообщения:   
Этот форум закрыт, вы не можете писать новые сообщения и редактировать старые.   Эта тема закрыта, вы не можете писать ответы и редактировать сообщения.    Список форумов Архив форумов ЦИТФорума -> Программирование Часовой пояс: GMT + 3
Страница 1 из 1

 
Перейти:  
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах


Powered by phpBB © 2001, 2002 phpBB Group
Русская поддержка phpBB

 

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 6608306, ICQ 232284597
Пресс-релизы — pr@citforum.ru
Послать комментарий
Информация для авторов
This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2006 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...