Avatar billede dehdar Nybegynder
03. marts 2008 - 13:22 Der er 15 kommentarer og
2 løsninger

set_size, dynamisk allokering af Array

Hej, jeg har lavet en klasse, hvor brugeren ved oprettelse af et objekt sætter størrelsen af et dynamisk array explicit. Senere har jeg så tilføjet en setfunktion, som ændrer på størrelsen af mit Array.

Jeg får følgende fejl, når jeg forsøger at compile nedstående:

Error1 error C2057: expected constant expression
Error2 error C2466: cannot allocate an array of constant size 0 Error3 error C2133: 'LokalArray' : unknown size   

Size er en medlemsdata, som jeg har initialiseret ved "member initializing". Hvis jeg i stedet for at skrive size skriver, "sizeof(vaerdiPtr)", så virker det... men burde det ikke virke alligevel? I min constructor, hvor jeg opretter mit array, så giver jeg den nemlig størrelsen af size, så... jeg forstår ikke hvorfor jeg får ovenstående fejl.


void CirkulearBuffer::setSize( const int nySize )
{
Point LokalArray[size];

if ( nySize > 0)
{
if ( nySize < size )
{
  for ( int i = (size - nySize); i < size; i++ )
  LokalArray[i] = vaerdiPtr[i];
}
else
{
  for ( int i = 0; i < size; i++ )
  LokalArray[i] = vaerdiPtr[i];
}
delete vaerdiPtr;
vaerdiPtr = new Point[nySize];

for (int i = 0; i < nySize; i++)
vaerdiPtr[i] = LokalArray[i];
}   
}
Avatar billede tiller3 Nybegynder
03. marts 2008 - 14:14 #1
Du kan ikke allokere et array af ukendt stoerelse paa stacken, saa linien
Point LokalArray[size];
er ikke gyldig. Du skal i stedet allokere det med new(Og saa huske at delete det ogsaa :}
Avatar billede arne_v Ekspert
03. marts 2008 - 14:15 #2
Aeldre C/C++ compilere tillader ikke brug af variable til at dimensionere arrays
med - kun konstanter.

C99 standarden understoetter det.

Brug malloc (C) eller new (C++).
Avatar billede dehdar Nybegynder
03. marts 2008 - 16:13 #3
Til tiller3:

Jeg har allerede en dynamisk allokeret Array. Jeg ønsker blot at tillade brugeren af klassen at ændre arrayets størrelse. Det gør jeg ved først at oprette et lokalt array, som jeg initialiserer med indholdet af mit dynamisk allokerede Array. Dernæst sletter jeg det dynamisk allokerede array og opretter et nyt dynamisk allokeret Array, med den størrelse brugeren ønsker. Til sidst initialiserer jeg den med det, som jeg har kopieret over i mit lokale array, som kun eksisterer i funktionens scope.

Variablen size er som sagt en medlemsdata og hvis jeg skriver "cout << size;" i funktionen, så udskriver den 8, som er hvad jeg har initialiseret den med explicit ved oprettelse af objektet. Mærkeligt...

Til Arne_v:

Eftersom min underviser ikke kunne se hvad der var galt, så må du jo have ret. Det skal lige siges til min undervisers forsvar, at dette var en "uofficiel" ekstra opgave og at han kun havde de sidste 2 minutter af undervisningen til at finde fejlen, samtidig med at han skulle krydse folk af sin godkendelsesliste :)

Under alle omstændigheder, så vil jeg sende din tråd til ham og høre, om han har input til det. Tusind tak for hjælpen.

Forresten, hvor finder jeg oplysninger om den compiler Visual Studio 2008 bruger og kan jeg skifte compileren uden besvær? Du må gerne vedlægge et svar :)
Avatar billede tiller3 Nybegynder
03. marts 2008 - 18:16 #4
Jeg kan ikke se hvad der er saa maerkeligt, men lad mig proeve at omformulere mig.

Hvis du vil allokere et array paa stacken(Point LokalArray[size]) saa skal stoerelsen af det array du allokere vaere konstant og kunne bestemmes paa compile time.

