Dynamicznie rozszerzalna tablica typu char w klasie.

0

Moim zadaniem jest stworzenie metody, która będzie dopisywać do składnika klasy jakim jest char* słow zapisanych rownież w tablicy charow jako argument.
Zadanie wykonałem tworza dynamicznie nowa tablice, przepisując i przestawiając wskaznik.

Pytanie: Jak mogę teraz usunąć z pamieci zawartosc miejsca, na które wcześniej wskazywał wskaźnik?

napis1 to element klasy przechowujący owy napis.

void dopisz(char *tekst)
	{
		int i = 0;
		int z = 0;
		int j = 0;
		while (tekst[i] != 0) //liczę ile miejsca zaalokować
		{
			i++;
		}
		char *pom = new char[sizeof(napis1) + i];
		while(napis1[z]!='\0') //kolejno przepisuję do nowej tablicy
		{
			pom[z] = napis1[z];
			z++;
		}
		while(tekst[j]!='\0')
		{
			pom[z + j] = tekst[j];
			j++;
		}
		pom[z + j] = '\0';
		napis1 = pom; //przestawiam wskaznik

//Tutaj chce usunąc poprzednia zawartośc pod wskaznikiem napis1.
	}
 
4

Każde wywołanie new[] musi mieć odpowiadające delete[] (i analogicznie dla new i delete). Jeśli nadpisujesz wskaźnik to przed jego nadpisaniem musisz zwolnić starą zawartość.

Nie widzę całego kodu, ale poniższe jest bardzo podejrzane. Jeśli napis1 jest wskaźnikiem, to sizeof(napis1) będzie wielkością wskaźnika, bez żadnego związku z pokazywanym napisem.

        char *pom = new char[sizeof(napis1) + i];

Polecam też funkcje takie jak std::strlen i std::strcpy/std::strncpy - nie ma co wymyślać koła na nowo. Zakładam, że zadanie polega na implementacji ubogiej wersji std::string, więc tego wyjątkowo nie polecam.

0
kq napisał(a):

Każde wywołanie new[] musi mieć odpowiadające delete[] (i analogicznie dla new i delete). Jeśli nadpisujesz wskaźnik to przed jego nadpisaniem musisz zwolnić starą zawartość.

Nie widzę całego kodu, ale poniższe jest bardzo podejrzane. Jeśli napis1 jest wskaźnikiem, to sizeof(napis1) będzie wielkością wskaźnika, bez żadnego związku z pokazywanym napisem.

        char *pom = new char[sizeof(napis1) + i];

Polecam też funkcje takie jak std::strlen i std::strcpy/std::strncpy - nie ma co wymyślać koła na nowo. Zakładam, że zadanie polega na implementacji ubogiej wersji std::string, więc tego wyjątkowo nie polecam.

Tak, racja to byl wskaznik, a sizeof zwracał złe wartosci, dziwne, że program sie nie wysypywał.

Tak wyglądają konstruktory i deklaracja.

private: 
char *napis1;

public:
 
napis()
	{
		napis1 = "";
	}
	napis(char* napis)
	{
		napis1 = napis;
	}

Jak mogę usunąc pamieć? Myslałem o czymś takim, ale niestety - program sie wywala.
 
	void dopisz(char *tekst)
	{
		int i = 0;
		int z = 0;
		int j = 0;
		while (tekst[i] != 0)
		{
			i++;
		}
		char *pom = new char[strlen(napis1) + i];
		while(napis1[z]!='\0')
		{
			pom[z] = napis1[z];
			z++;
		}
		while(tekst[j]!='\0')
		{
			pom[z + j] = tekst[j];
			j++;
		}
		pom[z + j] = '\0';
		char *usun = napis1;
		napis1 = pom;
		delete usun;
	}
0

napis1 = ""; się nie powinno kompilować (popełniłem na ten temat kiedyś rant).

Program się wywala, ponieważ:

  1. próbujesz wywołać delete na "". Nie ma to żadnego sensu (tak samo jak przypisanie początkowej wartości w taki sposób)
  2. wywołujesz delete zamiast delete[] do pamięci zaalokowanej przez new[] (to później, bo na razie wywala się z powodu 1.)
