Вопросы и ответы по программированию.

Для тех, кто хочет сделать мир лучше.
Сообщение
Автор
[user]
Эксперты no-Steam
Эксперты no-Steam
Сообщения: 3501
Зарегистрирован: 18.07.2008
Благодарил (а): 2 раза
Поблагодарили: 17 раз
Контактная информация:

#91 Сообщение 19.06.2011, 14:16

GanGSISoft писал(а):И если есть функция bool и в конце возвращает значение, как лучше

Код: Выделить всё

if(s==0){return true}else{return false}
или

Код: Выделить всё

if(s==0){return true}
return false
?
По-моему разницы никакой.

Добавлено спустя 13 минут 9 секунд:
GanGSISoft писал(а):Обнаружил странность, вот тут почему-то не работает delete[] c2

Код: Выделить всё

int main()
{
    FILE *f=fopen("/home/user/tmp/1.fb2","r");
    fseek(f,0,SEEK_END);
    int len=ftell(f);
    fseek(f,0,SEEK_SET);
    char *c=new char[len];
    fread(c,len,1,f);
    fclose(f);
    delete[] c;

    FILE *f2=fopen("/home/user/tmp/2.fb2","r");
    fseek(f2,0,SEEK_END);
    int len2=ftell(f2);
    fseek(f2,0,SEEK_SET);
    char *c2=new char[len2];
    fread(c2,len2,1,f2);
    fclose(f2);
    delete[] c2;

    abort();
    return 0;
}
На операторе delete вылетает ошибка непосредственно во время выполнения программы, когда ты вылезаешь за пределы выделенной области в памяти.

Если ты файл открываешь в текстовом режиме, то должен учитывать, что в текстовых файла символ '\n' записывается в файл и читается из него как два символа подряд '\n' и '\r'.

Для возврат в начало файла можно использовать также rewind(f) .
© [user]

Deus_Ex_Machina
Капитан
Капитан
Сообщения: 492
Зарегистрирован: 23.05.2010
Благодарил (а): 14 раз
Поблагодарили: 43 раза
Контактная информация:

#92 Сообщение 19.06.2011, 14:16

GanGSISoft писал(а):

Код: Выделить всё

if(s==0){return true}else{return false}
или

Код: Выделить всё

if(s==0){return true}
return false
?

Код: Выделить всё

if(!s)return true;
else return false;

Аватара пользователя
NiGHt-LEshiY
Полковник
Полковник
Сообщения: 10258
Зарегистрирован: 13.06.2008
Откуда: Россия
Благодарил (а): 752 раза
Поблагодарили: 2667 раз
Контактная информация:

#93 Сообщение 19.06.2011, 14:20

GanGSISoft
По первому куску кода: потрать время и всегда проверяй значение, которое возвращает функция. fread в случае ошибки возвращает -1.
Также ты читаешь (fread) 1 кусок данных размером len2. Но это не так. Это len2 кусков, каждый размером 1 байт.
Ах да, чуть ли не самое важное... Не мешай C и C++. Хуже просто не придумать.
Ещё вопрос, у меня есть функция, "char *delescape(char *s)" которая в строке перед символами кавычки, пробел и прочее ставить символ ''. Как правильнее сделать, чтобы она заменяла *s или *s оставалась неизменной, а возвращала другую строку. Как принято делать в таких функциях?
Посмотреть исходники php, обратить внимание на функцию addslashes.
Ты же возвращаешь указатель? Значит можно создать в куче новую строку и копипастнуть туда старую, постепенно заменяя нужные символы или расставляя слэши. Память выделять сначала равную старой строке, потом перевыделять, если нужно ещё.
И если есть функция bool и в конце возвращает значение, как лучше
Зачем bool? Возвращай 0 или НЕ 0. Ладно, допустим...
Лучше выглядит такой вариант:

Код: Выделить всё