Dette er ikke tilfaeldet her, da din stoerelse(din const int mySize) er en variable som kan have forskellige vaerdier.
Avatar billede tiller3 Nybegynder
03. marts 2008 - 18:21 #5
On lige en kommentar mere:

Du har slet ikke brug for dit Point LokalArray[size];
Du kan bare allokere et nyt array med new, lad os kalde det newArray,

og saa kopiere vaerdierne direkte der over i, og saa til sidst lave en

delete[] vaerdiPtr; // Bemaerk at det er delete[] fordi du sletter et array.
vaerdiPtr = new Point[nySize];
Avatar billede dehdar Nybegynder
03. marts 2008 - 19:58 #6
Meningen med funktionen er jo, at man skal kunne ændre arrayets størrelse ved hjælp af ovenstående funktion. Derfor skal størrelsen være en variabel. Det jeg finder mærkeligt er, at følgende ikke virker, men jeg går ud fra at Arne har ret i, at det er compileren som er for gammel..., hvad mener du?

#include <iostream>
using namespace std;

void funktion( const int x )
{
    int Array[x];
}

void main()
{
    funktion(5);
}

Angående din idé om at allokere et nyt array med new og direkte kopiere indholdet, så har du selvfølgelig ret, men... jeg har desværre undladt at fortælle, at pointeren "vaerdiPtr" er en private medlemspointer, som bliver brugt i andre funktioner. Derfor skal det være den eneste pointer der skal pege på det, som jeg gemmer i heapen. Men ellers tak :)
Avatar billede tiller3 Nybegynder
03. marts 2008 - 20:10 #7
Du kan sagtens lave det saa vaerdiPtr bliver den eneste pointer der peger paa dine data, den anden midlertidige pointer forsvinder jo naar funktionen slutter.

Og
void funktion( const int x )
{
    int Array[x];
}

Er ikke, og har aldrig vaeret gyldig c eller c++ kode, for naar du allokere et array paa den maade(Du allokere det paa stacken) saa skal arrayts stoerelse vaere kendt paa compile time(Naar du oversaetter programmet) og det er det ikke i dette tilfaelde.
Avatar billede tiller3 Nybegynder
03. marts 2008 - 20:16 #8
Omskrevet funktion, uden brug af tmp array.

(Ikke testet, men ideen er i hvertfald god nok :}

void CirkulearBuffer::setSize( const int nySize ) {

if ( nySize > 0) {
  if ( nySize < size ) {
    // Denne del kan du selv lave. Ps: Overvej hvilke data fra det gamle array du vil kopiere
    // Er du sikker paa at du altid vil have dem der ligger foerst i arrayet?
  }
  else {
    // Lav et nyt og stoerrer array
    Point *newPointArray=new PointArray[nySize];

    for ( int i = 0; i < size; i++ ) {
      newPointArray[i] = vaerdiPtr[i];
    }
    delete[] vaerdiPtr; // Slet det gamle array(Bemarke delete[])
    vaerdiPtr = new PointPoitnArray; // Og saet vaerdiPtr til det nye array
  }
}

}
Avatar billede dehdar Nybegynder
03. marts 2008 - 20:25 #9
Ok, så blev jeg klogere :) Tak for svaret...

Så for at få det banket helt fast, så kan man simpelthen ikke lave en funktion, som alt afhængig af input allokere en bestemt størrelse af et array i heapen?
Avatar billede dehdar Nybegynder
03. marts 2008 - 21:05 #10
ugh, jeg har på fornemmelsen at jeg kun har forvirret mig selv og at opgaven vi fik var uigennemtænkt, for som du siger så kan man kun definere størrelsen på et Array compiletime. Lige så snart Arne har svaret, så accepterer jeg begge svar.

Tak igen.
Avatar billede tiller3 Nybegynder
03. marts 2008 - 21:08 #11
quote:
Så for at få det banket helt fast, så kan man simpelthen ikke lave en funktion, som alt afhængig af input allokere en bestemt størrelse af et array i heapen?

Jeg tror du mener stacken, ikke heapen.
Stacken er der hvor du allokere lokale variable fra, og her er det korrekt at du kan kan allokere ting som du kender stoerles paa ved compile time.
Saa

