[C++] Array ad informazione tappo

paolotesla91
Salve a tutti. Avrei un problema con la compilazione di un programma il cui codice sorgente è riportato come esempio sui miei appunti del corso. Il codice in questione è un esempio di come si rappresenti un array di lunghezza non nota utilizzando una informazione di tipo TAPPO e successivamente effettuare una elaborazione degli elementi presenti nell'array. Riporto di seguito il codice sorgente:

#include

using namespace std;

int main (){

const int TAPPO = -1000;
int n, i;
double x, somma;
double lista[MAX];


n = 0;
cin>> x;

while( x != TAPPO ){
a[n] = x; n++;
cin >> x;
}

somma=0;
for(i=0; i somma= somma+lista;
}

cout << somma;

return 0;
}

Il compilatore mi da più errori relativi allo stesso problema e cioè la dichiarazione delle variabili. Il compilatore mi dice che le variabili MAX, lista, a non sono state dichiarate. Qualcuno saprebbe aiutarmi?
Ringrazio in anticipo.

Risposte
Super Squirrel
Come giustamente sottolineato dal compilatore, una variabile per poter essere utilizzata deve prima essere dichiarata, quindi il problema può essere risolto semplicemente dichiarando le variabili "a" e "MAX".
Inoltre affinché il codice faccia il suo dovere devi sostituire all'interno del ciclo while la variabile "a" con la variabile "lista".

Vabbè poi si potrebbero migliorare alcune cose (per esempio si potrebbero utilizzare un minor numero di variabili), ma visto che lo scopo del codice è quello di fare un esempio non è molto importante.

paolotesla91
Ciao. Ti ringrazio per la risposta. Avrei delle domande: se dichiaro la variabile MAX non sto implicitamente dicendo che l'array ha una dimensione (lunghezza) massima pari proprio a MAX? Quindi che senso avrebbe l'esempio per un array di lunghezza indefinita? La variabile lista andrebbe sostituita ad a ma anche negli altri esempi mi riporta sempre la variabile a in riferimento all'array. Ci provo comunque e scriverò il risultato.

Super Squirrel
Avrei delle domande: se dichiaro la variabile MAX non sto implicitamente dicendo che l'array ha una dimensione (lunghezza) massima pari proprio a MAX? Quindi che senso avrebbe l'esempio per un array di lunghezza indefinita?


Quando dichiari un array devi anche fissare la sua dimensione (che deve essere un intero positivo) e da qui non si scappa. Un trucchetto a cui potresti ricorrere potrebbe essere quello di dichiarare (senza inizializzarla) la variabile "MAX" come un intero senza segno (unsigned int). Tale variabile non essendo stata inizializzata assumerà un valore casuale.
Ovviamente nel momenti in cui gli inserimenti superano quel valore casuale il programma crasherà.

Per quanto riguarda il senso dell'esempio non l'ho capito nemmeno io.

La variabile lista andrebbe sostituita ad a ma anche negli altri esempi mi riporta sempre la variabile a in riferimento all'array. Ci provo comunque e scriverò il risultato.


Come già detto ogni variabile va innanzitutto dichiarata e quindi anche l'array "a" (presumo come "double a[MAX]").
In ogni caso senza effettuare la sostituzione detta nel mio post precedente il programma farà la seguente cosa:
inserisci valori in "a" finché non inserisci il valore -1000 e poi sommerà i primi "n" (dove "n" è il numero di inserimenti precedenti al -1000) elementi dell'array "lista" (che non essendo stato inizializzato conterrà valori casuali).

Non capisco l'utilità di tutto ciò... :|

vict85
La dimensione di un array, nel c++, deve essere una espressione costante che può essere convertita in un valore intero maggiore di zero. Essere una espressione costante è una proprietà abbastanza ristretta, ma di fatto significa che il compilatore, nel momento in cui legge l'espressione, deve essere in grado di determinare il valore esatto.
GCC (se compili senza esplicitare lo standard o forzando la compatibilità), e gli ultimi standard C, permettono di definire array la cui dimensione è determinata in fase di esecuzione. Ma farlo in c++ rende il codice non portabile.

Quindi non solo il trucchetto di Super Squirrel non compila in C++, ma non è assicurato che il compilatore compili qualcosa come:
#include<cstdio>

int main()
{
int num = 5;
int A[num] = {0};
printf("%d", A[2]);
}

paolotesla91
Posto di seguito il codice sorgente, ditemi se è corretto;

#include


using namespace std;