if (s == 0)
{
	return true;
}
return false;
Добавлено спустя 1 минуту 5 секунд:
Если ты файл открываешь в текстовом режиме, то должен учитывать, что в текстовых файла символ '\n' записывается в файл и читается из него как два символа подряд '\n' и '\r'.
Это где, в Windows? Речь не о ней.
Кодекс поведения участников сообщества — обязательно к прочтению.
Просьба присылать сообщения об ошибках в ЛС.

[user]
Эксперты no-Steam
Эксперты no-Steam
Сообщения: 3501
Зарегистрирован: 18.07.2008
Благодарил (а): 2 раза
Поблагодарили: 17 раз
Контактная информация:

#94 Сообщение 19.06.2011, 14:20

[user] писал(а):
GanGSISoft писал(а):И если есть функция bool и в конце возвращает значение, как лучше

Код: Выделить всё

if(s==0){return true}else{return false}
или

Код: Выделить всё

if(s==0){return true}
return false
?
По-моему разницы никакой.

Добавлено спустя 13 минут 9 секунд:
GanGSISoft писал(а):Обнаружил странность, вот тут почему-то не работает delete[] c2

Код: Выделить всё

int main()
{
    FILE *f=fopen("/home/user/tmp/1.fb2","r");
    fseek(f,0,SEEK_END);
    int len=ftell(f);
    fseek(f,0,SEEK_SET);
    char *c=new char[len];
    fread(c,len,1,f);
    fclose(f);
    delete[] c;

    FILE *f2=fopen("/home/user/tmp/2.fb2","r");
    fseek(f2,0,SEEK_END);
    int len2=ftell(f2);
    fseek(f2,0,SEEK_SET);
    char *c2=new char[len2];
    fread(c2,len2,1,f2);
    fclose(f2);
    delete[] c2;

    abort();
    return 0;
}
На операторе delete вылетает ошибка непосредственно во время выполнения программы, когда ты вылезаешь за пределы выделенной области в памяти.

Если ты файл открываешь в текстовом режиме, то должен учитывать, что в текстовых файла символ '\n' записывается в файл и читается из него как два символа подряд '\n' и '\r'.

Для возврат в начало файла можно использовать также rewind(f) .
И ещё на счёт fread. По-моему эту функцию целесообразнее использовать когда файл открываешь в бинарном режиме.

Код: Выделить всё

FILE *f=fopen(<filename>,"r+");
© [user]

Аватара пользователя
NiGHt-LEshiY
Полковник
Полковник
Сообщения: 10258
Зарегистрирован: 13.06.2008
Откуда: Россия
Благодарил (а): 752 раза
Поблагодарили: 2667 раз
Контактная информация:

#95 Сообщение 19.06.2011, 14:23

r+
"rb" - бинарное чтение.
а "r+" - чтение/запись с установкой "курсора" в начало файла
Кодекс поведения участников сообщества — обязательно к прочтению.
Просьба присылать сообщения об ошибках в ЛС.

Аватара пользователя
GanGSISoft
Полковник
Полковник
Сообщения: 1430
Зарегистрирован: 27.03.2008
Откуда: Бацькаўшчына
Благодарил (а): 2 раза
Поблагодарили: 3 раза
Контактная информация:

#96 Сообщение 19.06.2011, 14:43

На операторе delete вылетает ошибка непосредственно во время выполнения программы, когда ты вылезаешь за пределы выделенной области в памяти.
Если я первый кусок закоментирую, тоесть сделаю так
code

Код: Выделить всё

