Oryginalna strona colobot.cba.pl umarła, gdy cba.pl przestało oferować darmowy hosting. To jest statyczny mirror, pobrany w 2018. ~krzys_h
 
Polski Portal COLOBOTa
COLOBOT Polish Portal

C, C#, C++ - Tablica[ZMIENNA][ZMIENNA]

Simbax - 30-05-2011, 19:42
Temat postu: Tablica[ZMIENNA][ZMIENNA]
Natknąłem się na malutki problemik. Mam już napisaną całą grę w kółko i krzyżyk. Wykonałem (bardzo trudne wg. tutoriala) ćwiczenie, żeby móc zmienić rozmiar planszy za pomocą stałej w pliku nagłówkowym.

Teraz chciałbym zrobić tak, żeby użytkownik sam na początku ustalał ten rozmiar. I tu pojawia się problem. Rozmiar jest stałą. Zapytacie - to co za problem zrobić z niego zwykłą zmienną? Otóż taki problem, że ta zmienna jest potrzebna do ustalenia rozmiaru tablicy dwuwymiarowej, a rozmiar tablicy musi być... stały.

Prościej:

Na początku programu chce się spytać o rozmiar planszy do gry. Musi to być zmienna.
cin wywala błąd, bo rozmiar planszy jest stałą.
Robię z tej stałej zmienną.
PewnaTablica[RozmiarPlanszy][RozmiarPlanszy] <- błąd! Rozmiar tablicy musi być stałą!

I co ja mam zrobić z tym, zdaje mi się nierozwiązywalnym, problemem? Może to dla was błahe, ale ja się uczę jeszcze :oops:

Raptor - 30-05-2011, 21:14
Temat postu: Re: Tablica[ZMIENNA][ZMIENNA]
Simbax napisał/a:
Może to dla was błahe, ale ja się uczę jeszcze :oops:

Dla mnie nie jest to wcale błahe. I tak jesteś na bardziej zaawansowanym poziomie, niż ja...

krzys_h - 30-05-2011, 21:14

Polecam lekturę dotyczącą dynamicznej allokacji pamięci. W wolnej chwili może dam jakiś przykładzik.
Simbax - 30-05-2011, 21:54

To ma związek ze wskaźnikami? Jeszcze daleka droga zanim dojdę do rozdziału o nich... Cóż... Będę wdzięczny za przykład.
adiblol - 30-05-2011, 22:37

Kod:
int width, height;
puts("Podaj szerokosc i wysokosc oddzielone spacja.");
scanf("%i %i", &width, &height);
T* tab = (T*)malloc(sizeof(T)*width*height);
#define tab2d(x, y) (tab[(x)+(y)*width])

Pod T podstawiamy typ tablicy.

Użycie:
Kod:

tab2d(0, 0) = jakas_zmienna;
if (tab2d(666, 1337) == jakas_inna_zmienna) poraz_uzytkownika_pradem();


Oczywiście można to zrobić lepiej na klasach.

Simbax - 31-05-2011, 16:59

ERROR '(typ ENUM)' does not define this operator or a conversion to a type acceptable to the predefined operator

:roll: Chyba sobie podziękuje. Taka drobna modyfikacja, a tyle problemów...

adiblol - 31-05-2011, 18:22

Simbax napisał/a:
ERROR '(typ ENUM)' does not define this operator or a conversion to a type acceptable to the predefined operator
Nie podałeś w której linii.
Simbax - 31-05-2011, 19:41

W takiej, w której chcę użyć tablicy ;P

(pętle for)
g_aPlansza[i][j] = FLD_EMPTY; //błąd.

W dodatku podkreśla drugi nawias kwadratowy "No operator "[]" matches these operands". I taki błąd jest jeszcze w kilkunastu innych linijkach, w których używam tablicy.

Myślałem, że dałoby radę zrobić tak, żebym nie musiał zmieniać reszty kodu. Zresztą użycie tablica(x, y) też wywołuje błąd w kompilacji :roll:

Więc jak użyć tej tablicy w linijce takiej jak ta:

Kod:
    if (g_aPlansza[uY][uX] == FLD_EMPTY) g_aPlansza[uY][uX] = static_cast<FIELD>(g_AktualnyGracz);


Po zmianie nadal jest błąd:

Kod:
    if (g_aPlansza(uY, uX) == FLD_EMPTY) g_aPlansza(uY, uX) = static_cast<FIELD>(g_AktualnyGracz);


A najlepiej to daje kod źródłowy, bo już nie wyrabiam z tym...
http://dl.dropbox.com/u/16682532/CrossCircle.zip

adiblol - 31-05-2011, 20:20

