Tablice tworzone za pomocą malloc - możliwe złe gospodarowanie pamięcią

0

Dobry wieczór, mam problem z tym programem - działa, itd., ale program DrMemory wskazuje 3 błędy i 3 ostrzeżenia co do gospodarowania pamięcią. Za nic nie mogę zrozumieć o co chodzi, a siedzę nad tym od paru godzin, dodaje do załącznika wyniki sprawdzania przez Dr Memory. Zauważyłem, że jak deklaracje "tablica = ( char** ) malloc( liczbaWierszy * sizeof( char ))" dam po zapełnianiu poszczególnych tablic (pierwsza pętla for w main() ), to wychodzą dwa ostrzeżenia mniej, ale program się wtedy sypie. O co może chodzić?

EDIT: dodaje numery wierszy by było wiadomo gdzie jest problem.

results.txt

#include <iostream>
#include <cstdlib>

using namespace std;

void wypiszTablice( char **tablica, int liczbaWierszy, int *dlugoscWierszy)
	{
		int dlugosc = 0;
		int pomocnicza;
		char znak;
		for( int i = 0; i < liczbaWierszy; i++)
		{
			dlugosc = 0; //dlugosc tych samych ciagow znakow
			pomocnicza = 0; //odlicza miejsce w tablicy do sprawdzenia
			for ( int j  = 0; j < * (dlugoscWierszy + i); ) // brak j++ bo wynik wychodzil za duzy
				{
					dlugosc = 0;
					znak = * ( * ( tablica + i) + j);
					do
						{
							dlugosc++; 
							pomocnicza++;
						} while ( znak == * ( * ( tablica + i) + pomocnicza ));
					j = j + dlugosc; // to zalatwia j < *(....
					cout << dlugosc << " " << znak << " "; 
				}
			cout << endl;
		}
	}

void usunWiersz( char **tablica, int &liczbaWierszy, int *dlugoscWierszy, int indeksWiersza) //referencyjnie by operowac na zmiennej, nie kopii
	{
		for ( int i = indeksWiersza; i < liczbaWierszy - 1; i++ ) // glowna petla
			{
				* ( dlugoscWierszy + i ) = * ( dlugoscWierszy + i + 1 ); // trzeba zmienic tablice dlugosci wierszy, inaczej funkcje sie posypia
				* ( tablica + i) = * ( tablica + i + 1); // zamiana tablicy wskaznikow 
			}
		free ( tablica + liczbaWierszy);
		liczbaWierszy --;
		
	}
	
void dolaczenieWiersza( char **tablica, int drugiWiersz, int pierwszyWiersz, int *dlugoscWierszy )
	{
		int j = 0;
		char *pomocnicza;
		pomocnicza = (char*) realloc ( * ( tablica + pierwszyWiersz), ( * ( dlugoscWierszy + pierwszyWiersz) + * ( dlugoscWierszy + drugiWiersz)) * sizeof( char )); // zmiana wielkosci pierwszego wiersza na wielkosc mogaca pomiescic obydwa wiersze
		if ( pomocnicza != NULL)
			{
				* ( tablica + pierwszyWiersz ) = pomocnicza; // **wiersz 51 Error #1: UNINITIALIZED READ:**
			}
		else 
			{
				free( * ( tablica + pierwszyWiersz) );
				exit (1);
			}
		for ( int i = * ( dlugoscWierszy + pierwszyWiersz ) ; i <= * ( dlugoscWierszy + pierwszyWiersz) + * ( dlugoscWierszy + drugiWiersz) ; i ++) // zaczynamy od elementu konczacego pierwszy wiersz
			{
				* ( * ( tablica + pierwszyWiersz) + i ) =  * ( * ( tablica + drugiWiersz) + j ); // kopiowanie zawartosci
				j++;
			}
		* ( dlugoscWierszy + pierwszyWiersz ) = * ( dlugoscWierszy + drugiWiersz ) + * ( dlugoscWierszy + pierwszyWiersz);
	}
	