int main()
{
 /*   FILE *f=fopen("/home/siarhei/tmp/1.fb2","r");
    fseek(f,0,SEEK_END);
    int len=ftell(f);
    fseek(f,0,SEEK_SET);
    char *c=new char[len];
    fread(c,len,1,f);
    fclose(f);
    delete[] c;*/

    FILE *f2=fopen("/home/siarhei/tmp/2.fb2","r");
    fseek(f2,0,SEEK_END);
    int len2=ftell(f2);
    fseek(f2,0,SEEK_SET);
    char *c2=new char[len2];
    fread(c2,len2,1,f2);
    fclose(f2);
    delete[] c2;

    int yyyy; cin>>yyyy;

    return 0;
}
То файл 2.fb2 прекрасно загружается в память и удаляется из неё, если первый кусок кода не комментировать то тоже нормально загружается и программа завершается без ошибки, но обём замимаемой памяти больше чем надо, в памяти файл 2.fb2 остаётся(тоесть напишу я или не напишу delete[] c2;, ничего не меняется, когда нужно ввести yyyy то памяти занято 852кб, а хотя должно быть 172кб, а если сбросить core, то там можно найти не удалённый 2.fb2).
Загружаю я его не в текстовом режиме, а просто записываю в память байты из файла, а потом определяю кодировку и уже перегоняю в utf8 и делаю что мне надо(этот код просто пример непонятного мне явления).

Добавлено спустя 7 минут 10 секунд:
Ты же возвращаешь указатель? Значит можно создать в куче новую строку и копипастнуть туда старую, постепенно заменяя нужные символы или расставляя слэши. Память выделять сначала равную старой строке, потом перевыделять, если нужно ещё.
Я так и делаю, только выделяю сразу память strlen(s)*2 поскольку если вставлять туда слеши то она будет длиней, потом перевыделяю на более короткую. Функция работает. Просто заметил что некоторые функции, например strlwr старую строку не сохраняют, поэтому может есть какое-то правило по поводу это, вот и спросил.
Вообще с этим ясно, спасибо

Добавлено спустя 3 минуты 18 секунд:
Ах да, чуть ли не самое важное... Не мешай C и C++. Хуже просто не придумать.
В смысле? Использовать iostream? Я как то не привык. У меня вообще есть универсальная функция int LoadFile(const char *fn,char *&file), я почти всегда гружу весь файл в память, а потом делаю с ним что надо. (Ежели встречу большой файл, то естественно так делать не буду)
Последний раз редактировалось GanGSISoft 19.06.2011, 14:35, всего редактировалось 2 раза.

Аватара пользователя
NiGHt-LEshiY
Полковник
Полковник
Сообщения: 10258
Зарегистрирован: 13.06.2008
Откуда: Россия
Благодарил (а): 752 раза
Поблагодарили: 2667 раз
Контактная информация:

#97 Сообщение 19.06.2011, 14:53

GanGSISoft
Лучше делать правильно изначально. Грузить весь файл в память почти ВСЕГДА плохо.
Используй чистый C в таком случае. Нет необходимости в плюсах в твоих задачах.
Кодекс поведения участников сообщества — обязательно к прочтению.
Просьба присылать сообщения об ошибках в ЛС.

Аватара пользователя
GanGSISoft
Полковник
Полковник
Сообщения: 1430
Зарегистрирован: 27.03.2008
Откуда: Бацькаўшчына
Благодарил (а): 2 раза
Поблагодарили: 3 раза
Контактная информация:

#98 Сообщение 19.06.2011, 16:09

NiGHt-LEshiY писал(а):Грузить весь файл в память почти ВСЕГДА плохо.
Ну если файлы от 40кб и до 10мб потолок, не вижу ничего плохого. А в этом случае тут надо определить кодировку перекодировать, и читать кусками можно, но незачем, очень это будет сложно и накладно.
NiGHt-LEshiY писал(а):Используй чистый C в таком случае.
Ясно, но почему плохо в C++ программе использовать fopen, fread?
Последний раз редактировалось GanGSISoft 19.06.2011, 16:10, всего редактировалось 1 раз.

Аватара пользователя
NiGHt-LEshiY
Полковник
Полковник
Сообщения: 10258
Зарегистрирован: 13.06.2008
Откуда: Россия
Благодарил (а): 752 раза
Поблагодарили: 2667 раз
Контактная информация:

