C++ Builder przekazanie argumentu do funkcji

0

Próbuje przekazać argument typu int do funkcji:

Fragment konstruktora Form1:

  for(int i=0,j=0; i<5; ++i)
 {
    for(int g=0; g<5; ++g,++j)
    {
      (...)
      loadvalues(tab[j],j);
    }
 }

Fragment funkcji:

void _fastcall TForm1::loadvalues(klasa tablica,int tag)
 {
     string path="VALUES/",number;
     path+=IntToStr(tag).c_str();            
     path+=".txt";
 }

wywołuje błąd: EConvert error: "" is not valid ineger value.

Dlaczego tak się dzieje i w jaki sposób mogę to naprawić?

0

Na pewno to cały kod? Bo w tej sytuacji przekazanie zmiennej tablica do funkcji jest zbędne, ponieważ nie będzie nigdzie wykorzystywana.

Po drugie jakich stringów używasz? Tych z VCL'a? Bo coś mi tu nie gra. Przecież w C++ Builderze masz String a nie string i przy tym pierwszym nie musisz dawać .c_str().

Po trzecie zobacz w debuggerze jakie masz wartości zmiennych i będzie wiadomo co jest przyczyną błędu.

0
void _fastcall TForm1::loadvalues(klasa tablica,int tag)
  {
   String path=String::Format("VALUES/%d.txt", ARRAYOFCONST((tag)));
  }
  1. W pokazanym kodzie żadnego napisu nie konwertujesz na Int'a więc błąd nie jest w pokazanym kodzie.
0

Wrzucam wszystko w takim razie, byłem pewien że gdzieś tam jest błąd.

__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
string path,number;
limit=0,last=-1,count=0;
Button1->Visible=0;
Label1->Visible=0;
Button1->Caption="Start!";
  for(int i=0,j=0; i<5; ++i)
 {
    for(int g=0; g<5; ++g,++j)
    {
        TImage *img = new TImage(this);
        img->Parent=this;
        path=+"IMG/";
        path+=IntToStr(j-4).c_str();
        path+=".bmp";
        if(j>=0 && j<5)
        {
           img->Picture->LoadFromFile("IMG/Blank.bmp");
        }
        else
           img->Picture->LoadFromFile(path.c_str());;
        img->Width=100;
        img->Height=120;
        img->OnClick=imgClick;
        karty[j].image=img;
        karty[j].image->Left=g*105+5;
        karty[j].image->Top=i*125+5;
        karty[j].image->Tag=j;
        karty[j].real=j-4;
        karty[j].image->Cursor=crHandPoint;
        if(j>4)
        {
          loadvalues(karty[j],j);
        }
     }
 }
}
//---------------------------------------------------------------------------
 void _fastcall TForm1::loadvalues(cards deck,int tag)
 {
         String path="VALUES/";
         string number;
         path+=IntToStr(tag-4);
         path+=".txt";
         ifstream plik;
         plik.open(path.c_str());
         for(int m=0; m<4; ++m)
         {
          plik>>number;
          TEdit *val=new TEdit(this);
          val->Enabled=0;
          val->Parent=this;
          val->Text=StrToInt(number.c_str());
          if(StrToInt(number.c_str())==10)
                val->Text="A";
          val->Width=14;
          val->Height=14;
          if(m==0)
                {
                val->Left=deck.image->Left+20;
                val->Top=deck.image->Top+76;
                deck.top=StrToInt(number.c_str());
                }
          if(m==1)                     {
                val->Left=deck.image->Left+35;
                val->Top=deck.image->Top+85;
                deck.right=StrToInt(number.c_str());
                }
          if(m==2)                     {
                val->Left=deck.image->Left+20;
                val->Top=deck.image->Top+97;
                deck.bottom=StrToInt(number.c_str());
                }
          if(m==3)                     {
                val->Left=deck.image->Left+5;
                val->Top=deck.image->Top+85;
                deck.left=StrToInt(number.c_str());
                }

          deck.value[m]=val;
         }
         plik.close();
 }
2

Wg mnie to problem masz tu: val->Text=StrToInt(number.c_str()), nawet nie sprawdzasz czy plik się otworzył.

1