Simbax napisał/a:
bo już nie wyrabiam z tym
A w Minecrafcie wychodzi Ci wszystko od razu? Nie poddawaj się.
Berserker - 31-05-2011, 20:49

Kod:
   srand(time(NULL));
   int x = rand()%5+1;
   int y = rand()%5+1;
   Label1->Caption = x;
   Label2->Caption = y;
   AnsiString **w;
   *w = new (AnsiString*)[y];
   for(int i = 0; i < y; i++) w[i] = new AnsiString[x];
   int a, b;
   for(a = 0; a < y; a++) for(b = 0; b < x; b++) w[a][b] = "LOL ";

C++ Builder mi kompiluje, zamiast AnsiString wpisz sobie inny typ.

Swoja droga dziwny problem, pamietam, ze Dev-Cpp kompilowal mi zwykle tablice ze zmiennym rozmiarem bez problemu, tylko nie mozna bylo przy deklaracji odrazu nadawac wartosci.

Simbax - 31-05-2011, 21:19

Ech. Na razie daje sobie z tym spokój. Potrzebuję większej wiedzy żeby to wszystko ogarnąć.

adiblol napisał/a:
Oczywiście można to zrobić lepiej na klasach.


A więc lecę się dalej uczyć.

konrad-fligier@wp.pl - 17-06-2011, 23:47

(też robiłem kółko i krzyżyk - sam)

A tak trochę inaczej.
Mi działa takie coś:
Kod:

const int zmienna=10;
tab[zmienna+2][zmienna+1];


(Potrzebowałem takie coś w jednym programie)

Wiec czy zadziała to coś:
Kod:

const int zmienna=0;
int a;
cin>>a;
tab[zmienna+a];

Berserker - 18-06-2011, 01:50

Nie zadziala.
adiblol - 18-06-2011, 14:50

Simbax napisał/a:
PewnaTablica[RozmiarPlanszy][RozmiarPlanszy] <- błąd! Rozmiar tablicy musi być stałą!

A do stałej nie można zapisywać. No chyba że się uprzesz i użyjesz wskaźników ale wtedy cuda się będą działy...

Simbax - 18-06-2011, 14:59

Dałoby się wykorzystać dynamiczne tablice? Kiedyś takiego czegoś użyłem, tylko nie pamiętam w jakim celu. I jak :roll: Właściwie to w ogóle nie rozumiałem jak tamten kod działał, ale dobra...
Berserker - 18-06-2011, 15:26

Ja wlasnie dalem przyklad z dynamicznymi tablicami ;)
Phitherek_ - 10-07-2011, 23:07

Hmmm... Postaram się prosto napisać, jak stworzyć dwuwymiarową tablicę dynamiczną. Piszę na sucho bez sprawdzania, więc mogę coś pomylić, bo dawno już tego nie używałem... Kod jest w C++:

Kod:

//...
int** tab = NULL; // Tworzę wskaźnik na wskaźnik na int, na razie pusty;
int x, y; // Rozmiar tablicy x*y.
cin >> x >> y; // Wprowadzenie rozmiaru;
tab = new int*[x]; // Tworzę tablicę wskaźników o rozmiarze x.
for(int i = 0; i < x; i++) {
tab[x] = new int[y];
}
// Powyższa pętla tworzy drugi wymiar tablicy o rozmiarze y.
//...


Jeżeli nigdzie się nie pomyliłem, to powyższy kod tworzy dynamiczną tablicę dwuwymiarową o rozmiarze x*y, przy czym x i y wprowadza użytkownik z klawiatury. Tak stworzonej tablicy można potem używać tak jak tablicy statycznej - różnica jest w tym, że rozmiar może być zmienną, a nie stałą.

Mam nadzieję, że pomogłem.

Simbax - 11-07-2011, 12:30

Dzięki wszystkim za pomoc. Już powolutku rozkminiam OOP i wskaźniki. Na pewno każdy z waszych programów działa, tylko nie umiem ich wykorzystać :<

@up Bardzo ładnie, a teraz powiedz mi jak mam teraz taką tablicę wsadzić w plik nagłówkowy? :)

Phitherek_ - 11-07-2011, 13:18