#99 Сообщение 19.06.2011, 16:14

GanGSISoft
Плохо смешивать языки. Хоть C++ имеет совместимость с С, не стоит использовать это.
В твоей программе плюсы вообще не нужны. Ну никак.
Кодекс поведения участников сообщества — обязательно к прочтению.
Просьба присылать сообщения об ошибках в ЛС.

Аватара пользователя
Pr0Ger
Модератор
Модератор
Сообщения: 1829
Зарегистрирован: 16.01.2009
Благодарил (а): 17 раз
Поблагодарили: 214 раз
Контактная информация:

#100 Сообщение 19.06.2011, 16:23

GanGSISoft
запустил твой код, без комментария, как видишь с памятью все корректно

Код: Выделить всё

valgrind --leak-check=full ./a.out
...
==3357== 
==3357== HEAP SUMMARY:
==3357==     in use at exit: 0 bytes in 0 blocks
==3357==   total heap usage: 4 allocs, 4 frees, 712 bytes allocated
==3357== 
==3357== All heap blocks were freed -- no leaks are possible
а теперь он же без delete[] c2;

Код: Выделить всё

valgrind --leak-check=full ./a.out
...
==1708== 
==1708== HEAP SUMMARY:
==1708==     in use at exit: 4 bytes in 1 blocks
==1708==   total heap usage: 4 allocs, 3 frees, 712 bytes allocated
==1708== 
==1708== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==1708==    at 0x4025F53: operator new[](unsigned int) (vg_replace_malloc.c:299)
==1708==    by 0x80486CB: main (in /home/pr0ger/temp/a.out)
==1708== 
==1708== LEAK SUMMARY:
==1708==    definitely lost: 4 bytes in 1 blocks
==1708==    indirectly lost: 0 bytes in 0 blocks
==1708==      possibly lost: 0 bytes in 0 blocks
==1708==    still reachable: 0 bytes in 0 blocks
==1708==         suppressed: 0 bytes in 0 blocks
как видишь разница есть
GanGSISoft писал(а): а если сбросить core, то там можно найти не удалённый 2.fb2
а delete и не должен затереть память нулями, он помечает что память больше не используется, но данные там еще будут лежать, пока их не перезапишет чем-то другим
Последний раз редактировалось Pr0Ger 19.06.2011, 16:23, всего редактировалось 1 раз.

Аватара пользователя
GanGSISoft
Полковник
Полковник
Сообщения: 1430
Зарегистрирован: 27.03.2008
Откуда: Бацькаўшчына
Благодарил (а): 2 раза
Поблагодарили: 3 раза
Контактная информация:

#101 Сообщение 19.06.2011, 17:18

Pr0Ger
Хм, Оно понятное дело нулями не затирает, но если запустить без второго куска перед выходом программа занимает 176кб, если добавить второй кусок то 852кб, и если убрать delete[] c2; то тоже 852кб.
Возможно или я глючу или у меня что-то не то с компилятором, может это типа как бы оптимизация какая, что не освобождается до поры до времени участок?
Ну ладно, я тоже щас попробую в valgrind разобратся
У меня тоже самое, хм, даже не знаю чего дак и што#!&
Последний раз редактировалось GanGSISoft 19.06.2011, 17:35, всего редактировалось 2 раза.

[user]
Эксперты no-Steam
Эксперты no-Steam
Сообщения: 3501
Зарегистрирован: 18.07.2008
Благодарил (а): 2 раза
Поблагодарили: 17 раз
Контактная информация:

#102 Сообщение 19.06.2011, 17:29

NiGHt-LEshiY писал(а):"rb" - бинарное чтение.
а "r+" - чтение/запись с установкой "курсора" в начало файла
Перепутал... :blush:

