- sziku69: Szólánc.
- sziku69: Fűzzük össze a szavakat :)
- Luck Dragon: Asszociációs játék. :)
- D1Rect: Nagy "hülyétkapokazapróktól" topik
- btz: Internet fejlesztés országosan!
- gban: Ingyen kellene, de tegnapra
- Gurulunk, WAZE?!
- VoidXs: Tényleg minden játék optimalizálatlan?
- Hieronymus: Három júniusi képem
- Magga: PLEX: multimédia az egész lakásban
Új hozzászólás Aktív témák
-
dobragab
addikt
válasz
dabadab #4197 üzenetére
Vagy meg inkabb, ha C++11:
struct Point
{
int x = 0;
int y = 0;
Point() = default;
Point(int x, int y)
x(x),
y(y)
{}
};Csak mivel a kollega nem hasznalt inicializalo listat, ezert nem akartam abba bonyolodni, hogy megmutassam. Es beepitett tipusokra konkretan egyenerteku a ketto. Majd ha nincs default ctor vagy van dinamikus memoriakezeles, akkor kezd ertelme lenni megmutatni.
Amúgy meg van olyan kezdőknek szóló könyv, amit úgy meg bírtak írni, hogy a példák vállalhatóak?...
Nekem van egy kezdemenyezesem, de eleg hatarozottan a BME mernokinfos prog2-re van szabva, es a C ismeretere epit.
(#4198) mgoogyi
Amíg egy egyszerű téglalap reprezentációja ennyi magyarázatra szorul, az nekem azt mutatja, hogy nagyon keveset kódolt még.
Igen, es nem latom ertelmet annak, hogy OOP-t tanuljon ennyire koran, de hat...
-
mgoogyi
senior tag
válasz
dabadab #4197 üzenetére
Egyetértek veletek, hogy az OOP-t nem tanítják meg rendesen.
Viszont a kérdező srácnak még lehet korai túlzottan ebbe belemenni, egyelőre szerintem ott tart, hogy a nagyon alap dolgok meglegyenek. Amíg egy egyszerű téglalap reprezentációja ennyi magyarázatra szorul, az nekem azt mutatja, hogy nagyon keveset kódolt még.Visszatérve az OOP-re, nekem a láthatóságokkal kapcsolatban zavar pl, hogy mennyire nem tanítják(és nekem sem tanították), hogy mi a valódi haszna annak, hogy semmit sem szabad feleslegesen publicon hagyni.
Annyit tudnak, hogyha valami private, akkor az nem látszik kívülről, de hogy az miért jó, arra már semmi ötletük nincs.
És hát azért nem tanítják, mert jellemzően a gyakorlatvezető sem tudja. -
dabadab
titán
válasz
dobragab #4196 üzenetére
struct Point
{
int x;
int y;
Point()
{
x = 0;
y = 0;
}
Point(int x, int y)
{
this->x = x;
this->y = y;
}
};Sőt:
struct Point
{
int x;
int y;
Point()
{
x = 0;
y = 0;
}
Point(int x, int y):
x(x),
y(y)
{}
};Nyilván ízlés kérdése, de egyrészt nem szeretem az explicit this-ezést, mert az vagy felesleges vagy valami problémás dolgot takar, másrészt meg szerintem ez nagyon szép és intuitív (és - nem mellesleg - teljesen jól működik).
Amúgy meg van olyan kezdőknek szóló könyv, amit úgy meg bírtak írni, hogy a példák vállalhatóak?...
"az OOP-nek (objektumorientalt programozas) jo lenne, ha nem csak a szintaktikai elemeit tanitanak meg, hanem az elveket, ami menten epiteni es alkalmazni illik. Anelkul semmi ertelme az egesznek."
Így van, mert aztán az ember produkciós kódban olyat lát, hogy
pX->m_pY->m_Z = foo;
(és nem egy ilyen sort, hanem több tízezer sornyi kód van ebben a stílusban írva és persze az osztályok összes tagja public (a Lock() / Unlock() is (amik mondjuk eleve azért vannak, mert a RAII sem ért el hozzájuk))
-
dobragab
addikt
válasz
cadtamas #4190 üzenetére
Most, hogy mar erted is, hadd szidjam kicsit a feladatot.
A legnagyobb problema a Rectangle-ben, hogy redundans adattagok vannak benne. Alapvetoen ez egy olyan teglalapot tarol, aminek az oldalai parhuzamosak a tengelyekkel, tehat kb. ennyi adattagra lenne szukseg:
Point topLeft;
int width;
int height;vagy
Point topLeft;
Point bottomRight;Hiszen ebbol a kettobol ki lehet szamolni az osszes tobbi adatot, egyetlen osszeadassal / kivonassal. Amugy a getter ertelme pont ez, hogy ha valami nem kozvetlenul all rendelkezesre, akkor is ki tudja szamolni / ossze tudja rakni. Ha ennel tobb adatod van, akkor sziszifuszi harc ezt konzisztensen tartani (ertsd: ne legyenek benne egymasnak ellentmondo adatok), ezert 3-5 soros egy setter. Igy kene mondjuk:
Point getLowerLeft() const
{
return Point(topLeft.getX(), bottomRight.getY());
}A masodik baj, hogy tobb setter, pl. a setTopLeft fuggveny szemantikailag ertelmetlen. Egy teglalap bal felso sarkat hogy allitod? Tolod az egesz teglalapot, hogy a merete maradjon meg, vagy megnyujtod, es 2 pontot mozgatsz vele, hogy a jobb also pont maradjon a helyen? Mivel nem egyertelmu, hogy mit csinal, nem szabadna ilyen nevu fuggvenynek lennie. At lehetne nevezni mondjulk pushTopLeft-re vagy dragTopLeft-re, ugy mar egyertelmu, hogy a teglalapot nyujtja, mint PowerPointban a kep atmeretezese.
Altalaban veve pedig a setter rossz omen, azt sugja (haladobbaknak: code smell, tehat nem feltetlenul rossz, csak nagyon nagy valoszinuseggel), hogy valami nem oke a koddal. (haladobbaknak: Single Responsibility Principle-t sert, konkretan ugy, hogy nincs is responsibility.) Itt pl. az, hogy semmit nem csinal az osztalyod, semmivel sem jobb, mint
struct Point { int x; int y; };
A harmadik problema, hogy a Pont-nak kene konstruktor setter helyett.
struct Point
{
int x;
int y;
Point()
{
x = 0;
y = 0;
}
Point(int x, int y)
{
this->x = x;
this->y = y;
}
};Es igy nem kell bele setter sem, mert felul tudod irni az = operatorral, pl.
topLeft = Point(topLeft.x, topLeft.y + 10);
Destruktort megmutatni semmi ertelme, amig nincs eroforraskezeles (tipikusan: dinamikusan foglalt memoria), es a Rectangle osztalyban amugy sem szabad ilyennek lennie (egy teglalap ne kezeljen mar dinamikus adatot, haladobbaknak: ez megint SRP-t sert). De ezt irtak elottem is.
Negyedik: hibas a Point ket settere (ami amugy nem is kene, lasd fent). Igy lenne helyes:
void setX(int x) { itsX = x; }
void setY(int y) { itsY = y; }Igy hirtelen ennyi, ami bokte a csorom. Azert irtam le, mert az OOP-nek (objektumorientalt programozas) jo lenne, ha nem csak a szintaktikai elemeit tanitanak meg, hanem az elveket, ami menten epiteni es alkalmazni illik. Anelkul semmi ertelme az egesznek.
OFF: amugy sajnos nem talaltam olyan konyvet, ahol le vannak ezek irva rendesen, es nem 500+ oldalban. Ha valaki tud ilyet, ne tartsa magaban.
-
mgoogyi
senior tag
válasz
cadtamas #4193 üzenetére
Az implementáció mondja meg, hogy mit csinálnak a függvények. Anélkül nincs program, csak a függvények fejlécei. Az implementációt találod a cpp fileban.
A .h-ban megmondod, hogy ilyen-olyan függvényeid vannak az osztályban, meg ilye-olyan adattagjaid.
A .cpp-ben meg elvégzed az érdemi munkát, azaz kifejted(implementálod), hogy mit csinál a konstruktor, mit csinál a settop és a többi függvény. Ha ezt nem tennéd meg, a program futásakor nem lenne semmi a függvényhívások mögött.A privát változókat az osztály saját függvényei látják, egyedül előttük nem rejtett. Ha legalább ők nem látnák, akkor semmi értelme nem lenne a privátnak.
Ezek az osztály saját belső állapotát tükroző változók, nem lokálisak. A lokálisnak látnád a deklarációját a függvény elején, pl. int itsTop;
Az osztályra meg úgy gondolj, mint egy olyan valamire, aminek a belső változói adják az állapotát és a függvények pedig azt módosítják vagy azt felhasználva csinálnak valamit.
Amikor a konstruktor lefut, akkor éppen frissen létrejött az osztályodból egy új objektum. A konstruktor a kezdeti állapotát állítja be az objektumodnak. Ezután az objektumon az osztály minden publikus függvényét meghívhatod, ami konkrétan azon az objektumon fog dolgozni. Egy osztályból annyi objektumot csinálsz(példány példányosítasz), amennyit akarsz. Mindegyiknek meglesz a saját belső független állapota, saját itsTop, itsRight stb. belső értékekkel.
-
cadtamas
tag
Rectangle::Rectangle(int top, int left, int bottom, int right) //konstruktor, idáig rendben vagyunk
{
itsTop = top; //Ez elvileg az implementáció, amit nem taglal a könyv, hogy miért kell és később miért nem használjuk semmire.
itsRight = right;
itsLeft = left;
itsBottom = bottom;
itsUpperLeft.setX(left);
itsUpperLeft.setY(top);
itsUpperRight.setX(right);
itsUpperRight.setY(top);
itsLowerLeft.setX(left);
itsLowerLeft.setY(bottom);
itsLowerRight.setX(right);
itsLowerRight.setY(bottom);
}Ugye az implementáció azért kell, mert az alapján fog elkészülni a négyszög. Gyakorlatilag automatikusan lefutnak ezek az utasítások, amikor egy négyszög objektumot létrehozunk.
Viszont az első 4 változó privát elérésű tag. Itt mégis lehet nekik közvetlenül értéket adni?
Vagy ez ilyenkor nem számít? Vagy ez a négy változó nem is az a változó amit a .h fájlban deklaráltunk, hanem valami helyi dolog?Elnézést a hülye kérdésekért, de ha ezeket nem rakom tisztába, később tutira nem fogom érteni, hogy mi történik.
-
mgoogyi
senior tag
válasz
cadtamas #4190 üzenetére
//Ez elvileg az implementáció, amit nem taglal a könyv, hogy miért kell és később miért nem használjuk semmire.
-> Az implementáció írja le a dolgok működését, a .h-ban meg azt látod, hogy mit tudsz csinálni majd ezen az osztályon//ide kellene gondolom a destruktor, ami azért jó, mert memóriát szabadít fel?
-> vagy egyéb resource-öket enged el, de az osztályodban nincs ilyen. Akkor fogsz látni destruktort, ha az osztályodban lesz olyan, hogy "new"setupperleft:
//módosítja a JobbFelső pont Y értékét, de miért???
-> azért, mert ez egy téglalap, ha a bal felső sarkát feljebb húzod, a jobb felsőnek is követnie kell//a test felső vonalát határozza meg, de nem ez a dolga!!!
-> dehogynem, az itstop értékét, azaz mi a legnagyobb Y értéke a téglalapnak, módosítani kell, amikor valamelyik sarkát arrébb teszedsetTop(int top):
//beállítja a test felső vonalát. Ugyanazt mint a setUpperLeft() függvény. MIÉRT???
-> azért, mert ez a függvény a téglalap felső oldalát teszi arrébb, amivel együtt mozognak a felső sarkai -
cadtamas
tag
Sziasztok.
A tanuljuk meg a c++ nyelvet 24 óra alatt c. könyvből tanulok és az osztályoknál járok.
Van néhány dolog amit nem értek a példafeladatban.
Ez a header. Ez tiszta.#pragma once
# include <iostream>
class Point
{
private:
int itsX;
int itsY;
public:
void setX(int x) { int itsX = x; }
void setY(int y) { int itsY = y; }
int getX() const { return itsX; }
int getY() const { return itsY; }
};
class Rectangle
{
public:
Rectangle(int top, int left, int bottom, int right);
//~Rectangle();
int getRight() const { return itsRight; }
int getLeft() const { return itsLeft; }
int getTop() const { return itsTop; }
int getBottom() const { return itsBottom; }
Point getUpperLeft() const { return itsUpperLeft; }
Point getLowerLeft() const { return itsLowerLeft; }
Point getUpperRight() const { return itsUpperRight; }
Point getLowerRight() const { return itsLowerRight; }
void setUpperLeft(Point location);
void setLowerLeft(Point location);
void setUpperRight(Point location);
void setLowerRight(Point location);
void setRight(int right);
void setLeft(int left);
void setTop(int top);
void setBottom(int bottom);
int getArea() const;
private:
int itsTop;
int itsBottom;
int itsLeft;
int itsRight;
Point itsUpperLeft;
Point itsUpperRight;
Point itsLowerRight;
Point itsLowerLeft;
};Viszont itt több helyen elakadtam:
#include "rect.h"
Rectangle::Rectangle(int top, int left, int bottom, int right) //konstruktor, idáig rendben vagyunk
{
itsTop = top; //Ez elvileg az implementáció, amit nem taglal a könyv, hogy miért kell és később miért nem használjuk semmire.
itsRight = right;
itsLeft = left;
itsBottom = bottom;
itsUpperLeft.setX(left);
itsUpperLeft.setY(top);
itsUpperRight.setX(right);
itsUpperRight.setY(top);
itsLowerLeft.setX(left);
itsLowerLeft.setY(bottom);
itsLowerRight.setX(right);
itsLowerRight.setY(bottom);
}
//ide kellene gondolom a destruktor, ami azért jó, mert memóriát szabadít fel?
void Rectangle::setUpperLeft(Point location) //definiáljuk a függvényt
{
itsUpperLeft = location; //módosítja a változót ami elvileg az egyetlen feladata.
itsUpperRight.setY(location.getY()); //módosítja a JobbFelső pont Y értékét, de miért???
itsLowerLeft.setX(location.getX()); //módosítja a BalAlsó pont X értékét, de miért???
itsTop = location.getY(); //a test felső vonalát határozza meg, de nem ez a dolga!!!
itsLeft = location.getX(); //a test bal szélső vonalát határozza meg, de nem ez a dolga!!!
}
void Rectangle::setLowerLeft(Point location)
{
itsLowerLeft = location;
itsLowerRight.setY(location.getY());
itsUpperLeft.setX(location.getX());
itsBottom = location.getY();
itsLeft = location.getX();
}
void Rectangle::setLowerRight(Point location)
{
itsLowerRight = location;
itsLowerLeft.setY(location.getY());
itsUpperRight.setX(location.getX());
itsBottom = location.getY();
itsRight = location.getX();
}
void Rectangle::setUpperRight(Point location)
{
itsUpperRight = location;
itsUpperLeft.setY(location.getY());
itsLowerRight.setX(location.getX());
itsTop = location.getY();
itsRight = location.getX();
}
void Rectangle::setTop(int top) //beállítja a test felső vonalát. Ugyanazt mint a setUpperLeft() függvény. MIÉRT???
{
itsTop = top; //Ez lenne a dolga
itsUpperLeft.setY(top); //Ez ugyanazt módosítja, mint a setUpperLeft() függvény. (Részben) De ez nem ennek a feladata...
itsUpperRight.setY(top); //Ez ugyanazt módosítja, mint a setUpperRight() függvény. (Részben) De ez nem ennek a feladata...
}
void Rectangle::setLeft(int left)
{
itsLeft = left;
itsUpperLeft.setX(left);
itsLowerLeft.setX(left);
}
void Rectangle::setBottom(int bottom)
{
itsBottom = bottom;
itsLowerLeft.setY(bottom);
itsLowerRight.setY(bottom);
}
void Rectangle::setRight(int right)
{
itsRight = right;
itsUpperRight.setX(right);
itsLowerRight.setX(right);
}
int Rectangle::getArea() const
{
int width = itsRight - itsLeft;
int height = itsTop - itsBottom;
return (width*height);
}
int main()
{
Rectangle MyRectangle(100, 20, 50, 80); //Létrehozzuk a négyszöget
int Area = MyRectangle.getArea();
std::cout << "Terulet: " << Area << "\n";
std::cout << "Bal felso pont x koordinataja: ";
std::cout << MyRectangle.getUpperLeft().getX()<< std::endl; //ennek 20-nak kellene lennie, de nem annyi.
system("pause");
return 0;
}
Kommenteltem, ami nem világos. Tudnátok segíteni, hogy megértsem mi, miért történik? -
dobragab
addikt
válasz
Bruce1967 #4185 üzenetére
VS2015 / VS2017 + ReSharper C++. Amúgy amíg a tanulás legelején vagy, addig CodeBlocks-t érdemes, utána CLion-re érdemes áttérni. VS+ReSharper legnagyobb előnye a CLion-höz képest, hogy nagy kódbázison gyorsabb. pl. a "go to definition" meg ilyen dolgok, azt meg úgyse használod ki.
-
mgoogyi
senior tag
-
Bruce1967
tag
Sziasztok!
Lenne egy olyan kérdésem hogy ki mivel ir programot c++ban én spec code blocksban.
Nekem valahogy a c++ jobban fekszik mint a Java de melyik az erősebb nyelv amivel a legtöbb dologra lehet irni? -
Canela88
újonc
Köszönöm, meg is értettem a stepsTaken lényegét.
int sum = 0;
int stepsTaken = 1;
for (int i = 0; i < myVector.size(); ++i) {
for (int j = 0; j < myVector[j].size(); ++j) {
if (stepsTaken % 2 == 1) {
sum += myVector[j];
}
stepsTaken++;
}
}
std::cout << sum << std::endl;most ez a kód, és nem megy... 29-t ad ki. stepstakent is felvettem 1-re, mert úgy tűnik logikusnak. de mindhiába...sehogy sem akar 30 lenni..
-
Drizzt
nagyúr
válasz
Canela88 #4180 üzenetére
A pozicio csak egy szamlalo, hogy mennyit leptunk a ciklusban eddig. Minden masodik lepesre akarsz kiirni valamit, ezert kell szamolni, hogy masodik lepesben vagy-e. Es igen, myVector [j] kell. Gondolom a size az 3? Nem kell azt se beegetni, az elso ciklusban lehetne myVector.size() a masodikban myVector[j].size(). Lehet a position neve ha stepsTaken, vagy valami hasonlo lenne, vilagosabb lenne a celja.
Meg latom azt elrontottam, hogy a positiont az if-en kivul kellene leptetni, s a feltetel is position % 2 == 1 lenne helyesen.
-
Canela88
újonc
Ne haragudj nem értem, hogy honnan tudná, hogy mi a pozíció és nem is jön ki. A vektornak meg kell adjam az i indexét is, mert különben pirosan feszít itt nekem.
Nekem főleg most a megértéssel van a problémám.int sum = 0;
int position = 0;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; ++j) {
if (position % 2 == 0) {
sum += myVector[j];
position++;
}
}
//sum = myVector[0][1] + myVector[1][0] + myVector[1][2] + myVector[2][1];
}ezt írtam. Jó ez így egyáltalán?
-
Drizzt
nagyúr
válasz
Canela88 #4178 üzenetére
Hát iterálj végig az össze elemen sorfolytonosan, lehetőleg index alapján. Előtte csinálj egy int sum = 0 változót, meg egy int position = 0-t. Aztán a beágyazott ciklusban: if (position % 2 == 0) {sum += myVector[j]; position++;} (i a sorokon iteráló int változó, j az oszlopokon.) De c++hoz továbbra is 10+ éve nyúltam, úgyhogy szintaktikailag lehet helytelen.
-
Canela88
újonc
Sziasztok! Remélem tud nekem valaki segíteni, mert már jó ideje kínlódom, és csak nem jön a megvilágosodás. Nemrégen kezdtem C++-t tanulni és megfognak a többdimenziós vectorok. Többek között.
A példa a következő, adott egy vector és szeretném minden 2. elemét kinyerni és összeadni. Tehát az output 30 kell legyen (8+2+16+4).std::vector<std::vector<int>> myVector = {{3, 8, 2},
{2, 5, 16},
{-3, 4, 9}};Köszönöm előre is!
-
b.kov
senior tag
válasz
gergoavideki #4176 üzenetére
Szia!
Szerintem nyugodtan írhatod ide is a problémádat, több szem többet lát. -
gergoavideki
újonc
Sziasztok!
Code
locks-ban kéne írni egy nagyon alap programot, aki esetleg tudna segíteni és van egy 15 perce dobhatna egy PÜ-t.
Köszi!
-
mgoogyi
senior tag
válasz
Ron Swanson #4174 üzenetére
Rendezésből a buborékrendezést szokták elsőnek tanítani, de az O(n^2)-es, nem leszel vele előrébb.
Ez a sort(...) gyorsrendezést használ, nyugodtan használd.
A feladat megoldását meg nem tanultad órán, azt magadnak kéne kitalálnod, ezzel fejlődsz.
Értsd meg a beszúrt kódot, próbálgasd. Ha azt érted az utolsó betűig, meg tudod majd oldani a saját feladatod is. -
-
mgoogyi
senior tag
válasz
Ron Swanson #4172 üzenetére
Melyik része nem sikerül?
A megértés?Amit linkelt Drizzt fórumtárs, az pont ezt oldja meg:
#include<iostream>
#include<algorithm>
using namespace std;
void findMaxGuests(int arrl[], int exit[], int n)
{
// Sort arrival and exit arrays
sort(arrl, arrl+n);
sort(exit, exit+n);
// guests_in indicates number of guests at a time
int guests_in = 1, max_guests = 1, time = arrl[0];
int i = 1, j = 0;
// Similar to merge in merge sort to process
// all events in sorted order
while (i < n && j < n)
{
// If next event in sorted order is arrival,
// increment count of guests
if (arrl[i] <= exit[j])
{
guests_in++;
// Update max_guests if needed
if (guests_in > max_guests)
{
max_guests = guests_in;
time = arrl[i];
}
i++; //increment index of arrival array
}
else // If event is exit, decrement count
{ // of guests.
guests_in--;
j++;
}
}
cout << "Maximum Number of Guests = " << max_guests
<< " at time " << time;
}Az
int arrl[]
az érkezési időpontok tömbje, aint exit[]
pedig a távozási időpontok tömbbje.Ez rendezi le neked ezt a két tömböt gyorsrendezéssel O(N*logN) időben:
sort(arrl, arrl+n);
sort(exit, exit+n);A while ciklus pedig végigmegy a két tömbbön úgy, hogy hol az egyiket lépteti, hol a másikat.
Az"i" az érkezés indexe, a "j" a távozásé.Annyi, hogy ennek a programnak a kimenete az, hogy melyik időpontban voltak a legtöbben és nem az, hogy melyik vendég találkozott a legtöbb másikkal, de a két probléma technikailag szinte azonos.
Ha valami nem világos, kérdezz.
Az eredeti kódoddal a legfőbb baj, hogy volt benne egy egymásba ágyazott for ciklus pár, ami N darab vendég esetén N*N-nel arányos mennyiségű műveletet végez. Ezt hívják O(n^2)-nek és emiatt van az, hogy nagy N-re már túl sok ideig fut a programod. Ugye N=10-nél a a valahány 100 művelet nem gáz, de N=1000-nél már valahány millióról beszélünk. -
válasz
Ron Swanson #4171 üzenetére
Próbálkozom, de nem sikerül
Vasárnapig meg kéne csinálnom, addig kell beadni. -
-
dabadab
titán
válasz
Ron Swanson #4165 üzenetére
"Kis mennyiségű adatnál szépen le is fut, de ha mondjuk N = több ezer, akkor nem fut le 0,2s alatt...
"
Ó, hát erre egyszerű a megoldás, a lista tetejéről válassz valamit: [link]
Komolyabbra fordítva a szót, az a gondod, hogy kb. a vendégek számának négyzetével nő az elvégzendő számítások mennyisége. A megoldás az, ha találsz ennél kisebb ordójú algoritmust. Első blikkre ilyen lehet az, ha a vendégeket nem direktben hasonlítod össze egymással, hanem az időintervallummal machinálsz.
Például csinálsz egy listát, amiben olyan elemek vannak, amik állnak egy időpontból, a már ott lévő vendégek számából és az abban az időpillanatban érkezett vendégek számából és simán ezen a listán mész végig minden egyes vendégre.
Ez egyébként továbbra is algoritmikus kérdés, nem C++ - specifikus.
Hogy ontopic legyek, a C++ kódod valami egészen rettenetes és elavult, szóval fogadni mernék, hogy ezt a magyar (felső)oktatás keretében tanultad
, szerintem azt is érdemes jobb átnézni:
1. TVendegek:
Minek az a T? Most komolyan? Mitől lesz bárkinek is jobb attól, hogy az összes osztály neve T-vel kezdődik, mint "type" (sőt, "típus"). Szóval legyen inkább Vendegek.
Miért Vendegek? Egyetlen vendég adatait tárolja, nem többét, szóval legyen inkább Vendeg.
És persze kódot szigorúan angolul írunk, szóval a végleges változat az a Guest.2. erkezes / tavozas
Ha már név: itt pont van értelme annak, hogy jelöljük, hogy ezek adattagok, szóval m_arrive, m_leave
Adattagokat csak kivételes esetben érdemes kirakni publikba, ez meg semmiképpen sem az, szóval legyenek csak private-ok (és a private tagokat érdemes a publicok mögé rakni, mert így jobban olvasható a kód: az elején ott van a mindenkit érdeklő rész, a class API-ja, az implementáció meg elfér hátul).3. TVendegek(const int E, const int T):
A constok itt elég feleslegesek (érték szerit átadott primitívekről van szó), a nevek meg lehetnek nyugodtan beszédesek, a C++-ban a scope-ok miatt az is tök jól működik, hogyC::C(int x) : x(x) {}
De mivel a tagok neve pont az előbb kapott egy m_ előtagot, amúgy se lenne névütközés legyen inkábbGuest(int arrive, int leave)
....
és most mennem kell, majd folytatom, addig a többiek úgyis belekötnek abba, amit írtam
-
Drizzt
nagyúr
válasz
Ron Swanson #4165 üzenetére
Szerintem itt van az idealis megoldas, a 3 kozul a kozepso. De elkepzelhetonek tartom teljesen mas megkozelitesek is hasonloan gyorsak lehetnek. [link]
A te megoldasod o(n2) - nek nez ki. -
mgoogyi
senior tag
válasz
Ron Swanson #4165 üzenetére
Pontos feladatleírás?
for (i = 1; i < vendegek.size(); i++) {
Itt 0-tól kéne indulni, az első vendég is lehet a megoldás.
A TVendegek osztályt átnevezném Vendeg-re, mert az egy darab vendég szerintem.A feltöltésnél add át a vektornak a ctor-ba a méretét, hogy a push_back-nél elkerüld az átméretezést.
Ha kevés benne a hely, újrafoglal magának helyet és másolgat. De várhatóan nem ezen múlik.A kódodnál viszont valszeg a dupla for ciklusnál lehet fogni sokat, az teszi négyzetessé a futási idejét a bemenet méretétől függően. Ez a feladat gyakorlatilag annyi, hogy melyik zárt intervallumnak van a legtöbb metszete a többivel.
Én valami olyasmit csinálnák, hogy rendezném a vendégeket érkezési sorrendben (/távozásiban ) és végigmennék rajtuk lineárisan és jegyezném, hogy most jött valaki, most elment, és azt nézném, hogy mikor voltak a legtöbben.
Oké, most esestt le. Nem kell a vendégeket rendezni, külön az érkezési idejüket egy tömbbe teszed, külön a távozásit és párhuzamosan haladsz a kettőn két külön indexszel. Ha a soron követő két szám között az érkezési <=, akkor növelsz a számlálón, ha meg nem, akkor csökkentesz. Ennek a számlálónak a maximumát keresed és egy vendéget, aki akkor ott volt.
Ez már elég erős tipp szerintem. Lényeg, hogy az egymásba ágyazott ciklusokkal nem fogod tudod megoldani elég gyorsan, csak lineárisan mehetsz végig a vendégek dolgain. -
Az előző problémát megoldottam, viszont most ismét szükségem lenne egy kis segítségre. (Ez már egy másik feladat.)
Van ez a kódom:
#include <iostream>
#include <vector>
class TVendegek
{
public:
int erkezes;
int tavozas;
TVendegek(const int E, const int T):
erkezes(E), tavozas(T) {}
const bool talalkoztak(const TVendegek & g) const;
const int tartozkodasiIdo() const {
return tavozas > erkezes;
}
};
const bool TVendegek::talalkoztak(const TVendegek & g) const
{
const TVendegek * a;
const TVendegek * b;
if (this->erkezes > g.erkezes) {
a = &g;
b = this;
} else {
a = this;
b = &g;
}
return (a->tavozas >= b->erkezes);
}
int main()
{
using namespace std;
int N, i, Ei, Ti;
vector<TVendegek> vendegek;
int max_index, max_darab, darab, j;
cin >> N;
for (i = 1; i <= N; i++) {
cin >> Ei >> Ti;
vendegek.push_back(TVendegek(Ei, Ti));
}
max_index = 0;
max_darab = 0;
for (i = 1; i < vendegek.size(); i++) {
darab = 0;
for (j = 0; j < vendegek.size(); j++) {
if (j != i) {
if (vendegek[i].talalkoztak(vendegek[j])) {
darab++;
}
}
}
if (max_darab < darab) {
max_darab = darab;
max_index = i;
}
}
cout << (max_index + 1) << endl;
cout << max_darab << endl;
return 0;
}A probléma pedig az, hogy a feladatnál meg van adva, hogy 0,2 másodperc az időlimit. Kis mennyiségű adatnál szépen le is fut, de ha mondjuk N = több ezer, akkor nem fut le 0,2s alatt...
-
EQMontoya
veterán
válasz
Ron Swanson #4163 üzenetére
Neked nem c++ kerdesed van, hanem algoritmikai, adatszerkezeti,
Eloszor is gondolkozz.
Tarolnod kellene valahol az orhelyeket. Mondjuk tombben, mert azt tudod indexelni.
Tehat beolvasol egy orseget (ami egy szam), azzal indexeled a tombot, igy oda be tudsz rakni egy orseget.Neked nem a
sorszam[I]
-be kell beolvasnod, hanem beolvasol egy intbe, es azzal indexeled a tombot.Utana meg kell talalnod, hogy hogyan lehet optimalisan lefedni az egeszet. Ehhez gondolkodni kell kicsit, de gondolkodni nem fogunk helyetted, a c++ reszeben segitunk szivesen.
-
Sziasztok!
Van egy feladat, amit nem tudok megoldani, és örülnék egy kis segítségnek.
Ez lenne a feladat: KÉPOdáig eljutottam, hogy megadtam a változókat és bekértem azokat:
#include <iostream>
using namespace std;
int main()
{
int orhelyekSzama;
int orsegekSzama;
cin >> orhelyekSzama;
cin >> orsegekSzama;
int sorszam[orhelyekSzama];
for(int i=1; i<orhelyekSzama; i++){
cin >> sorszam[i];
}
}Még csak a nagyon alapokat tanultuk: if else, for ciklus, tömbök. Szóval egyszerű feladat, de mégsem tudom folytatni
-
m.zmrzlina
senior tag
válasz
PandaMonium #4161 üzenetére
Köszönöm. Nem állítom hogy minden részletét értem de egy kicsit beljebb vagyok.
-
PandaMonium
őstag
válasz
m.zmrzlina #4159 üzenetére
Pl.
#include <iostream>
#include <vector>
#include <string>
template<typename T>
std::size_t sizeOfContainer(const T& container) {
return container.size();
}
int main()
{
std::vector<int> x = { 1, 2, 3 };
std::string y = "foobar";
std::cout << sizeOfContainer(x) << std::endl;
std::cout << sizeOfContainer(y) << std::endl;
return 0;
}Ez a kódrészlet nem működne a string-en, ha nem lenne size függvénye, külön template specializációt kéne rá írni. Egyébként ahogy már írták elsősorban azért van size() függvénye, hogy hasonlítson a containerek intefészére, elvégre a string csak egy karakter container (iterátorai is vannak).
-
doc
nagyúr
válasz
m.zmrzlina #4159 üzenetére
gondolom azert van size() hogy a tobbi containerrel interface-kompatibilis legyen, a length() meg azert, mert stringnel az logikus
-
m.zmrzlina
senior tag
A string osztálynak van két tagfüggvénye a size() és a .length()
Azt olvasom itt:
Both string::size and string::length are synonyms and return the same value.Kérdésem, hogy miért kell két teljesen azonos tagfüggvény?
-
mgoogyi
senior tag
válasz
Teasüti #4155 üzenetére
Amit lehet a stacken jobb tartani(gyorsabb, nem kell delete), a nagy méretű adatot meg heap-en(van neki hely gazdagon).
A new+delete párra meg vannak osztályok, amikbe becsomagolva megkapod az eltakarítást.
std::vector a dinamikus tömbhöz, std::unique_ptr, std::auto_ptr egyéb mutatóhoz.
Ezek az osztályok a delete-et úgy oldják meg, hogy a destruktorukban meghívódik az általuk tárolt pointerre a delete.
És ezeket a pointer "wrapper"-eket pedig stack-en tartod valahol és amikor elhagyod a scope-ot, szépen lefut a destruktor és magától felszabadul a memória.
Ez azért nagyon fontos, mert minden programozó hibázik és nem igazán függ a hibázás gyakorisága attól, hogy mióta űzöd a mesterséget. Ezzel védjük magunkat a memory leak-től.A vector persze elsődlegesen nem pointer wrapper, arra találták ki, hogy nagyon kényelmesen legyen egy bármikor átméretezhető tömböd. A belsejében egy dinamikus tömb van.
-
jattila48
aktív tag
válasz
Teasüti #4153 üzenetére
"Tehát ami nekem átjött ebből a beszélgetésből, hogy ha new operátorral hozok létre tömböt (foglalok le dinamikus memóriát), akkor az egy ún. heap-re kerül,..."
Ez igaz.
"...míg ha new nélkül, akkor a stack-be."
Ez nem feltétlenül igaz, mert a globális adatterületen is deklarálhatsz tömböt.
Egyéb gyakorlati jelentősége pedig az, amit eddig leírtam. Röviden összefoglalva:
- A tömb név nem változó, nem adhatsz neki értéket, és nem képezheted a címét.
-A pointer változó, ami memória címet tartalmaz (pl. a heapen lefoglalt memória címét, de lehet más pl. "hagyományosan" deklarált tömb címe is). A pointer értéke megváltoztatható, és a címe is képezhető.
-Tömböt csak konstans méretűt deklarálhatsz (kivéve C99), míg new-val változó méretű memóriát foglalhatsz.
-Tömböt nem szabad felszabadítani, new-val létrehozott memóriát pedig fel kell szabadítani.
Kb. ennyi ami gyakorlatban különbség a két fogalom között, és amiről minden programozónak tudnia kell.
Még egy "apróság": C++ -ban tömb név, mint konstans pointer lehet template argumentum (mivel fordítási időben kiértékelhető), pointer viszont nem (mivel csak futási időben értékelhető ki). -
Teasüti
nagyúr
Tehát ami nekem átjött ebből a beszélgetésből, hogy ha new operátorral hozok létre tömböt (foglalok le dinamikus memóriát), akkor az egy ún. heap-re kerül, míg ha new nélkül, akkor a stack-be.
Ez így korrekt? Van egyéb gyakorlati jelentősége?
Köszönöm! -
jattila48
aktív tag
válasz
jattila48 #4149 üzenetére
Elnézést, a const int valóban olyan "változó", aminek nem lehet értéket adni. A static const int-re gondoltam, erre már áll az amit eddig írtam. Template argumentumként és tömb méretként is static const int használható, const int nem. Amiket a tömb vs. pointer témában írtam, azt fenntartom.
-
jattila48
aktív tag
válasz
mgoogyi #4148 üzenetére
Ahogy írtam, a const int kezelése esetleg lehet fordító és helyzet függő, pl. a példa programodban képezhető a címe (bár sok értelme nincs, mivel értéket nem adhatsz neki). De amiket példákat írtam (template argumentum, tömb méret), valószínűleg az értékét mint konstanst fogja használni, hiszen fordításkor még semmilyen memória címet nem tulajdoníthat neki. Értékadásnál esetleg lehet más a helyzet, hiszen az értékadás futás időben történik, és ott hivatkozhat a konstansra a memória címén keresztül (sok értelme ennek sem lenne, esetleg gyorsabb lehet az újra fordítás, ha megváltoztatod a forráskódban a konstans értékét. Ez csak tipp).
A #define egy más kérdés, az pusztán szövegfeldolgozás. Ott tényleg semmi különbség nem lehet ahhoz képest, mintha a konstans literált írtad volna minden helyen.
Kicsit elkanyarodtunk a témától. A const int-et és enum-ot csak a tömb mint konstans cím hasonlósága miatt hoztam fel. Eredetileg arra válaszoltam, hogy a tömb nem pointer, még ha sokszor hasonlóan is kezeljük. A különbség gyakorlatban is fontos vonatkozására is felhívtam a figyelmet, amit minden programozónak tudni kell. A technikai különbségek (mi hogy fordul, mennyire hatékony) valóban nem életbe vágók, de érdemes tudni róluk. -
mgoogyi
senior tag
válasz
jattila48 #4146 üzenetére
Ezzel nem mondtál semmi újat. A gyakorlati jelentőség = hogyan használod a kódban.
Évekig dolgoztam c++-ban, csak a saját gyakorlati nevezéktanomban változónak hívom a konstansokat is (legalábbis a const int-eket pl). Viszont a #define-olt cuccokat viszont konstansnak hívom.
A const int nekem egy olyan változó, amin nem tehetek meg tetszőleges műveletet.És szerintem a kódodtól függ, hogy minden tekintetben konstans lesz vagy sem.
Ugyanis a kódodhoz hozzácsapva azt, hogy&harom
simán megy, kiírathatod, és így már igazi változód lesz.A const-ot egy optimalizációs tippnek tekintem a fordító számára.
Ez nyilván péklapáttal tarkónbaszós kód, de példának jó.
-
jattila48
aktív tag
válasz
mgoogyi #4144 üzenetére
Nem, nem csak nevezéktanról, hanem lényeges különbségről van szó. A
const int harom=3;
kódban a harom semmilyen módon nem változó, mert a lefordított kódban nem a memóriában elfoglalt címe alapján fognak rá hivatkozni, hanem pl. egy értékadó utasításban konkrétan befordítják a 3 konstans értéket:x=harom;
lefordítva valahogy így fog kinezni:lea eax,DWORD PTR[ebp-12] ;x cime az eax regiszterbe kerul
mov DWORD PTR[eax],3 ;x a 3 konstanst kapja ertekul. a 3 itt jelenik meg a kodbanharom nevu valtozo pedig sehol nincs.Amit angolul idéztél, szerintem kissé értelem zavaró, mert valóban olyan változóként (mintha memóriában el lenne tárolva) hivatkozik rá, aminek az értékét nem lehet megváltoztatni. Ez szerintem nem így van (bár talán lehet fordító függő), annál is inkább, hogy a const int-ek és enumok lehetnek template argumentumok, amiket a fordító egész biztos konstans int-ként fog értelmezni mikor a template-et példányosítja. Sőt a tömb konstans mérete is lehet const int, vagy enum. Mikor a fordító a stack-en (vagy globális adatterületen)" lefoglalja" a megfelelő méretű memóriát a tömb számára, ott konkréten az adott konstans számszerű értékét fogja használni, nem pedig holmi memória címből képzett indirekt hivatkozást.
-
jattila48
aktív tag
válasz
mgoogyi #4142 üzenetére
"Pont nem érdekel, nem látom a gyakorlati jelentőségét"
Pl. az lehet a gyakorlati jelentősége, hogy innen már világos, hogy a C/C++ -ban miért nem lehet dinamikus méretű tömböt deklarálni (bár mint most megtudtam, újabb C szabvány szerint lehet):
int n=10;
int a[n]; //hiba. tomb meret csak konstans lehetEzt kezdők általában nem szokták érteni.
Ha az új C szabvány ezt mégis megengedi, akkor a tömb címe szükségképpen eltárolódik a memóriában (mintha változó lenne), de a fordító nem engedi meg a megváltoztatását és a címének képzését (gondolom így van, de nem ismerem a C-nek ezt a lehetőségét).
Másik gyakorlatban fontos vonatkozása a dolognak, hogy a dinamikusan allokált memóriát fel kell szabadítanod (ha nem akarsz memory leaket), a tömböt pedig nem kell (sőt nem szabad!) felszabadítani (hiszen nem a heapen lett lefoglalva). Tekintsük a következő kódrészletet:int tomb[10];
int *dinamik_tomb=new int[10];
int *pointer;
pointer=tomb;
delete[] pointer; //hiba! nem szabad felszabaditani a tomb-ot
pointer=dinamik_tomb;
delete[] pointer; //OK, fel kell szabaditani a dinamik_tombotAmint látod, a pointer felszabadításánál észnél kell lenni, tudni kell, hogy tömb, vagy dinamikusan allokált memória terület címét tartalmazza-e. Ebből bizony sok hiba adódik (jó párat láttam már), és megy a fejvakarás, hogy miért száll el a program, hiszen a "tomb valójában pointer". Hát nem!
-
mgoogyi
senior tag
válasz
jattila48 #4143 üzenetére
Ok, főleg nevezéktanról beszélgetünk gyakorlatilag.
Én abból indulok ki, ahogy angolul hívni szoktunk dolgokat. Magyar szakirodalmat csak egyetemen olvastam utoljára kb.[https://msdn.microsoft.com/hu-hu/library/07x6b05d.aspx?f=255&MSPPError=-2147217396]
Pl:
"The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it."" you must declare your const variable as"
const int harom=3;
Szóval ez itt nekem egy konstants változó. Hülyén hangzik valóban.
-
jattila48
aktív tag
válasz
mgoogyi #4142 üzenetére
Nevezheted tömbnek a dinamikusan allokált memória területet, de az nem tömb abban az értelemben (konstans mérettel deklarált tömb), ahogy írtam. A különbséget nem írom le még egyszer.
"Pusztán ránézve a kódra én "a"-ra és "b"-re is változóként(előbbire pointer típusú változóként, utóbbira tömb típusúként) fogok hivatkozni."
b nem változó, hiszen nem változhat az értéke, mint ahogy egy változónál (a nevében is benne van) ez megtörténhet. Ennyi erővel a 3-at is nevezheted változónak, holott az sincs sehol a memóriában eltárolva. A tömb esetében kicsit azért kevésbé nyilvánvaló, hogy nem változó, hanem konstans, mert nevet adsz neki. A 3 leírva konstans literál, ezért nyilvánvalóbb hogy ő nem változó. Azonban írhatsz olyat, hogyconst int harom=3;
enum akarmi={nulla,egy,ketto};
ahol a névvel illetett számok szintén konstansok, nem lehet sem megváltoztatni az értéküket, sem a címüket képezni. A tömb ugyanilyen értelemben konstans. Ennek a látszat ellenére igenis van gyakorlati jelentősége, és illik is tudni róla. Csak erre szerettem volna felhívni a figyelmet -
mgoogyi
senior tag
válasz
jattila48 #4141 üzenetére
"Nem, nem lehet a heapen tömb. Az nem tömb lesz, hanem dinamikusan foglalt memória"
Lehet én vagyok a retardált, de nekem a tömb = összefüggő memóriaterület egy adott típusra.
Szóval nekem van olyan, hogy statikusan allokált array és dinamikusan allokált array.https://msdn.microsoft.com/hu-hu/library/kewsb8ba.aspx?f=255&MSPPError=-2147217396
Az msdn meg le mer írni ilyet, hogy "When allocating an array using the new operator"?
"Ahogy írtam, a t NEM változó, hanem konstans és ez a lényeg."
int * a = new int[10];
int b[10];Pusztán ránézve a kódra én "a"-ra és "b"-re is változóként(előbbire pointer típusú változóként, utóbbira tömb típusúként) fogok hivatkozni. Utóbbi konstans és nincs mögötte valódi változó? Pont nem érdekel, nem látom a gyakorlati jelentőségét. Lehet ez rossz berögzültség, soha egyszer nem volt még hátrányom belőle a munkám során.
-
jattila48
aktív tag
válasz
mgoogyi #4140 üzenetére
Attól tartok, teljesen félreérted.
"...én a t-re gondolok, mint változóra"
Ahogy írtam, a t NEM változó, hanem konstans és ez a lényeg. Ha azt írod, hogyint i=j+3;
akkor az i és j változók, amik a memóriában futás időben keletkeznek, a 3 viszont konstans, ami sehol nem tárolódik el e memóriában, hanem a generált kódban jelenik meg mint konstans adat. Hasonlóan a tömb esetén is, sehol nem tárolódik a tömb (mint cím) értéke, hiszen csak egy konstans.
"Az a konstans cím, amiről beszélsz, az maga a t változó tartalma"
Nincs semmiféle t változó.
"Annyit tud egy pointerhez képest, hogy a típusából kifolyólag tud arról, hogy hány elemű"
Nem, nem tud róla hogy hány elemű, hiszen a konstansban ez nincs kódolva. C-ben egyébként sincs tömb index ellenőrzés (futás közben), és a fordító sem különböztet meg ez alapján típusokat (template-tel megoldható, ha a tömb méret template argumentum).
"nem pointer, de mégis pontosan ugyanúgy viselkedik"
Nem pontosan úgy viselkedik, ahogy előző hozzászólásomban írtam, nem adható neki érték, és nem képezhető a címe (szemben a pointerrel).
"Másrészt nem csak a stacken lehet a tömbünk, hanem a heapen is"
Nem, nem lehet a heapen tömb. Az nem tömb lesz, hanem dinamikusan foglalt memória, aminek a címe bekerül egy változóba (vagyis pointer), bár valóban kezelheted tömb szintaxissal, ha az elemeit akarod elérni. Tömböt deklarálni a stack-en lehet, vagy a globális adatterületen (amit a betöltő foglal le a memóriában).
"Egyébként aki most ismerkedik a C++-szal, annak lehet inkább riasztó, mint segítség."
A C++ nem egy egyszerű nyelv, és szerintem jó az elején tisztázni bizonyos dolgokat (pl. ezt), hogy később ne rögzüljön hibásan, mint ahogy az esetedben is. -
mgoogyi
senior tag
válasz
jattila48 #4139 üzenetére
Ja értem, hogy mire gondolsz, én gyakorlatiasabban közelítem a kérdést.
int t[10] esetén a t a gyakorlatban úgy viselkedik, mint egy konstans pointer. Amikor a tömbről beszélek a kódban, akkor én a t-re gondolok, mint változóra, márpedig ez pontosan a 0. elem címe.
Az a konstans cím, amiről beszélsz, az maga a t változó tartalma. Annyit tud egy pointerhez képest, hogy a típusából kifolyólag tud arról, hogy hány elemű, azaz nem int * hanem int[10] típusú. De ettől még értékként a 0. elem címe van benne. És igen, valóban nem pointer, de mégis pontosan ugyanúgy viselkedik.Másrészt nem csak a stacken lehet a tömbünk, hanem a heapen is new-val foglalva, akkor meg direktbe egy int *-ba toljuk be a 0. elem címét és azzal a pointerrel is pont azt fogod csinálni, mint a stack-en foglalt t-vel.
Az assemblys részt elolvasom megint, amit írtál, abban nem vagyok otthon. Egyetemen meglehetősen félvállról vettem, így ennyi is maradt meg belőle. Egyébként aki most ismerkedik a C++-szal, annak lehet inkább riasztó, mint segítség.
-
jattila48
aktív tag
válasz
Teasüti #4135 üzenetére
"De hisz a tömb is egy pointer.
"
Nem, nem az! C-ben valóban hasonlóan kezelheted a tömböt és a pointert, de ettől még a tömb nem pointer. Sok félreértés és hiba forrása ez, ugyanakkor nagyon kényelmes is tud lenni. A pointer egy változó, ami történetesen memória címet tartalmaz. Mint minden változónak, neki is van címe, és megváltoztathatod az értékét (balérték). Ezzel szemben a tömb egy konstans memória cím (ahol a tönb kezdődik). Ezt a konstanst a fordító/linker/betöltő számolja ki, amit te nem változtathatsz meg, és a címét sem képezheted (hiszen nem is létezik a memóriában).
int tomb[10];
tomb=new int[10]; //Hiba! tombnek nem lehet erteket adni, hiszen az konstans
int **ppi=&tomb; //Hiba! tombnek nem kepezheto a cime, mert az nem valtozo
int *pi=new int[10]; //OK
int **ppi=π //OK valtozonak kepezheto a cime
pi=new int[10]; //OK valtozo erteke megvaltoztathatoAmikor tömb elemre hivatkozol (kiindexeled), a fordító ehhez a konstans címhez adja hozzá az indexet, és erről a címről veszi elő a tömb elemet (intelnél egyetlen utasítás pl. : mov eax, DWORD PTR[ebx+0x1000]; indirekt indexelt címzési mód, ahol 0x1000-nél kezdődik a tömb, ebx-ben pedig az elérni kívánt tömbelem indexe található). Tehát itt a kódba a fordító beleírja a tömb konstans kezdőcímét.
Ha new-val foglalsz helyet, akkor a lefoglalt memória kezdőcímét egy változó kapja értékül, ez a változó a pointer. Ha ezen a memória területen tömb szintaxissal hivatkozol egy elemre, akkor a fordítónak (intel esetén) ehhez legalább két utasításra lesz szüksége. Az elsővel regiszterbe tölti a változó (pointer) címéről a változó értékét (ez maga a new-val foglalt memória kezdőcíme lesz). Ha pl. a pointered címe eax-ben van, akkor mov eax,DWORD PTR[eax] utasítás ezt megoldja. Majd az elem elérése mov eax,DWORD PTR[eax+esi] utasítással történik, ahol az esi tartalmazza azi indexet. Látható, hogy ez jóval lassabb művelet, mint az "igazi" tömb kiindexelése. -
mgoogyi
senior tag
válasz
Teasüti #4135 üzenetére
Igen, így van, a tömböt is pointerként kezeled. Gyakorlatilag a 0. elemére mutató pointer van a változóban értékként.
A kérdésedre a válasz igen, mindig más memóriaterületen kapsz egy új összefüggő memóriaterületet az új tömbödnek. A pointert írasd ki és látod, hogy mindig más értéket kap. Ez a logikai címe a kezdeti memóriacellának (a programod csak a memória egy számára logikailag elkülönített részét látja).
A régi tömb ugyanúgy meglesz az előző ciklusodból, csak a címe már nem lesz meg és anélkül nehéz felszabadítani.
Csináld ciklus belsejében simán, amit írtál. Ha jó sok kört fut a ciklusod, megzabálja a géped memóriáját.
Azért figyelj arra, hogy ne zabálja meg az összeset, kevés elemű int tömböt foglalj le 1000-szer ciklusban, kísérletnek elég. -
Teasüti
nagyúr
válasz
mgoogyi #4134 üzenetére
A new (new []) esetében egy pointer-t kapsz vissza
De hisz a tömb is egy pointer.Ha ezeket nem használod és elfelejteted a delete-et, akkor keresheted, hogy miért növekszik a progid memóriahasználata (memóriaszivárgás).
Mi van akkor, ha egy függvény minden lefutáskor létrehoz egy tömböt és elfelejtem törölni miután lefutott, majd újra meghívom a függvényt? Más memóriaterületen fogja megint létrehozni ugyanazt a tömböt?(#4133) dabadab
Áhhá!! Értem.
Ezt mintha olvastam is volna, hogy adott esetben egy szinttel feljebb szokták törölni, mondjuk az adott függvényen kívül. -
mgoogyi
senior tag
válasz
Teasüti #4132 üzenetére
A new meg nem new között az a különbség, hogy a new-val a heap-en foglalsz memóriát, new nélkül meg a stack-en. (itt nem erre a nem szabványos dologra gondolok:
int p [I]= {};
)
Ez utóbbi elég limitált tud lenni, ha majd egyszer írsz rekurzív(önmagát hívó) függvényt, belefuthatsz.
Ezt hívják stackoverflow-nak. Olvass utána, hogy mi az a heap és mi az a stack.
Egyébként paraméterezett méretű tömböt new nélkül nehéz lértehozni.A new (new []) esetében egy pointer-t kapsz vissza és a te feladatod ezt eltakarítani delete-tel ( delete []).
Azért, hogy ezt ne felejtsd el, javasolt olyan osztályokat használni, amik megteszik ezt helyetted.
A vector meghívja helyetted a new[]-t és a delete[]-t, menet közben át is méretezi a benne lévő array-t.
Kényelmessé és biztonságossá teszi a tömbkezelést.
A unique_ptr pedig általánosságban jó arra, hogy egy objektum felszabadításával ne kelljen foglalkozni.Ha ezeket nem használod és elfelejteted a delete-et, akkor keresheted, hogy miért növekszik a progid memóriahasználata (memóriaszivárgás).
-
dabadab
titán
válasz
Teasüti #4132 üzenetére
"Még sose alkalmaztam new-t. Mi szükségem volna rá, ha meg tudom oldani lokális változókkal?"
Ha meg tudod oldani, akkor semmi
Akkor van rá szükséged, ha nem tudod megoldani lokális változókkal (pl mert azt a p[] tömböt visszatérési értékként akarod használni a függvényedben).
-
dobragab
addikt
Az, hogy a masodik kodreszlet nem szabvanyos, csak C-ben, C99-tol, C++-ban sose volt az. Egyebkent a neve Variable Length Array.
Az elsovel pedig az a baj, hogy a
delete[]
-et konnyu elfelejteni (vagy nem figyelni valami aprosagra, ami miatt nem fut le, hiaba irtad ki, pl.return
vagy kivetel), sulyos hibaforras.Hasznalj helyette
std::vector
-t, esetleg teddstd::unique_ptr
-be, ha a vector tul "nagy" (arduino-n nem tudom mik vannak). -
Teasüti
nagyúr
Sziasztok!
Volna egy kezdő kérdésem, tudnátok segíteni kérlek?
Köszi! -
xors
senior tag
válasz
Headless #4127 üzenetére
a char[32], az ugyanúgy egy char* mutató, csak foglalva van hozzá 32db hely a memóriában.
A méret igazából csalóka mert lehet röviebb is mint a lefoglalt, stringek esetén az utolsó karakter utáni lezáró nulla ('\0') jelzi a végét, a strcmp is ezt használja.
A hiba arra utal, hogy valamiért a strcmp ki van kapcsolva, esetleg próbáld meg az#include <cstring>
std::strcmp(egyik, masik)ha így sem megy, akkor kell írni egy összehasonlító függvényt, az nem egy nagy cucc
int myStrCmp (const char *s1, const char *s2) {
const unsigned char *p1 = (const unsigned char *)s1;
const unsigned char *p2 = (const unsigned char *)s2;
while (*p1 != '\0') {
if (*p2 == '\0') return 1;
if (*p2 > *p1) return -1;
if (*p1 > *p2) return 1;
p1++;
p2++;
}
if (*p2 != '\0') return -1;
return 0;
} -
Headless
őstag
-
Z_A_P
addikt
-
xors
senior tag
válasz
Headless #4124 üzenetére
char* összehasonlításra ott a strcmp(const char* egyik, const char* masik) függvény. Ez tulajdonképpen a C string.
A tömböd jó úgy ahogy csináltad, const char* paramNames[4] = {//elemek}
Természetesen a char* -ok tömbjét (paramNames) végig kell nézned egyesével egy for ciklussal.Én ilyesmit csinálnék:
#include <string.h> //a strcmp -hez kell
for(int i = 0; i< 4; i++)
if(strcmp(name, paramNames[i])
//itt azt csinálsz amit akarsz velük, ekkor egyeznek megremélem tudtam segíteni
-
Headless
őstag
válasz
Headless #4123 üzenetére
A korábbi gondom megoldódott, viszont most inkább felétek való kérdésem lenne.
van egy karakter tömböm
char name[32]
nem én csináltam ez van megadva
és van egy (ezt úgy módosíthatom ahogy akarom)
const char *paramNames[4]={"ConPosX_1","ConPosY_1","ConPosX_2","ConPosY_2"};
tömböm és össze kellene hasonlítani a kettőt ha megegyezik, akkor kéne vele csinálnom valamit.
Namár most ha így szimplán if-be rakom őket nem fog megegyezni.
if(name==paramNames[i])
Próbáltam hogy a tömbömet valami olyasmi formában hozom létre, hogy
char paramNames[4][32];
paramNames[0]="ConPosX_1";csak így meg nem tudja a char [10]-et char[32]-be alakítani. Hogy kellene ezt helyesen megoldani?
Hú de el vagyok veszve itt a string/char, mutató tömbökkel sajnos ost jön elő, hogy nem vagyok képben ezekkel, próbáltam keresgélni, de sajnos nem találtam megfelelő megoldást.
-
Headless
őstag
válasz
dabadab #4122 üzenetére
Köszönöm a gyors választ.
Ahogy az kitalálható volt a definicióból ez egy API részlet, tehát fő programba nem tudok belenyúlni. Ezt kell használni, közben megtaláltam az API-ban azt a funkciót ami a paraméterek információit tartalmazza így meglett ez a probléma, de valahogy olyan mintha nem tudnám kiolvasni a 0-án kívüli elemeket. De valószínű ezzel már egy inkább specifikus fórumban kéne feltennem a kérdést.
-
dabadab
titán
válasz
Headless #4121 üzenetére
"hogyan tudom kiolvasni, hogy hány paraméterrel rendelkezik?"
Sehogy. Alapvetően két dolgot tudsz csinálni:
1. valahogy átadod a pointertömb mellé azt is, hogy hány eleme van
2. (és ez a javasolt) hagyod a C-s tömbökét és C++-ban C++-ban programozol, ami jelen esetben azt jelenti, hogy az STL konténerei közül használsz valamit, pl. vectort. -
Headless
őstag
Sziasztok!
Viszonylag új vagyok a c++ programozásban és biztos, hogy nem a helyes úton járok annak megtanulásában/értésében. De most ezt dobta a gép, van egy struktúrám amibe pointerek és dupla pointerek vannak. azt szeretném kérdezni, hogy hogy tudnám megtudni a dupla pointerek nagyságát, hogy egy for ciklussal végig mehessek rajtuk?
typedef struct {
...
API_AddParType **params;
...
} API_ElementMemo
typedef struct {
...
char name[API_NameLen];
....
} API_AddParType;tehát ami most megy
memo.params[0]->name
tehát a 0. paraméter nevét kiadja. hogyan tudom kiolvasni, hogy hány paraméterrel rendelkezik?
-
Dinter
addikt
Valaki tudna segíteni, hogy miért kétszer olvas be ez a függvény?
bool beolvas(){
String nev;
int letszam;
String str1;
String str2;
int adat;
int konstr; //csapat típusa
std::ifstream in("adatok.txt");
while((in>>konstr)){
cout<<"KONST:"<<konstr<<endl;
switch(konstr){
case 1:{
in>>nev;
in>>letszam;
in>>str1;
in>>str2;
Focicsapat* uj= new Focicsapat(nev, letszam, str1, str2);
hozzaad(uj);
break;
}
case 2:{
in>>nev;
in>>letszam;
in>>adat;
Kezicsapat* uj= new Kezicsapat(nev, letszam, adat);
hozzaad(uj);
break;
}
case 3:{
in>>nev;
in>>letszam;
in>>adat;
Kosarcsapat* uj= new Kosarcsapat(nev, letszam, adat);
hozzaad(uj);
break;
}
default:
break;
}
}
in.close();
return true;
}Input:
1 BME Foci 22 Egyik Edzo Masik Edzo
2 BME Kezi 15 2000000
3 BME Kosar 11 8 -
xors
senior tag
válasz
EQMontoya #4115 üzenetére
Igen, erre én is gondoltam, csak az zavart meg, hogy a típusnév(), ugye konstruktor hívás, aminek nincs visszatérési értéke alapból.
De azt értem , hogy kell valami default érték, amit ugye majd a sablon fog adni, és a default konstruktor pedig valamit létre tud hozni. -
xors
senior tag
Sziasztok!
Valaki el tudná nekem mondani, hogy ennél a konstuktornál (generikus tömbhöz van), miért fontos a "T()" ?template<class T, size_t maxsiz = 6>
class Array {
size_t siz; // adatok tényleges mennyisége
T t[maxsiz]; // elemek tömbje
public:
/// default konstruktor
explicit Array(size_t n = 0, const T& value = T() ) : siz(0) {
while (siz < n && siz < maxsiz)
t[siz++] = value;
}
}; -
Dinter
addikt
Valaki tudna segíteni, hogy ebben miért van memóriaszivárgás? [link]
Tuti, hogy a ListaElem-ek azok, viszont amikor törölni akarnám őket, azt írja, hogy "nem létező adat felszabadítása".
-
dobragab
addikt
válasz
Ereshkigal #4110 üzenetére
Én is erre próbáltam utalni, csak finomabban
-
dobragab
addikt
válasz
EQMontoya #4103 üzenetére
Egyébként ezt is meg lehet csinálni, azért élőben is szoktad látni a próbálkozásaimat
Annyi a lényeg, hogy a szüzet a másik irányból kell támadni. (Mármint a legelvadultabb C++ kiskapukat kell keresgélni és abuse-olni.) Ami szar meló, sok munka van vele, és sose lesz az igazi
-
jattila48
aktív tag
válasz
EQMontoya #4106 üzenetére
Melyik ostoba hozzászólásomra gondoltál? Amiben annak minősítettem, hogy szerinted 2018-ban a bináris api fv.-eknek C++ template-eket kéne tudni értelmezni? Ha az szerinted nem volt ostobaság, az baj.
A másik, hogy nincs azzal baj, ha api fv.-eket akarok objektum orientált módon használni, az miért ostobaság? Ilyen simán előfordulhat. Az, hogy te még nem találkoztál ilyennel, nem jelent semmit. -
jattila48
aktív tag
válasz
dobragab #4087 üzenetére
Köszi szépen a válaszodat. Először is engedd meg, hogy egy hibát javítsak:
static RET fptr_handler(ARGS... args)
{
tl_function(std::forward<ARGS>(args)...);
}helyesen:
static RET fptr_handler(ARGS... args)
{
return tl_function(std::forward<ARGS>(args)...);
}Egyébként szép megoldás a problémára.
Lényegében hasonló, mint amit a szimulációban írtam. Ott globálisan hoztam létre az objektumokat, ezek tfv.-eit pedig free wrapper fv.-eken keresztül hívtam meg (amik a globális objektumokhoz hozzáférnek), és a free fv.-ekre mutató fv. pointert tudom aztán használni callback fv. pointerként.
Lényegében a te megoldásod is hasonló, csak nem globális, hanem (thread_local) static std::function objecteket hozol létre (tl_function), amik tartalmazzák az objektum címét (ez a lambdában kapturált argumentum), és a megfelelő tfv. pointert. Majd ezt a tl_function std::function objectet meghívó fptr_handler statikus wrapper tfv.-nek a címét (mint közönséges pattintott C fv. pointert) adod vissza. A trükk pedig az, hogy a to_fptr function template második argumentuma egy []{} dummy lambda, aminek a típusa mindíg (fordító által generált) egyedi típus, ezért a to_fptr_t class template minden egyes alkalomkor külön-külön példányosul (a dummy lambda aktuális típusával), minden egyes function object-re külön osztályt, és azzal külön fptr_handler fv.-t létrehozva. Szép megoldás, gratula! -
jattila48
aktív tag
válasz
PandaMonium #4086 üzenetére
Szerintem meg azt sem érted, hogy pontosan miről is van szó. target-tel nem fv. pointert kapsz vissza, hanem annak az objektumnak a címét, amit az std::function-ban eltároltál (ha ez történetesen fv. pointer volt akkor azt, ha std::bind volt akkor azt). A target template argumentumában pontosan meg kell adni az std::function-ben eltárolt callable object típusát, különben NULL-t kapsz vissza ([link] . Lambdát ugyan lehet megfelelő fv. pointerré konvertálni, de csak akkor ha nem kapturál semmit (ez számomra érdektelen). Szóval előbb olvass, értelmezz és ne az észt oszd!
Új hozzászólás Aktív témák
● ha kódot szúrsz be, használd a PROGRAMKÓD formázási funkciót!
- HP Spectre x360 Érintős Hajtogatós Laptop Tab 16" -60% i7-1360P 32/2TB Intel Arc A370M 4GB UHD OLED
- Szép! Lenovo Thinkpad T14s G2 Üzleti "Golyóálló" Laptop 14" -60% i5-1135G7 4Mag 16GB /512GB FHD IPS
- Samsung Q80T 55" QLED - 4K 120Hz VRR / FreeSync / HDMI 2.1
- ÚJ HP ENVY 17 Nagyképernyős "Kis Gamer" Laptop -45% 17,3" Brutál i7-13700H 16/1TB Iris Xe FHD IPS
- Legion Go 8APU1
- Dell D6000 univerzális dokkoló USB-C/ USB-A, DisplayLink & Dell WD15 (K17A) USB-C + 130-180W töltő
- Bomba ár! HP EliteBook 840 G2 - i5-5GEN I 8GB I 256GB SSD I 14" HD+ I Cam I W10 I Garancia!
- Részletfizetés , Acer Nitro V 15 minimálisan használt uj állapot sok garancia
- Telefon felváráslás!! Xiaomi Redmi Note 11, Xiaomi Redmi Note 11 Pro, Xiaomi 11 Lite
- Azonnali készpénzes Intel i3 i5 i7 i9 12/13/14 gen processzor felvásárlás személyesen / csomagküldés
Állásajánlatok
Cég: CAMERA-PRO Hungary Kft
Város: Budapest
Cég: Promenade Publishing House Kft.
Város: Budapest