No i jeszcze mieszanie typów stringów o czym @_13th_Dragon wspominał w komentarzu:

 void _fastcall TForm1::loadvalues(cards deck,int tag)
 {
         String path="VALUES/";
         string number;
 }

Raz string, drugi raz String. Jeśli kolega używa tylko VCL'a to osobiście radziłbym używać tego pierwszego typu.

0

Zmieniłem na drugi typ stringa po tym jak mi powiedziałeś, że jest jeszcze drugi "String" tylko że jest z nim problem kiedy chcę wczytać coś z pliku używając plik>>String

0

To sobie dodaj:

istream &operator>>(istream &s,String &str)
  {
   string in;
   s>>in;
   str=String(in.c_str());
   return s;
  }

i wczytuj do String bezpośrednio z pliku.

0

A nie lepiej użyć np. TStringList? Szczerze powiedziawszy, to mi się nie podoba mieszanie dwóch bibliotek. Jak piszę coś w VCL'u to używam obiektów które ta biblioteka udostępnia. No chyba, że obsługa mi nie pasuje. Ale to są pojedyncze przypadki.

Tak samo jeśli miałbym jeszcze coś poradzić. To niech kolega @Soderlight nie pisze kodu spaghetti. Chodzi o to aby nie pisać wszystkiego w kodzie formatki. A wydzielić całość do oddzielnej klasy/ bądź nawet kilku klas. Takie coś jest o wiele bardziej przejrzyste i ma swoje plusy.

0

@mr.YaHooo, zaproponuj sensowne rozwiązanie do wczytania pliku w formacie: MiastoFrom MiastoTo Distance np:

Warszawa Karków 20
Warszawa Gdynia 30
Karków Gdynia 15

Przy mieszaniu mamy:

ifstream fin(FileName.c_str());
String CityFrom,CityTo;
double distance;
while(fin>>CityFrom>>CityTo>>distance)
  {
   ...
  }
fin.close();

oraz

istream &operator>>(istream &s,String &str)
  {
   string in;
   s>>in;
   str=String(in.c_str());
   return s;
  }

i to wszystko.

0

@_13th_Dragon faktycznie trochę więcej kodu trzeba by było. Jednak wersja korzystająca z VCL nie będzie o wiele dłuższa:

  TStringList *slFile;
  slFile = new TStringList;

  slFile->LoadFromFile("E:\\test.txt");

  for (int i=0; i<slFile->Count; i++)
  {
    TStringList *slRow;
    slRow = new TStringList;
    slRow->DelimitedText = slFile->Strings[i];

    String CityFrom,CityTo;
    double distance;
    CityFrom = slRow->Strings[0];
    CityTo = slRow->Strings[1];
    distance = slRow->Strings[2].ToDouble();

    delete slRow;
    slRow = NULL;
  }

Jednak wiadomo, że taki sposób padnie w przypadku gdy będą nazwy miast ze spacją jak np. Bielsko Biała.

0
Mr.YaHooo napisał(a):

Jednak wersja korzystająca z VCL nie będzie o wiele dłuższa

  • Trochę dłuższa
  • Bardziej błędogienna - bo już masz wyciek pamięci.
  • Mniej idiotoodporna - zobacz co się stanie przy np literce zamiast distance w obu kodach
    Czyli w sumie bez sensu.
0
_13th_Dragon napisał(a):
  • Trochę dłuższa
    Akurat taka różnica to moim zdaniem żadna różnica.
_13th_Dragon napisał(a):
  • Bardziej błędogienna - bo już masz wyciek pamięci.
    Cóż, źle się skopiowało. Zabrakło 2 lini kodu.
_13th_Dragon napisał(a):
  • Mniej idiotoodporna - zobacz co się stanie przy np literce zamiast distance w obu kodach
    U Ciebie zatrzymuje się. U mnie rzuca wyjątek. U mnie z kolei można wyjątek złapać i zadecydować co dalej. U Ciebie nic dalej nie zrobisz.
  TStringList *slFile;
  slFile = new TStringList;

  slFile->LoadFromFile("E:\\test.txt");

  for (int i=0; i<slFile->Count; i++)
  {
    TStringList *slRow;
    slRow = new TStringList;
    slRow->DelimitedText = slFile->Strings[i];

    String CityFrom,CityTo;
    double distance;
    CityFrom = slRow->Strings[0];
    CityTo = slRow->Strings[1];
    try
    {
      distance = slRow->Strings[2].ToDouble();
    }
    catch(EConvertError &exception)
    {
      distance = -1;
    }

    delete slRow;
    slRow = NULL;
  }

  delete slFile;
  slFile = NULL;