Добавлено спустя 10 минут 46 секунд:
Кстати, у меня тоже вопрос один есть...
С динамической памятью в C++ я разобрался, а вот в чистом C не очень...
  1. Объявляю переменную-указатель.
  2. Вызываю malloc / calloc.
  3. Далее, по мере необходимости, - realloc.
  4. В конце - free.
На некотором вызове функции realloc (не на первом и не на втором) программа падает со ссылкой на повреждение кучи. Всё многократно перепроверял. Писал специально тестовую программу - ничего лишнего, только тест динамической памяти. В чём может быть проблема? Компилил в 2008й студии.
© [user]

Аватара пользователя
GanGSISoft
Полковник
Полковник
Сообщения: 1430
Зарегистрирован: 27.03.2008
Откуда: Бацькаўшчына
Благодарил (а): 2 раза
Поблагодарили: 3 раза
Контактная информация:

#103 Сообщение 19.06.2011, 17:49

Вот прогнал через valgrind одну программу, вроде утечек нет, но куча вот таких штук выскакивает, это как понимать?

Код: Выделить всё

==8562== Invalid read of size 1
==8562==    at 0x4C2974F: strlen (mc_replace_strmem.c:282)
==8562==    by 0x4013E0: pos(char const*, char const*) (charstr.h:47)
==8562==    by 0x402AA9: xml_GetParam(char const*, char const*) (FB2.h:21)
==8562==    by 0x4030CD: procfile(char*, char*, char*, bool, bool) (main.cpp:40)
==8562==    by 0x4039E3: main (main.cpp:206)
==8562==  Address 0x5a13ccd is 0 bytes after a block of size 13 alloc'd
==8562==    at 0x4C28658: operator new[](unsigned long) (vg_replace_malloc.c:305)
==8562==    by 0x4029AB: xml_GetParam(char const*, char const*) (FB2.h:7)
==8562==    by 0x4030CD: procfile(char*, char*, char*, bool, bool) (main.cpp:40)
==8562==    by 0x4039E3: main (main.cpp:206)

Аватара пользователя
NiGHt-LEshiY
Полковник
Полковник
Сообщения: 10258
Зарегистрирован: 13.06.2008
Откуда: Россия
Благодарил (а): 752 раза
Поблагодарили: 2667 раз
Контактная информация:

#104 Сообщение 19.06.2011, 18:34

[user]
Покажи код.
Кодекс поведения участников сообщества — обязательно к прочтению.
Просьба присылать сообщения об ошибках в ЛС.

Аватара пользователя
Pr0Ger
Модератор
Модератор
Сообщения: 1829
Зарегистрирован: 16.01.2009
Благодарил (а): 17 раз
Поблагодарили: 214 раз
Контактная информация:

#105 Сообщение 19.06.2011, 20:08

GanGSISoft
GanGSISoft писал(а):Invalid read of size 1
обращение к некорректному участку
оно говорит, что strlen читает невесть что размером 1 байт
GanGSISoft писал(а):Address 0x5a13ccd is 0 bytes after a block of size 13 alloc'd
а здесь поясняет что именно оно читает, т.е. содержимое по адресу 0x5a13ccd, что находится сразу за (0 bytes after) блоком памяти выделенном в xml_GetParam

пример:

Код: Выделить всё

int main() {
	char *a = new char[10];
	std::cout << a[11];
	delete[] a;
	return 0;
}

Код: Выделить всё

==2028== Invalid read of size 1
==2028==    at 0x80485F4: main (sample.cpp:3)
==2028==  Address 0x42ce033 is 1 bytes after a block of size 10 alloc'd
==2028==    at 0x4025F53: operator new[](unsigned int) (vg_replace_malloc.c:299)
==2028==    by 0x80485E8: main (sample.cpp:2)
конкретно в твоем случае (strlen и чтение сразу за выделенным куском памяти) скорее всего строка не завершена \0 и strlen продолжает читать дальше, уже за пределами строки, пока не встретит случайно \0

Ответить Вложения 1