int main (){

const int TAPPO = -1000;
int n, i;
double x, somma;
int MAX;
double lista [MAX];

cout << "inserire elementi della lista \n";
n = 0;
cin>> x;

while( x != TAPPO ){
lista [n] = x; n++;
cin >> x;
}

somma=0;
for( i=0; i somma= somma + lista;
}

cout << somma;

return 0;
}

Ho provato a compilarlo ed effettivamente compila ed esegue m il problema è che il programma crasha mentre sto inserendo gli elementi della lista. Soluzioni??

paolotesla91
Credo di aver risolto in questo modo:


#include

using namespace std;

int main (){

const int TAPPO = -1000;
int n, i, MAX;
double lista [MAX];
double x, somma;
//inserisco gli elementi della lista
cout << "inserire elementi della lista \n";

n = 0;
cin >> x;

while ( x != TAPPO ){
lista [MAX] = x;
n++;
cin >> x;
}
//faccio la somma degli elemtni e la stampo a video
somma = 0;
for ( i=0; i somma = somma + lista;
cout << somma;


return 0;
}

Ora il programma non crasha più ma una volta inserita la lista il programma stampa a video solo l'ultimo elemento della lista. Cosa sbaglio?

vict85
Come stavo dicendo, il tuo codice non è standard e a mio avviso NON dovrebbe compilare senza warning su NESSUN compilare. Il fatto che GCC e clang lo compilino lo considero un bug del compilatore. Detto questo, ci sono altri errori nel codice, ma il codice originale è così tanto sbagliato, in così tanti modi, che è meglio se butti quella pagina degli appunti nel cestino dell'immondizia.

paolotesla91
quanto odio le dispense scritte dai prof ...

Super Squirrel
@vict85
Sono un po' arrugginito sulla teoria, ma se ricordo bene la dimensione di un array statico deve essere nota già in fase di compilazione in modo da riservare la giusta quantità di memoria. Inoltre dopo avermelo fatto notare mi sono ricordato che tale dimensione deve anche essere una costante (ossia un numero, una variabile definita const o utilizzando la direttiva #define). Alla luce di ciò è evidente che una variabile non è una costante e quindi da un punto di vista formale la seguente scrittura è sbagliata:

unsigned int n = 5;
int v[n];


Da un punto di vista logico invece perché non dovrebbe andar bene? In fase di compilazione il valore di n non è già noto?
Nel senso c'è un motivo pratico per cui quel codice è sbagliato oppure è dovuto solo al fatto che il compilatore è stato implementato per accettare come dimensioni di array solo costanti?


@paolotesla91
Per quanto riguarda il crash non saprei dirti di preciso cosa avviene a livello di memoria, in ogni caso ti basti sapere che la dimensione di un array deve essere una costante (un numero per farla breve).
Inoltre visti i tuoi dubbi e la modifica che hai apportato all'ultimo codice da te postato, ti consiglio di ripetere un po' le basi del C++ magari con esempi più costruttivi rispetto a questo.

apatriarca
In linea di principio non c'è alcuna ragione per cui tu debba ignorare casi come quello. Tuttavia presenta il problema di definire quando ci si debba fermare. Considerare casi particolari come questo potrebbe non essere particolarmente utile e complicherebbe inutilmente le regole del linguaggio. Viceversa, qualcosa come "qualsiasi espressione il cui valore possa essere calcolato a tempo di compilazione" è troppo generico e ambiguo. Inoltre, se quel codice fosse in una funzione non c'è alcuna ragione per fermarsi ad una espressione costante e se fosse globale le tue supposizioni sul valore di n potrebbero non essere esatte.

Ma credo che la principale ragione sia alla fin fine che nulla ti vieta di usare una costante in quel caso. Per gli altri casi ci sono constexpr e const.

vict85
Comunque al di là della definizione dell'array, direi che questa parte è anche peggio:
n = 0;
cin >> x;
	
while ( x != TAPPO ){
	lista [n] = x;
	n++;
	cin >> x;
}

infatti anche supponendo che [inline]MAX[/inline] sia definito con un define o con una variabile costante, NON stai testando che [inline]n[/inline] sia inferiore al valore [inline]MAX[/inline] e quindi è un possibile buffer overflow.

L'ultima versione di questa parte del codice è ancora meno corretta perché scrive OGNI volta al di fuori dell'array ([inline]lista[MAX][/inline] non è infatti nell'array lista ma è il primo elemento che non lo è), senza considerare che sovrascrive i valori precedenti.

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.