Informatică, întrebare adresată de gugleadennis88, 8 ani în urmă

Eroare in C++. Cum as putea sa solutionez ?

#include

using namespace std;
ifstream fin("culoare.in");
ofstream fout("culoare.out");
const int di[]={-1, 0, 1, 0},
dj[]={ 0, 1, 0,-1};
int n , m, istart , jstart, a, culoare;

void Fill(int i ,int j ,int v, int abc)
{
// i,j - elementul curent, v - valoarea cu care facem Fill
if(i >= 1 && i <= n && j >= 1 && j <= m && A[i][j] == abc)
{ // in matrice, element liber si nemarcat
A[i][j] = v;
for(int k = 0 ; k < 4 ; k ++)
Fill(i + di[k] , j + dj[k], v, abc);
}
}

int main()
{

fin>>n>>m;
int A[n][25];
for(int i = 1 ; i <= n ;i ++)
for(int j = 1 ; j <= m ; j ++)
fin >> A[i][j];
fin >> istart >> jstart>> culoare;
a=A[istart][jstart];

Fill(istart, jstart, culoare, a);

for(int i =1 ; i <= n ;i ++, fout << "\n")
for(int j = 1; j <= m ; j ++)
fout << A[i][j] << " ";

return 0;
}

Anexe:

andrei750238: Matricea A e declarata doar in functia main, trebuie transmisa ca parametru ca aceasta sa fie vizibila si in alte functii.
andrei750238: Si e declarata prost, nu asa se declara o matrice dinamic
gugleadennis88: ok, am inteles, asta stiu. Intrebarea mea era, cum sa declari o variabila integer 2D, marimile caruia sunt luate de la tastatura ?
gugleadennis88: astfel incat sa fie vizibila si in functia void? si cum ar trebui sa scriu, pentru ca parametrul A, sa fie transmis la acea functie. Eu abia invat, astfel de probleme.
gugleadennis88: scuze de deranj dar poti sami raspunzi la o intrebare ?

Răspunsuri la întrebare

Răspuns de andrei750238
5

► PROGRAM C++ :

#include <fstream>

using namespace std;

void fill(const unsigned i, const unsigned j, const unsigned culoare_noua, const unsigned culoare_veche, const unsigned n, const unsigned m, int** matrice)

{

const int di[] = { -1, 0, 1, 0 };

const int dj[] = { 0, 1, 0,-1 };

if (i >= 0 && i < n && j >= 0 && j <= m && matrice[i][j] == culoare_veche)

{

 matrice[i][j] = culoare_noua;

 for (int vecin = 0; vecin < 4; vecin++)

  fill(i + di[vecin], j + dj[vecin], culoare_noua, culoare_veche, n, m, matrice);

}

}

//Functie pentru alocarea dinamica a memoriei

int** alocare_mem(int n, int m) {

//Alocare linii

int** A = new int* [n];

//Alocare coloane

for (int col = 0; col < m; col++)

 A[col] = new int[m];

//Returnare matrice alocata dinamic

return A;

}

void dealocare(int** A, int n) {

//Dealocare fiecare linie

for (int col = 0; col < n; col++)

 delete A[col];

//Dealocare fiecare coloana

delete A;

}

int main()

{

//Deschidere fisiere

ifstream fin("culoare.in");

ofstream fout("culoare.out");

//Citire dimensiuni matrice

int n, m;

fin >> n >> m;

//Alocare memorie matrice

int** matrice;

matrice = alocare_mem(n, m);

//Citire matrice

for (int i = 0; i < n; i++)

 for (int j = 0; j < m; j++)

  fin >> matrice[i][j];

//Citire coordonate start, culoare

unsigned istart, jstart, culoare;

fin >> istart >> jstart >> culoare;

//Compensare pentru inceperea de la 0

--istart;

--jstart;

//Inchidere fisier citire

fin.close();

//Umplere recursiva

fill(istart, jstart, culoare, matrice[istart][jstart], n, m, matrice);

//Afisare

for (int i = 0; i < n; i++)

{

 for (int j = 0; j < m; j++)

  fout << matrice[i][j] << " ";

 fout << endl;

}

//Inchidere fisier scriere

fout.close();

//Dealocare matrice

dealocare(matrice, n);

return 0;

}

