Avatar billede al1407 Nybegynder
11. februar 2003 - 17:15 Der er 24 kommentarer og
5 løsninger

Resize af array ?

Jeg vil bruge FindFirstFile() til at søge efter filer og mapper rekursivt, og har i min VB udgave lavet et Static array der bliver ReDim'et (resized) hvis der er for få elementer (sizeof()+100 bliver den nye størrelse), men jeg kan ikke rigtigt kringle hvordan dette kan lade sig gøre i VC++ .. eller, om det KAN lade sig gøre .. ?

Hvis det kan, er der nogle der har en idé til hvordan ?
Avatar billede soreno Praktikant
11. februar 2003 - 17:26 #1
Du kan f.eks. bruge en stl vector.
Avatar billede arne_v Ekspert
11. februar 2003 - 17:27 #2
Du kan ikke resize et array.

Men du kan resize noget malloc'ed med realloc.
Avatar billede soreno Praktikant
11. februar 2003 - 17:31 #3
F.eks:

#include <iostream>
#include <vector>

using namespace std;

int main(int argc, char **argv)
{
  vector<char *> v;
  v.push_back("Hello");
  v.push_back(" ");
  v.push_back("World");   
  v.push_back("!!");
  vector<char *>::iterator iter;
  for(iter=v.begin();iter!=v.end();iter++)
  {
      cout << *iter;
  }
   
  return 0;
}
Avatar billede soreno Praktikant
11. februar 2003 - 17:47 #4
Det fremgår ikke rigtigt hvad fordelen med en vector er..
En vector udvides automatisk når der ikke er plads til et element - sikkert det samme som sker i dit basic program. Altså en pæn (og vel testet) indpakning af Arnes forslag.
Avatar billede al1407 Nybegynder
11. februar 2003 - 18:36 #5
Det må jeg lige se på når jeg kommer hjem .. tak indtil videre :)
Avatar billede hsloth Novice
12. februar 2003 - 10:31 #6
Hvis du tager udgangspunkt i sorenos kode skal du huske at kopiere navnene på de filer du får tilbage fra FindFirstFile, hvis du laver en vektor med char pointers bliver der ikke kopieret. F.eks. :

WIN32_FIND_DATA hit;
std::vector<std::string> v;
//...
HANDLE h = FindFirstFile("*.exe", &hit );
v.push_back( hit.cFileName );

while( FindNextFile(h, &hit ) )
{
  v.push_back( hit.cFileName );
}
//...

Hver gang der laves push_back i ovenstående vil der blive oprettet en ny std::string og indholdet af cFileName feltet vil blive kopieret.
Avatar billede dilleberg Nybegynder
15. februar 2003 - 02:39 #7
VC++ ? Så kan du anvende MFC CStringArray :

I dit loop gør du følgende:

CStringArray rgFilenames;
while(...)
{
  ...
  rgFilenames.Add(szFilename); // Tilføj streng og forøg, om nødvendig
  ...
}

Og arrayet kan gennemløbes:
for (int iIndex = 0; iIndex < rgFilenames.GetSize(); iIndex++)
{
  ...
  CString strFilename = rgFilenames[iIndex];
  ...
}

db
Avatar billede olennert Nybegynder
15. februar 2003 - 09:52 #8
Hvis du skal vælge mellem STL (std::vector) og MFC (CStringArray), så vælg STL. Det er standard, og findes i langt flere oversættere end MFC gør.
Avatar billede emileej Nybegynder
15. februar 2003 - 16:10 #9
Man KAN jo oss lave det med arrays :)
Eksempel med et char array:

#include <string.h>
void ResizeArr(char *arr, int oldLen, int newLen){
    if(newLen < 0 || oldLen < 0)throw string("Dumeflad! En længde kan ikke være mindre end 0!");
    char *tmp, *newArr=new char[newLen];
    int uLen=0;
    if(oldLen < newLen)uLen=oldLen;
    else uLen=newLen;
    for(int i=0;i < uLen;i++)
        newArr[i]=arr[i];
    tmp=arr;
    arr=newArr;
    delete[] tmp;
}

E-)mil
Avatar billede arne_v Ekspert
15. februar 2003 - 17:37 #10
emil>

Et program der bruger den funktion vil med stor sandsynelighed crashe
hurtigt p.g.a. memory corruption.

