Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 18.05.2012, 07:58   #1
Познающий
Форумчанин
 
Аватар для Познающий
 
Регистрация: 09.05.2009
Сообщений: 162
Вопрос [C++] Не удаётся удалить динамическую строку, которую вернула функция

Здравствуйте.
Всё время я не заморачивался насчёт освобождения кучи, и вот настал момент, когда дипломный проект может из-за этого сильно пострадать.

по сабжу:
У меня есть структуры данных и функция DataToString у каждой, для превращения всех полей в одну строку, указатель на которую она возвращает к источнику вызова.
Источник читает данные, а строка продолжает висеть в памяти.
В одной теме сказали очевидную вещь: "Удалить указатель, в который записывается результат функции", но у меня чёто не получается =).
Напишу короткий упрощенный код (вставлю псевдомакросы),
как я это делаю:

Код:
char*	SStruct::DataToString(){
  char*out; // выходная строка.
  size = CountResSize(SStruct.data[]); // считаю, сколько знакомест займут данные в структуре, плюс пробелы и прочее.
  out = new char[size+1];
  strcpy(out,data[0]);
  strcat(out," ");
  strcat(out,IntToString(data[1])); 
  .
  .
  .
  return out; // тут всё замечательно. строка корректная.
};

main(){
 char*d;
 for (int i=0;i<ALOT!;i++){
    d= MyS.DataToString()
    delete [] d; // убиваю строку, которая находится по этой ссылке.
    // Debug Error; DAMAGE: after Normal Block (#67) at 0xsomeaddr
    delete d; // тоже самое, пишу на всякий случай ;).
 }
}
Не понимаю - я ведь создаю через new, ссылку получаю в main и могу же я ее убить delete

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

Полный код затронутых функций:
Код:
//---------------------------------------------- 
// atoms.cpp
char* IntToString(int num){
	int dim = 1;
	bool minus;
	int tmp = num;
	if (num < 0) 
		{
		minus = 1;
		tmp = -num;
	}
	else minus = 0;

	// определить разрядность
	while (tmp/10 != 0){
		tmp = tmp/10;
		dim++;
	};

	// выделить память
	char* str;
	int index = 0;
	str = new char [dim+1 + minus];
	// копировать каждую цифру в массив
	if (minus) tmp = -num; else tmp = num;

	for (int i = dim+minus ; i>0+minus; i--)
	{
		switch (tmp%10){
			case 0: str[i-1]='0'; break;
			case 1: str[i-1]='1'; break;
			case 2: str[i-1]='2'; break;
			case 3: str[i-1]='3'; break;
			case 4: str[i-1]='4'; break;
			case 5: str[i-1]='5'; break;
			case 6: str[i-1]='6'; break;
			case 7: str[i-1]='7'; break;
			case 8: str[i-1]='8'; break;
			case 9: str[i-1]='9'; break;
		}
		tmp = tmp / 10;
	}

	if (minus) str[0] = '-';
	str[dim+minus] = 0;
	return str;
}
/////
char*	SLecture::DataToString(){

	// Выделяем переменные
	char*out; // выходная строка.
	int	size = 0; // вычисление размера этой строки, согласно совокупному количеству знаков, которые занимают записи.
	int ITEMS = 6; // количество полей в данной записи.
	int SPACES = ITEMS -1; // количество пробелов в записи.

	// Вычисляется общая длина записи.
	size += strlen(IntToString(Day));
	size += strlen(IntToString(Group));
	size += strlen(IntToString(Lector));
	size += strlen(IntToString(Number));
	size += strlen(IntToString(Room));
	size += strlen(IntToString(Subject));	
		
	// Выделяется строка, в которой вместятся все символы из записей, разделяющие пробелы, нуль-знак
	out = new char[size + 1 + SPACES ];

	strcpy(out,IntToString(Day));
	strcat(out," ");
	strcat(out,IntToString(Group));
	strcat(out," ");
	strcat(out,IntToString(Lector));
	strcat(out," ");
	strcat(out,IntToString(Number));
	strcat(out," ");
	strcat(out,IntToString(Room));
	strcat(out," ");
	strcat(out,IntToString(Subject));
	
	out[size + 1 + SPACES] = 0;
	return out;
}
//---------------------------------------------- 
// main
#include <iostream>
#include "atoms.h"
#include <vector>
#include <windows.h>
using namespace std;