► Explicatie :

O variabila (fie aceasta o variabila simpla, vector, matrice, ins.tanta a unei clase, s.a.m.d. ) este vizibila doar in functia/scope in care este declarat.

Pentru ca matricea noastra sa fie vizibila in functia fill avem doua optiuni :

  • Trimitem matricea ca parametru (adaugam int** matrice la lista de parametrii). Deoarece o matrice este un pointer catre un vector de vectori NU este necesar sa transmitem matricea prin referinta. Putem accesa si modifica elementele matricei direct.
  • Declaram matricea global (nerecomandat)
  • Ne folosim de avantajele programarii orientate pe obiect (recomandat cu tarie)

Pentru alocarea/eliberearea memoriei in mod dinamic in C++ avem operatorii new si delete.

Pentru alocarea memoriei trebuie sa alocam memorie pentru fiecare linie (liniile sunt vectori de numere intregi, deci int *), iar pentru fiecare astfel de linie trebuie sa alocam memorie pentru m variabile de tip int.

Dealocarea se face in ordine inversa (dealocam fiecare linie apoi dealocam matricea = vectorul de linii).

Gasesti pe net mai multe resurse privind alocarea dinamica in C++.

Sfaturi :

  • Incercam sa evitam variabilele declarate global pe cat posibil. In proiecte mari acestea pot cauza probleme greu de diagnosticat, deci e indicat sa ne invatam sa le evitam pe cat putem de acum.
  • Incercam sa declaram constant tot ce ar trebui sa fie constant.
  • Inchidem fisierele in momentul in care nu mai avem nevoie de ele pentru a putea elibera resurse.
  • Nu uitam sa eliberam memoria alocata dinamic.
  • In mod normal se evita proiectarea functiilor cu mai mult de 3-4 parametrii, folosind concepte de programare orientata pe obiecte (presupun ca nu ai invatat, din acest motiv nici nu am folosit aici).
  • Incercam sa pastram codul cat mai usor de citit, punem nume sugestiv variabilelor.
  • Evitam functiile recursive, utilizam stive/cozi pentru a putea rezolva problema iterativ (nu am respectat sfatul asta aici, am vrut sa modific codul tau, dar pe viitor tine minte ca implementarile recursive "costa" mai mult decat implementarile iterative)

Ai test pe exemplu in atasament

Anexe:

gugleadennis88: scuze de deranj dar poti sami raspunzi la o intrebare ?
gugleadennis88: de ce in acest program care til trimit, programul se inchide inainte, de a introduce variabila string
gugleadennis88: int main()
{
int n; cin>>n;
string s;
getline (cin, s);
cout< return 0;
}
gugleadennis88: se sterg unele lucruri, din program, dar scriele corect intrun compiler, si introduci un numar, si se inchide imediat, fara ca un string sa-l scrii, nu stii de ce ?
andrei750238: E o ciudatenie la modul in care functioneaza getline. Practic acesta citeste caracterele din buffer pana cand da de caracterul new line. Ia stringul citit pana la caracterul respectiv si in copiaza.

Tasta enter e echivalenta cu intalnirea caracterului new line.
Caracter gol = spatiu, caracter new line, caracter null, tab, etc.
andrei750238: Atunci cand folosim consola avem un buffer care memoreaza mereu tastele apasate. La intalnirea cin se sar caracterele "goale", si se copiaza continutul pana la urmatorul caracter "gol", dar nu se sterge acest caracter gol din buffer.

Cand apelam getline apoi se intalneste caracterul new line (pe care cin nu l-a scos din buffer) si crede ca trebuie sa se opreasca. Copiaza stringul citit (de niciun caracter practic) in s si zice ca si-a terminat treaba.
andrei750238: O diferenta intre cin si getline e ca getline "face curatenie", sterge si caracterul newline din buffer.
andrei750238: Daca pui getline(cin, s); de doua ori ar trebui sa mearga cum trebuie
andrei750238: Sau daca vrei sa folosesti prima metoda poti scrie numarul si stringul pe acelasi rand si la final dai enter
gugleadennis88: mersi foarte mult
Alte întrebări interesante