0
napis()
	{
		napis1 = new char[1];
		napis1[0] = '\0';
	}
 

Ten konstruktor jest poprawny?

char *usun= napis1;
		napis1 = pom;
		delete[] usun; 

Przy takim usuwaniu nadal sie wywala.
Bloga będę śledził :)

0

Teraz wygląda mniej więcej ok. Pokaż cały kod.

0

class napis
{
	char *napis1; 
public: 
	napis()
	{
		napis1 = new char[1];
		napis1[0] = '\0';
	}

	void dopisz(char *tekst)
	{
		int i = 0;
		int z = 0;
		int j = 0;
		while (tekst[i] != 0)
		{
			i++;
		}
		char *pom = new char[strlen(napis1) + i];
		while(napis1[z]!='\0')
		{
			pom[z] = napis1[z];
			z++;
		}
		while(tekst[j]!='\0')
		{
			pom[z + j] = tekst[j];
			j++;
		}
		pom[z + j] = '\0';
		char *usun = napis1;
		napis1 = pom;
		delete[] usun;
	}

};
 
0

Zamiast liczyć i też możesz użyć strlen. Ponadto musisz zaalokować 1 znak więcej na null byte na końcu. Ale nie jestem w stanie powtórzyć wywałki: http://melpon.org/wandbox/permlink/BWoqV7gaUdAgz4QN

0

http://melpon.org/wandbox/permlink/BWoqV7gaUdAgz4QN

Może zatem coś się sypie w funkcji wypisującej, chociaż to dziwne, bo bez delete[] działało bez zarzutu.

2

Dlatego prosiłem: pokaż kod (cały), który się wysypuje. A nie tylko ten fragment, który Ci się wydaje, że może być zły.

0
#include "stdafx.h"
#include <iostream>
#include <string>

using namespace std;
class napis
{
	char *napis1; 
public: 
	napis()
	{
		napis1 = new char[1];
		napis1[0] = '\0';
	}
	napis(char* napis)
	{
		napis1 = napis;
	}
	napis(const napis& nap)
	{
		napis1 = nap.napis1;
	}
	void dopisz(char *tekst)
	{
		int z = 0;
		int j = 0;
		char *pom = new char[strlen(napis1) + strlen(tekst) +1];
		while(napis1[z]!='\0')
		{
			pom[z] = napis1[z];
			z++;
		}
		while(tekst[j]!='\0')
		{
			pom[z + j] = tekst[j];
			j++;
		}
		pom[z + j] = '\0';
		char *usun = napis1;
		napis1 = pom;
		delete[] usun;
	}
	void wypisz()
	{
		cout << napis1<<endl;
	}
	char wartosc(int n)
	{
		return napis1[n];
	}
	void dlugosc()
	{
		cout<<strlen(napis1)<<endl;
	}

};

int main()
{
	char *na = "kot";
	napis n(na);
	n.dopisz(na);
	n.dopisz(na);
	n.dopisz(na);
	n.dopisz(na);
	n.wypisz();
	n.dlugosc();
    return 0;
}

 

Nie umiem wrzucić w ten internetowy kompilator, więc daje tutaj.

2

Wykorzystujesz inny konstruktor niż domyślny, gdzie znów przekazujesz string literal, na którym potem wykonujesz delete[] :​)

Poprawka na szybko:

	napis(char* napis)
	{
		napis1 = napis;
	}

	napis(char* napis) : napis::napis() // delegating constructor (min. C++11)
	{
		this->dopisz(napis);
	}

Przy czym jeszcze raz podkreślam, wszystkiego byś uniknął gdybyś miał argumenty funkcji typu const char* zamiast char*. Wtedy kompilator nie pozwoliłby przypisać takiego wskaźnik do napis1.

0

Super, dzięki.
Takiej konstrukcji nie znałem. Chodzi tu o wywołanie konstruktora bez argumentowego tak?

0
kq napisał(a):

Tak, to "nowość" (sprzed 6 lat): http://en.cppreference.com/w/cpp/language/initializer_list#Delegating_constructor

Fakt, w Symfonii tego nie ma :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1