void main(){
	// SLector
	// SLecture
	// SRoom
	// SSubject
#define TEST SLecture

	TEST x[2];
	x[0].Set(1,1,1,1,1,1);
	x[1].Set(x[0].DataToString());

	vector <TEST> vec;
	vec.push_back(x[0]);
	vec.push_back(x[1]);

	char*d =0;
	for (int i =0;i<10000; i++){
		d = vec[0].DataToString();  // здесь очень сильная утечка памяти
		d=0;
	}
	::CharToOem(d,d);
	cout<<d<<endl;
}
С наилучшими пожеланиями.
Познающий вне форума Ответить с цитированием
Старый 18.05.2012, 15:30   #2
Познающий
Форумчанин
 
Аватар для Познающий
 
Регистрация: 09.05.2009
Сообщений: 162
По умолчанию

скорее всего я неверно выделял память. Может быть даже new не было...

Так работает

Код:
char* f(){
	char*a = new char[3];
	return a;
}

char*a;
a=f();
delete[]a;
Удачи, читающий сие =)

UPD:
Да. Похоже, что я пытался применить delete к char[]. Я запутался в потоке данных и теперь не различаю, какая функция возвращает ссылку на поле, а какая - на созданный массив.


UPD через час:
Все-таки я не тестировал свою функцию еще... А ведь она все еще дает ошибку.
Но я, пересмотрев эту функцию, понял в чем ошибка. Сначала я обвинил strcat'ы, но виноват я. Я невнимательно подсчитал индекс последней строки, и закрывающий нуль-символ ставлю куда-то за пределы строки. Не удаляется, наверное, потому что строка не оканчивается нулём.

Код:
char* SLector::DataToString(){
	// Тут надо подробнее.

	// Выделяем переменные
	char*out; // выходная строка.
	int	size = 0; // вычисление размера этой строки, согласно совокупному количеству знаков, которые занимают записи.
	int ITEMS = 4; // количество полей в данной записи.
	int SPACES = ITEMS -1; // количество пробелов в записи.
	int StringSize[] = {30}; // массив размерностей строк.

	// Вычисляется общая длина записи.
	size += strlen(IntToString(Key));
	size += strlen(IntToString(Status));
	size += strlen(FIO);
	size += strlen(IntToString(Extra));
	
	// Выделяется строка, в которой вместятся все символы из записей, разделяющие пробелы, нуль-знак, и два апострофа для ФИО
	out = new char[size+1+ SPACES +2];

	strcpy(out,IntToString(Key));
	strcat(out," ");
	strcat(out,IntToString(Status));
	strcat(out," '"); // перед ФИО - апостроф.

	int j = strlen(out);
	
	for (int i = 0; i<StringSize[0] && FIO[i] != 0;i++)
	{
		out[j+i] = FIO[i];
	}
	out[j+i] = 0;
	strcat(out,"' "); // закрывающий апостроф

	strcat(out,IntToString(Extra));

//	out[size+1+ SPACES +2] = 0; Враг государства. РАССТРЕЛЯТЬ!
	out[size+1+ SPACES +2-1] = 0; // Так работает.

	return out;
}
С наилучшими пожеланиями.

Последний раз редактировалось Познающий; 18.05.2012 в 16:51. Причина: Эврика
Познающий вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как нарисовать в OpenGL сферу которую которую можно рассматривать с разных ракурсов Sh0cK Мультимедиа в Delphi 2 07.11.2017 14:51
функция получае на вход строку чисел, выводит строку символов DellOleg Microsoft Office Access 2 18.02.2012 11:17
задача на Си,Ввести строку, в которую могут входить только цифры и буквы. vinternete Помощь студентам 0 11.07.2011 12:35
VBA_макрос: удалить всю строку в таблице, если в ней есть слово "удалить" макарошка Microsoft Office Excel 15 05.10.2010 09:09
Как записать (считать) динамическую строку в (из) файл(а)? C++ Сергей089 Помощь студентам 2 10.02.2010 22:00