_13th_Dragon napisał(a):

Czyli w sumie bez sensu.
Co kto woli. Ja wolę wiedzieć, że mam błąd i mogę zadecydować co mam zrobić. Czy zarzucić przetwarzanie, czy robić dalej.

0

Ok to powiedz jak twój fragment zareaguje na plik:

Warszawa
   Karków 20
Warszawa 
   Gdynia 30
Karków 
   Gdynia 15

to co ja podałem odczyta bez problemów.
A taki:

Warszawa    Karków    20
Warszawa    Gdynia    30
Karków      Gdynia    15

znowu mój odczyta bez problemów.

Powtarzam, twoja propozycja jest bardzo błędogenna.

0

@_13th_Dragon niestety robisz jakieś wyimaginowane formaty danych. Takich formatów nikt nie stosuje gdzie masz 1 rekord rozbity na 2 wiersze. Bo to bez sensu. Jakbym ja pisał, to bym użył jakiegoś sensownego formatu danych. Chociażby prostego jak budowa cepa pliku dbf. Ja też mogę rzucić kontrargument. A jak Twój sposób poradzi sobie z bardziej skomplikowaną strukturą jak INI:

[main]
items=3

[item1]
CityFrom=Warszawa
CityTo=Opole
distance=123

[item2]
CityFrom=Warszawa
CityTo=Gdansk
distance=30

[item3]
CityFrom=Zakopane
CityTo=Bydgoszcz
distance=777

Bo ja korzystając z klas VCL'a jestem w stanie w niewielkiej ilości kodu sobie z tym poradzić.

Owszem, mój sposób może i powoduje błędy, ale chyba uważamy jak piszemy :)

Widzę, że jednak nic z naszej dyskusji nie wyniknie. Nikt nikogo nie przekona i tyle, a zaraz dojdziemy do jakiegoś flame.

1

Oczywiście że taki jak ten pierwszy się nie stosuje, ale że jest to plik tekstowy to uzyszkodnik mógł jeden lub kilka enterów od tak przypadkiem wsadzić (nie zmyślam, sytuacja z życia wzięta), albo nieodpowiedni plik zapodać (też się nie raz zdarzało).
Moja propozycja nadal z tym radzi, zaś twoja wymaga dopracowania.
Drugi format jest jednak często stosowany weź na przykład rozkład jazdy ZTM Warszawa - plik ma format pozycyjny.
Moja propozycja nadal z tym radzi, zaś twoja wymaga dopracowania.

Jak będziesz potrzebować odczytać ten plik od ZTM to możesz tam zadzwonić i powiedzieć w jakim formacie ten plik potrzebujesz ...,
oczywiście nie muszę opisywać w jak głębokim poważaniu będą oni mieli twoje zachcianki.
Więc albo odczytasz ten plik jakoś sensownie albo nici z tego.
Zaś aby odczytać sensownie to potrzebujesz jeszcze trzykrotnie (mniej-więcej) powiększyć ten swój kod lub zgodzić się na mój.

0

Fakt, user może sobie zmieniać dowolnie pliki z palca i nic z tym nie zrobię. Ja wtedy z reguły w dokumentacji umieszczam strukturę wraz z dokładnym opisem i jak ktoś coś namiesza, to jego wina. Aż tyle czasu nie mam aby pisać importy/eksporty uniwersalnie. jest struktura, ktoś zmienił, może przejść, ale nie musi. Od taką mamy filozofię.

Jeśli chodzi zaś o formaty pozycyjne, to tu w sumie robotę za mnie odwala system. ADO bardzo ładnie czyta takie pliki, plus taki, że mam wszystko dostępne spod SQL. Co ważniejsze mam takie importy i userzy nie narzekają że coś się nie dograło. Jedyny minus jest taki, że jak się zmieni format, czy długość pola, to trzeba zmienić konfigi. To fakt. Bo jeśli miałbym pisać uniwersalnie to faktycznie lepiej wczytywać Twoim sposobem.

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