Poczytaj sobie o zmiennych globalnych, polecam "Thinking in C++", strona 122 (http://helion.pl/online/thinking/index.html). Ja postaram się jeszcze zaraz napisać jakiś przykład (a tym razem siedzę na Linuxie, więc będzie to sprawdzone).

A oto i obiecany przykład:

dyntable.cpp:
Kod:

#include <iostream>
#include <cstdlib>
using namespace std;

int** tab = NULL; // Tworzę wskaźnik na wskaźnik na int
void create(int x, int y) { // Funkcja tworząca tablicę x*y
tab = new int*[x];
for(int i = 0; i < x; i++) {
tab[i] = new int[y];
}
return;
}

void init(int x, int y) { // Funkcja inicjalizująca tablicę
for(int i = 0; i < x; i++) {
for(int j = 0; j < y; j++) {
tab[i][j] = 0;
}
}
return;
}


dyntable.h
Kod:

extern int** tab; // Zmienna globalna zawarta w pliku dyntable.cpp
void init(int x, int y); // Funkcja inicjalizująca tablicę
void create(int x, int y); // Funkcja tworząca tablicę x*y


tableuse.cpp:
Kod:

#include <iostream>
#include <cstdlib>
#include "dyntable.h" // Dołączony plik nagłówkowy
using namespace std;

int main() {
int x, y; // Rozmiar tablicy x*y
// Wprowadzenie danych:
cout << "x: ";
cin >> x;
cout << "y: ";
cin >> y;
create(x,y); // Stworzenie tablicy x*y (funkcja z pliku nagłówkowego)
init(x,y); // Inicjalizacja tablicy (funkcja z pliku nagłówkowego)
for(int i = 0; i < x; i++) {
for(int j = 0; j < y; j++) {
cout << "tab[" << i <<"][" << j << "] = " << tab[i][j] << endl; // Wyświetlenie tablicy. Zwróć uwagę, że nie ma w tym programie wzmianki o zmiennej tab, jest to zmienna globalna dołączona przez plik nagłówkowy.
}
}
return EXIT_SUCCESS;
}


Kompiluję to poleceniem:
Kod:
g++ -o tableuse tableuse.cpp dyntable.cpp
- uwaga, ważne - te dwa pliki trzeba skompilować w ten sposób, to jest tzw. rozłączna kompilacja.

Program w działaniu wygląda mniej więcej tak:
Kod:

phitherek@stary-kubuntu global_test $ ./tableuse
x: 4
y: 5
tab[0][0] = 0
tab[0][1] = 0
tab[0][2] = 0
tab[0][3] = 0
tab[0][4] = 0
tab[1][0] = 0
tab[1][1] = 0
tab[1][2] = 0
tab[1][3] = 0
tab[1][4] = 0
tab[2][0] = 0
tab[2][1] = 0
tab[2][2] = 0
tab[2][3] = 0
tab[2][4] = 0
tab[3][0] = 0
tab[3][1] = 0
tab[3][2] = 0
tab[3][3] = 0
tab[3][4] = 0


Mam nadzieję, że dzięki temu zrozumiesz, jak użyć takiej tablicy w pliku nagłówkowym ;) .

Simbax - 11-07-2011, 14:25

Ooo, dzięki. Wreszcie coś zrozumiałem :>
Phitherek_ - 11-07-2011, 14:37

Nie ma sprawy, też dzięki temu odświeżyłem trochę moją wiedzę ;) .
adiblol - 11-07-2011, 18:38

A ja wciąż brzydko łączę pliki przez #include "plik.cpp" bez nagłówków. ;) Działa.
Istnieje może jakiś generator kodu żeby nie pisać ręcznie .h?

Phitherek_ - 11-07-2011, 18:49

Hmmm... Szczerze mówiąc to nie wiem, jak na razie nie pracowałem za dużo z plikami nagłówkowymi, bo moje programy są jak na razie małe i jednoplikowe, więc nie interesowałem się... Musiałbyś poszukać...

A co do łączenia plików, to w sumie do zmiennych globalnych niepotrzebne są pliki nagłówkowe, w "Thinking in C++" jest przykład rozłącznej kompilacji bez tego, wystarczy tylko to co jest w pliku nagłówkowym wstawić zamiast tego w pliku, który ma korzystać z tych zmiennych (logiczne, co nie?). Wtedy nie potrzebujesz nawet #include, tylko wystarczy rozłączna kompilacja. Pliki nagłówkowe są bardzo przydatne, jeśli chcesz używać zmiennych i funkcji w wielu plikach (czytaj: w większych projektach albo bardzo modularnych), ale takie małe programiki w ogóle ich nie potrzebują w sumie, tylko więcej roboty z ich pisaniem...

EDIT: A tak swoją drogą to przydałoby się zamknąć temat, skoro problem został rozwiązany ;) .

Simbax - 11-07-2011, 19:31

Wiesz, to jest "programik" z kursu. Właśnie miałem się nauczyć jak korzystać z plików nagłówkowych :> I tak się zgadzam, to wystarczyłoby mieć w jednym pliku, ale cóż... Uczę się :mrgreen:

Powered by phpBB modified by Przemo & WRIM © 2003 phpBB Group