Предыдущая тема :: Следующая тема |
Автор |
Сообщение |
Владимир И.
Зарегистрирован: 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 можно принять за конец файла, что неверно. |
|
Вернуться к началу |
|
|
|