For forklaring og et forslag til hvordan det kan forbedres se:

#include <iostream>

using namespace std;

void redim1(char *p,int oldsiz,int newsiz) {
  char *pp = new char[newsiz];
  cout << "new address = " << (int)pp << " length = " << newsiz << endl;
  memcpy(pp,p,oldsiz);
  char *ppp = p;
  p = pp;
  delete[] ppp;
  cout << "delete address = " << (int)ppp << endl;
  return;
}

void redim2(char **p,int oldsiz,int newsiz) {
  char *pp = new char[newsiz];
  cout << "new address = " << (int)pp << " length = " << newsiz << endl;
  memcpy(pp,*p,oldsiz);
  char *ppp = *p;
  *p = pp;
  delete[] ppp;
  cout << "delete address = " << (int)ppp << endl;
  return;
}

int main()
{
  char *p1 = new char[100];
  cout << "new address = " << (int)p1 << " length = 100" << endl;
  redim1(p1,100,200);
  cout << "redim address = " << (int)p1 << " length = 200" << endl;
  cout << "----------" << endl;
  char *p2 = new char[100];
  cout << "new address = " << (int)p2 << " length = 100" << endl;
  redim2(&p2,100,200);
  cout << "redim address = " << (int)p2 << " length = 200" << endl;
}
Avatar billede emileej Nybegynder
15. februar 2003 - 17:41 #11
>>arne_v
"Et program der bruger den funktion vil med stor sandsynelighed crashe hurtigt p.g.a. memory corruption"