void funktion( const int x )
{
    int Array[x];
}
er ikke muligt;

Heapen er der hvor du allokere fra med new/malloc og der kan du godt bestemme stoerelsen ved runtime.
Avatar billede arne_v Ekspert
03. marts 2008 - 22:21 #12
Øh.

Variable length arrays er en del af C99 standarden.

Hurtig kilde se: http://en.wikipedia.org/wiki/Variable-length_array

GCC har understøttet det i mange år både i C og C++.

MS compilere understøtter det ikke.

Lidt googling antyder at IBM's compilere gør men SUN's gør ikke.

C:\>type go99.c
#include <stdio.h>

void f(int n)
{
    int i,a[n];
    for(i = 0; i < n; i++)
    {
        a[i] = i;
    }
    for(i = 0; i < n; i++)
    {
        printf("%d\n", a[i]);
    }
}

int main()
{
    f(1);
    f(2);
    f(3);
    f(4);
    return 0;
}

C:\>gcc go99.c -o go99.exe

C:\>go99
0
0
1
0
1
2
0
1
2
3

C:\>copy go99.c go99.cpp
        1 file(s) copied.

C:\>g++ go99.cpp -o go99.exe

C:\>go99
0
0
1
0
1
2
0
1
2
3

Personligt synes jeg at det er lidt ringe at C99 som altså er 9 år gammel ikke er implementeret
endnu.

malloc og new allokerer i heap, mens et lokalt array allokeres på stack.

Hvis man vil allokere et variabelt antal på stack med en ældre compiler så kan man
gå tilbage til den måde man gjorde det på for 20 år siden.

void f(int n)
{
    int i,*a;
    a = (int *)alloca(n*sizeof(int));
    for(i = 0; i < n; i++)
    {
        a[i] = i;
    }
    for(i = 0; i < n; i++)
    {
        printf("%d\n", a[i]);
    }
}

gør det samme.

Det bør da iøvrigt være indlysende at det kan implementeres.

Hvad gør:

int a[3];

?

den tæller stack pointeren ned med 3*sizeof(int).

int a[3];

kan bare tælle stack pointeren ned med n*sizeof(int).
Avatar billede arne_v Ekspert
03. marts 2008 - 23:11 #13
og et svar fra mig
Avatar billede dehdar Nybegynder
03. marts 2008 - 23:23 #14
Tak for en detaljeret gennemgang. Jeg er som sagt forholdsvis ny til c++ programmering og har først her på det sidste lært om dynamisk allokering. Jeg havde blot den opfattelse, at man kunne initialisere et lokalt array runtime... jeg synes jeg har gjort det mange gange før og jeg var stensikker på at følgende ville compile inden jeg prøvede det. Jeg tror jeg vil dykke ned i min c++ bog og læse hele afsnittet om arrays.


void funktion( const int x )
{
    int Array[x];
}

void main()
{
    funktion(5);
}
Avatar billede tiller3 Nybegynder
04. marts 2008 - 19:32 #15
Aha der kan man bare se. Men det en sjovt nok kun gyldigt i C, og ikke i c++
(Selvom lidt googling siger at g++ ogsaa acceptere(Eller i hvert fald har gjort)) variable length arrays i c++.
Avatar billede dehdar Nybegynder
04. marts 2008 - 20:56 #16
Hmmm jeg synes det var spild af tid at læse i min bog, men fremover vil jeg huske på, at et dynamisk allokeret array kan dimensioneres runtime (vidste jeg godt i forvejen) og et lokal erklæret array kun kan dimensioneres compiletime.

Tak igen :D
Avatar billede arne_v Ekspert
05. marts 2008 - 02:04 #17
C++98 kom før C99.

Men som det ser ud nu er featuren heller ikke med i C++0x.

Hardcore C++ folkene kan slet ikke lide C style arrays. De mener at man skal bruge
STL i.s.f. f.eks. vector.

void f(int n)
{
    vector<int> a(n);
    for(int i = 0; i < n; i++)
    {
        a[i] = i;
    }
    for(int i = 0; i < n; i++)
    {
        cout << a[i] << endl;
    }
}
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