void odwrocenieWiersza( char **tablica, int *dlugoscWierszy, int numerWiersza )
	{
		char a;
		for ( int i = 0; i < * ( dlugoscWierszy + numerWiersza ) / 2 ; i++ ) // wystarczy dojsc do polowy
			{
				a = * ( * ( tablica + numerWiersza) + i );
				* ( * ( tablica + numerWiersza) + i ) = * ( * ( tablica + numerWiersza) + * ( dlugoscWierszy + numerWiersza) - 1 - i ); // minus jeden, inaczej wychodzily krzaki
				* ( * ( tablica + numerWiersza) + * ( dlugoscWierszy + numerWiersza) - 1 - i ) = a;
			} 
	}

void usuniecieElementow ( char **tablica, int *dlugoscWierszy, int numerWiersza )
	{
		int pomocnicza = 0; // zapisuje o ile zmniejszyc dlugosc wiersza
		for ( int i = 0; i < * (dlugoscWierszy + numerWiersza); i++ )
			{
				if ( i%2 == 0)
					{
						for ( int k = i; k < * ( dlugoscWierszy + numerWiersza ); k++ )
							{
								* ( * ( tablica + numerWiersza) + k ) = * ( * ( tablica + numerWiersza) + k + 1 );
							}
						* ( dlugoscWierszy + numerWiersza ) = * ( dlugoscWierszy + numerWiersza ) - 1;
						pomocnicza++;
					}
			}
		// * ( dlugoscWierszy + numerWiersza ) = * ( dlugoscWierszy + numerWiersza ) - pomocnicza;
	} 
	
int main()
{
	// tworzenie tablicy i deklaracja podstawowych zmiennych
	char **tablica;
	int liczbaWierszy;
	int liczbaLiter;
	char litera;
	cin >> liczbaWierszy;  // wiersz 102 Error #1: UNINITIALIZED READ:
	int *dlugoscWierszy;
	int liczbaPoszczegolnychLiter;
	int suma = 0;
	int j = 0;
	int pomocniczaZmienna = 0;
	char kodOperacji;
	int numerWiersza;
	int numerWiersza1D;
	int numerWiersza2D;
	int numerWierszaF;
	int numerWierszaX;
	tablica = ( char** ) malloc( liczbaWierszy * sizeof( char )); // **Wiersz 114 WARNING: heap allocation failed **
	dlugoscWierszy = ( int* ) malloc( liczbaWierszy * sizeof( int )); // **Wiersz 115 WARNING: heap allocation failed**
	for( int i = 0; i < liczbaWierszy; i++ ) // tworzenie tablicy // **Wiersz 116 Error #4: UNINITIALIZED READ:**
		{
			suma = 0;
			j = 0;
			pomocniczaZmienna = 0;
			cin >> liczbaLiter;
			* ( dlugoscWierszy + i) = liczbaLiter; // **Wiersz 122 Error #5: WARNING: heap allocation failed** **Error #6: UNADDRESSABLE ACCESS:**
			* ( tablica + i ) = ( char* ) malloc( liczbaLiter * sizeof( char ));		
			while ( suma < liczbaLiter ) // zakladam, ze dane sa poprawnie wprowadzone 
				{
					cin >> liczbaPoszczegolnychLiter;
					cin >> litera;
					pomocniczaZmienna = liczbaPoszczegolnychLiter + j;
					for ( j; j < pomocniczaZmienna; j++ )
							{
								*(* ( tablica + i) + j ) = litera;
							}
					suma = suma + liczbaPoszczegolnychLiter;
				}		
		}
	cin >> kodOperacji;
	while ( kodOperacji != 'K')
		{
			if ( kodOperacji == 'W')
				{
					wypiszTablice( tablica, liczbaWierszy, dlugoscWierszy );
				}
			if ( kodOperacji == 'U')
				{
					cin >> numerWiersza;
					usunWiersz( tablica, liczbaWierszy, dlugoscWierszy, numerWiersza );
				}
			if ( kodOperacji == 'D')
				{
					cin >> numerWiersza1D;
					cin >> numerWiersza2D;
					dolaczenieWiersza( tablica, numerWiersza1D, numerWiersza2D, dlugoscWierszy );
				}
			if ( kodOperacji == 'R')
				{
					cin >> numerWierszaF;
					odwrocenieWiersza ( tablica, dlugoscWierszy, numerWierszaF );
				}
			if ( kodOperacji == 'X')
				{
					cin >> numerWierszaX;
					usuniecieElementow( tablica, dlugoscWierszy, numerWierszaX);
				}
			cin >> kodOperacji; 
		}
	/* for( int i = 0; i < liczbaWierszy; i++)
		{
		for ( int j  = 0; j < * (dlugoscWierszy + i); j++ )
			{
				cout << *(* ( tablica + i) + j );
			}
		cout << endl;
		} */
	free(tablica);
	free(dlugoscWierszy);
	return 0;
}
1

Nie wiem czy to bezpośrednio związane, ale imho alokujesz zły rozmiar zmiennej tablica:

//jest 
tablica =  (char**) malloc(liczbaWierszy * sizeof(char));
//powinno być //zwroc uwage na sizeof i gwiazdke
tablica =  (char**) malloc(liczbaWierszy * sizeof(char*));

EDIT: tak, to o to chodzi.
Do tego doktorek zgłasza też błąd w wyświetlaniu tablicy. Dalej mi się już nie chce szukać, sorry :P

Mogę to jeszcze przeanalizować, ale pytanie zasadnicze - taka z czapki architektura czemuś ma służyć? Bo rozsądniej byłoby np. stosować zero-terminated string albo np. strukturę typu

struct dynamic_text {
  char * contents;
  unsigned int len;
}
0

Racja, coś to pomogło, a wyjaśnisz czym się to różni od tego co zastosowałem? Czy dlatego, bo char* oznacza prośbę o przydzielenie pamięci dla tablicy, a zwykły char o parę bitów dla znaku? A czemu ma to służyć - ma służyć mojemu wykładowcy ze studiów :D. Co do takiej struktury - nie mogłem używać stringów, ale o takiej strukturze nie pomyślałem...

0

bo char to znak a char* to wskaźnik na znak
znak zajmuje 1 bajt, a wskaźnik zazwyczaj 4

0

wgl co ten program ma robić? nie możesz korzystać z std::string i tablic tak?

0

@mały Kaczor
Ach, no tak, to wszystko wyjaśnia... ale program mi się kompilował i działał O_o.

@karolinaa
Co ma robić? Te funkcje co tam są podane w sumie... Najpierw się tworzy tablice, potem daje literki i się robią funkcje, sęk w tym, że mogą się robić dla milionów danych, więc zarządzanie pamięcią jest bardzo ważne. Stringów nie mogłem używać, a to są tablice, tylko. że zapisywane "wskaźnikowo", nie nawiasami kwadratowymi. Których nie mogłem używać.

0

@karolinaa strup odpadało, mogłem użyć tylko biblioteki cstdio i cstdlib. O strukturach nie pomyślałem.

Ponadto pomoglibyście z funkcją usuniecieElementow? Ma ona usuwać elementy tablicy o parzystych indeksach, siedzę nad tym i nie mogę znaleźć błędu. Nie wiem, czy zamysł jest w ogóle zły, czy jest jakiś głupi błąd... Czasami funkcja nie usuwa niektórych elementów których powinna, np. dla 10 x, usuwa tylko 4 x, przez co zostają 6 x , a nie 5 x. A dla tablicy
10x 2c 1b 1a zostawia 6x 2c 1a, a powinno 5x 1c 1a.

void usuniecieElementow ( char **tablica, int *dlugoscWierszy, int numerWiersza )
	{
		for ( int i = 0; i < * (dlugoscWierszy + numerWiersza); i++ )
			{
				 if ( i % 2 == 0)
					{
						for ( int k = i; k < * ( dlugoscWierszy + numerWiersza ); k++ )
							{
								* ( * ( tablica + numerWiersza) + k ) = * ( * ( tablica + numerWiersza) + k + 1 ); // przesuwam wszystkie elementy o jeden
							}
							* ( dlugoscWierszy + numerWiersza ) = * ( dlugoscWierszy + numerWiersza ) - 1;		// aktualizuje tablice dlugosci poszczegolnych wierszy	
					} 
				
			}	
	} 

Wiem, że jak na bieżąco aktualizuje długość tablicy to się pętla for za mało razy wykonuje. Jak to naprawić, jakiś inny algorytm wymyślić?

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