Hvad faen er det for noed at fyre af uden at forklare sig?! Jeg smed noget kode efter jer hoeder for at illustrere en idé og så bliver jeg kritisseret uden at man gidder spilde tid på at forklare sig i ord?...
Avatar billede arne_v Ekspert
15. februar 2003 - 17:41 #12
(og ja mine eksempler kan kun redim'e op i størrelse)
Avatar billede arne_v Ekspert
15. februar 2003 - 17:44 #13
emil>

Læs lige mit lille eksempel eller endnu bedre kør det.

redim1 er ekvivalent med din kode (bortset fra at jeg har forsimplet
data kopieringen lidt fordi det ikke lige er det aspekt der har
betydning).
Avatar billede emileej Nybegynder
15. februar 2003 - 17:45 #14
Har du tænkt dig at forklare?
Avatar billede arne_v Ekspert
15. februar 2003 - 17:46 #15
emil>

Det er lidt svært at forklare på dansk, men hvis du kører det
program (som jeg altså brugte 10 minutter på at skrive), så burde
min pointe fremgå klart.
Avatar billede emileej Nybegynder
15. februar 2003 - 17:46 #16
Jeg tvivler ikke på din kode - vil bare godt høre hvad det er du mener går galt i min...
Avatar billede arne_v Ekspert
15. februar 2003 - 17:48 #17
Jeg kan godt prøve: en char pointer som argument er pass by reference
for det bagvedliggende char array men pass by value for pointeren
selv og derfor bør man ikke ændre den men istedetfor sende adressen
på pointeren over.
Avatar billede arne_v Ekspert
15. februar 2003 - 17:51 #18
Output af mit program er:

new address = 4144184 length = 100
new address = 4145384 length = 200
delete address = 4144184
redim address = 4144184 length = 200
----------
new address = 4144184 length = 100
new address = 4145600 length = 200
delete address = 4144184
redim address = 4145600 length = 200

og man ser at redim1 (som bruger char *p) går grueligt
galt da man efter return fra redim1 står med en pointer som
peger på et stykke memory, som man har delete'd inde i redim1.

redim2 gør derimod det som man ønsker og man står med en pointer til
det nye stykke memory.
Avatar billede arne_v Ekspert
15. februar 2003 - 17:53 #19
Det er i virkeligheden det samme som den klassiske:

int i = 1;
foobar(i);
cout << i << endl;

void foobar(int i)
{
  i = 2;
  return;
}

som skriver 1 ikke 2 ud.
Avatar billede emileej Nybegynder
15. februar 2003 - 17:55 #20
"...bør man ikke ændre..." du mener altså at koden virker, men at du ikke ville bruge den?
Avatar billede arne_v Ekspert
15. februar 2003 - 18:00 #21
Nej.

Der sker ikke det fjerneste ved at man ændrer den.

*Men* man skal være klar over at ændringerne forsvinder
når man udfører return.

Og i dette tilfælde hvor man har free'et den gamle pointer er
det katastrofalt.

Generelt vil jeg kalde det meget dårlig skik at ændre i pass by
value argumenter.

Lav en temporær variabel og assign til den og ændre i den
temporære. Så er der ikke nogen som er i tvivl om at ændringerne ikke
føres tilbage ved return.
Avatar billede emileej Nybegynder
15. februar 2003 - 18:04 #22
Du mener således?:

#include <string.h>
char *ResizeArr(const char *arr, int oldLen, int newLen){
    if(newLen < 0 || oldLen < 0)throw string("Dumeflad! En længde kan ikke være mindre end 0!");
    char *tmp, *newArr=new char[newLen];
    int uLen=0;
    if(oldLen < newLen)uLen=oldLen;
    else uLen=newLen;
    for(int i=0;i < uLen;i++)
        newArr[i]=arr[i];
    tmp=arr;
    delete[] tmp;
    return newArr;
}

...

char *c=new char[5];
c=ResizeArr(c,5,4);
Avatar billede arne_v Ekspert
15. februar 2003 - 18:22 #23
Ja. Det vil virke.

Du kunne også bruge pointer to pointer ligesom i min redim2 altså:

void ResizeArr(char **arr, int oldLen, int newLen){
    if(newLen < 0 || oldLen < 0)throw string("Dumeflad! En længde kan ikke være mindre end 0!");
    char *tmp, *newArr=new char[newLen];
    int uLen=0;
    if(oldLen < newLen)uLen=oldLen;
    else uLen=newLen;
    for(int i=0;i < uLen;i++)
        newArr[i]=(*arr)[i];
    tmp=(*arr);
    (*arr)=newArr;
    delete[] tmp;
}
Avatar billede arne_v Ekspert
15. februar 2003 - 18:23 #24
Og kalde med:
char *c=new char[5];
ResizeArr(&c,5,4);
Avatar billede hsloth Novice
16. februar 2003 - 12:13 #25
En udgave med mindre kode, der også er hurtigere :

void ResizeArr(char **arr, unsigned int oldLen, unsigned int newLen)
{
    char *newArr=new char[newLen];
    memcpy( newArr, *arr, min(oldLen, newLen) );
    delete[] *arr;
    *arr=newArr;
}
Avatar billede emileej Nybegynder
16. februar 2003 - 12:26 #26
al1407 har ikke opgivet hvilken type hans array er, så for liiige at få det hele med:

//Ret 'char' til den type dit array skal være
#define ARRTYPE char
void ResizeArr(ARRTYPE **arr, unsigned int oldLen, unsigned int newLen){
    ARRTYPE *newArr=new ARRTYPE[newLen];
    memcpy(newArr, *arr, min(oldLen, newLen));
    delete[] *arr;
    *arr=newArr;
}

Nu kan der vist heller ikk gøres mere :)
Avatar billede hsloth Novice
16. februar 2003 - 12:34 #27
emileej>

Der er mindst en ting man skal huske - størrelsen af de data der skal kopieres :

//Ret 'char' til den type dit array skal være
#define ARRTYPE char
void ResizeArr(ARRTYPE **arr, unsigned int oldLen, unsigned int newLen){
    ARRTYPE *newArr=new ARRTYPE[newLen];
    memcpy(newArr, *arr, sizeof(ARRTYPE) * min(oldLen, newLen));
    delete[] *arr;
    *arr=newArr;
}

Personligt foretrækker jeg dog en template til sådan noget her :

template <class T> void ResizeArr( T ** arr, unsigned int oldLen, unsigned int newLen)
{
    T *newArr=new T[newLen];
    memcpy(newArr, *arr, sizeof(T) * min(oldLen, newLen));
    delete[] *arr;
    *arr=newArr;
}
Avatar billede arne_v Ekspert
19. februar 2003 - 23:06 #28
al1407>

Har du fået svar på dit spørgsmål ?
Avatar billede al1407 Nybegynder
08. marts 2003 - 15:40 #29
Tak for jeres foreslag og kommentarer :o)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester