Risolto Prendere in input diversi elementi nella stessa riga in un ciclo for

ByteMurderer

Utente Iron
6 Maggio 2023
43
14
1
18
Ciao a tutti, stavo completando degli esercizi in cpp che ho trovato sul web pero non riesco a risolvere un particolare eserczio dove viene chiesto di chiedere in input un numero poi creare un array con dimensione del numero chiesto in precedenza, riempirlo (sempre con numeri in input) e poi stampare l'array al contrario. Fin qua tutto facile pero chiede di aver i numeri in input tutti nella stessa riga separati da uno spazio che normalmente faccio coasì: cin >> a >> b >> c ecc.... pero essendo che non so il numero di elementi prima dell'esecuzione del programma ho utilizzato un ciclo for, ma in questo caso come faccio ad avere tutti gli input in una riga?? Questo è il codice che ho scritto:

C++:
#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;
    
    int a[n];
    for(int i=0; i<n; i++){
        cin >> a[n];
    }   
    
    for(int i=n; i>0; i++){
        cout << a[i];
    }
    return 0;
}

Sapete come fare?
(Non so se ho spiegato bene il problema, in caso faccio qualche esempio)
 
Questa cosa qui
C++:
int n;
cin >> n;
int a[n];
Non è un array normale, ma è un VLA. I VLA sono una di quelle features che esiste in C ma non esiste in C++, il tuo codice è quindi sbagliato. Gli array normali si devono essere definiti con una dimensione costante. Quindi tu non puoi usare i VLA perché in C++ non sono supportati, ma non puoi usare nemmeno gli array normali perché dovresti conoscere la dimensione a tempo di compilazione. Hai due alternative:
  1. fissi una dimensione massima ragionevolmente grande, almeno sei ragionevolmente sicuro che il tuo array è in grado di mantenere almeno n numeri, in questo modo
    C++:
    #include <iostream>
    int main() {
      int n;
      std::cin >> n;
      int a[4096];
    
      // do something
    
      return 0;
    }
  2. allochi la memoria dinamicamente con new e delete, in questo modo
    C++:
    #include <iostream>
    int main() {
      int n;
      std::cin >> n;
      int *a = new int[n];
    
      // do something
    
      delete[] a;
      return 0;
    }

C++:
for(int i=n; i>0; i++){ cout << a[i] }
Questo pezzo di codice è sbagliato. Il primo elemento dell'array è a[0] e l'ultimo elemento è a[n-1], quindi il tuo ciclo for deve partire da n-1 (non n), deve continuare per tutti i numeri maggiori o uguali (non strettamente maggiori) a 0, e deve decrementare l'indice (i-- invece di i++).
C++:
for(int i = n - 1; i >= 0; i--){ cout << a[i] }

Infine, per rispondere alla tua domanda, per leggere valori separati dallo spazio puoi usare cin nello stesso modo in cui lo useresti se i valori fossero separati da newlines. Il tuo codice potresti scriverlo in questo modo
C++:
#include <iostream>
using namespace std;

int main() {
  int n;
  int a[4096];

  cin >> n;

  if (n > 4096) {
    cout << "non puoi inserire più di 4096 numeri\n";
    return 0;
  }

  for (int i = 0; i < n; i++) { cin >> a[i]; }
  for (int i = n - 1; i >= 0; i--) { cout << a[i] << "\n"; }

  return 0;
}

Vista la difficoltà dell'esercizio suppongo che new e delete ancora non li hai studiati ma, come vedi, un valore costante va comunque bene.
 
  • Incredibile
Reazioni: ByteMurderer
Non è un array normale, ma è un VLA. I VLA sono una di quelle features che esiste in C ma non esiste in C++, il tuo codice è quindi sbagliato. Gli array normali si devono essere definiti con una dimensione costante. Quindi tu non puoi usare i VLA perché in C++ non sono supportati, ma non puoi usare nemmeno gli array normali perché dovresti conoscere la dimensione a tempo di compilazione. Hai due alternative:
  1. fissi una dimensione massima ragionevolmente grande, almeno sei ragionevolmente sicuro che il tuo array è in grado di mantenere almeno n numeri, in questo modo
Rileggendo bene l'esercizio n ha un limite che mi pare fosse 1000, quindi impostero la dimensione del l'array a mille pero questo non rallenterà il processo quando stampera i numeri, stampando insieme tantisssimi numeri casuali? perchè le posizioni vuote di un array in teoria vengono riempite automaticamente da numeri casuali o zeri, (ho fatto una prova e stampa tanti numeri casuali). Comunque non ho mai sentito parlare dei VLA anche perchè con il mio prof facevo molti esercizi dove gli array non erano definiti con una dimensione costante ma invece con una presa in inpuit quindi ho sempre pensato si facessero cosi. Invece per quanto riguarda la soluzuione di allocare l'array dinamicamente potrei adottare quella, L'ho studia quando ho fatto gli oggetti e alcune volte si dovevano allocare dinamicamente

Questo pezzo di codice è sbagliato. Il primo elemento dell'array è a[0] e l'ultimo elemento è a[n-1], quindi il tuo ciclo for deve partire da n-1 (non n), deve continuare per tutti i numeri maggiori o uguali (non strettamente maggiori) a 0, e deve decrementare l'indice (i-- invece di i++).
Qua mi rendo conto dell'errore, grazie mille per avermelo fatto notare ma è da un po che non programmavo in cpp e per questo volevo riprende tramite alcuni di questi esercizi

Infine, per rispondere alla tua domanda, per leggere valori separati dallo spazio puoi usare cin nello stesso modo in cui lo useresti se i valori fossero separati da newlines. Il tuo codice potresti scriverlo in questo modo
Qua invece non ho capito bene cosa intendi, ma forse mi sono spiegato male io, ecco degli esempi di input corretti e sbagliati:
Input corretto:
4 (dimensione array)
1 2 3 4 (elementi che verranno inseriti nell'array, come vedi devono essere tutti nella stessa linea ma separati da uno spazio)

Invece questo sarebbe un input sbagliato:
4 (dimensione array)
1
2
3
4(questi i numeri che conterranno l'array)
 
Rileggendo bene l'esercizio n ha un limite che mi pare fosse 1000, quindi impostero la dimensione del l'array a mille pero questo non rallenterà il processo quando stampera i numeri, stampando insieme tantisssimi numeri casuali? perchè le posizioni vuote di un array in teoria vengono riempite automaticamente da numeri casuali o zeri, (ho fatto una prova e stampa tanti numeri casuali).
Come puoi vedere dal codice che ti ho postato, il mio array ha ben 4096 elementi ma nella stampa non appare nessun numero casuale. È vero che l'area di memoria non inizializzata contiene valori non ben definiti, ma tu non sei costretto a stamparli. Quello che ti ho fatto vedere, ovvero fissare un upperbound sufficientemente grande e usare gli array very (non VLA), è prassi comune: fanno così anche in alcune parti del linux kernel, non è una porcata che si fa soltanto quando non si sa usare new/delete (o malloc/free).

Se l'esercizio ha un limite di 1000 puoi sostituire 4096 con 1000 nel codice che ti ho fatto vedere, poi se l'utente inserirà un numero più molto più piccolo (cosa probabile) vuol dire che gran parte dell'array rimarrà vuoto (non inizializzato). La parte non inizializzata dell'array non dovrai mai usarla, ma non è un problema lasciarla inutilizzata, è solo un piccolo spreco di spazio. Se lo vuoi rifare con new/delete (ricordandoti di usare le parentesi quadre anche sul delete) va benissimo, ti aiuterà a fare pratica.

Comunque non ho mai sentito parlare dei VLA anche perchè con il mio prof facevo molti esercizi dove gli array non erano definiti con una dimensione costante ma invece con una presa in inpuit quindi ho sempre pensato si facessero cosi.
Ti hanno insegnato male. È un errore che si vede spesso perché in C è consentito (anche se è meglio non usarli) e perché tipicamente i professori sono più interessati a spiegarti "come pensare da programmatore" piuttosto che i vari quirks dei linguaggi di programmazione. Però, adesso che lo sai, puoi disabituarti per diventare un programmatore migliore.

Qua invece non ho capito bene cosa intendi, ma forse mi sono spiegato male io, ecco degli esempi di input corretti e sbagliati:
Input corretto:
4 (dimensione array)
1 2 3 4 (elementi che verranno inseriti nell'array, come vedi devono essere tutti nella stessa linea ma separati da uno spazio)

Invece questo sarebbe un input sbagliato:
4 (dimensione array)
1
2
3
4(questi i numeri che conterranno l'array)
Il codice che ti ho fatto vedere, ovvero for (int i = 0; i < n; i++) { cin >> a[i]; }, va bene sia per l'input giusto che per l'input sbagliato. La cosa importante è che va bene per l'input giusto, poco ci importa se va bene anche per l'input sbagliato.
 
  • Incredibile
Reazioni: ByteMurderer
Come puoi vedere dal codice che ti ho postato, il mio array ha ben 4096 elementi ma nella stampa non appare nessun numero casuale. È vero che l'area di memoria non inizializzata contiene valori non ben definiti, ma tu non sei costretto a stamparli. Quello che ti ho fatto vedere, ovvero fissare un upperbound sufficientemente grande e usare gli array very (non VLA), è prassi comune: fanno così anche in alcune parti del linux kernel, non è una porcata che si fa soltanto quando non si sa usare new/delete (o malloc/free).

Se l'esercizio ha un limite di 1000 puoi sostituire 4096 con 1000 nel codice che ti ho fatto vedere, poi se l'utente inserirà un numero più molto più piccolo (cosa probabile) vuol dire che gran parte dell'array rimarrà vuoto (non inizializzato). La parte non inizializzata dell'array non dovrai mai usarla, ma non è un problema lasciarla inutilizzata, è solo un piccolo spreco di spazio. Se lo vuoi rifare con new/delete (ricordandoti di usare le parentesi quadre anche sul delete) va benissimo, ti aiuterà a fare pratica.


Ti hanno insegnato male. È un errore che si vede spesso perché in C è consentito (anche se è meglio non usarli) e perché tipicamente i professori sono più interessati a spiegarti "come pensare da programmatore" piuttosto che i vari quirks dei linguaggi di programmazione. Però, adesso che lo sai, puoi disabituarti per diventare un programmatore migliore.


Il codice che ti ho fatto vedere, ovvero for (int i = 0; i < n; i++) { cin >> a[i]; }, va bene sia per l'input giusto che per l'input sbagliato. La cosa importante è che va bene per l'input giusto, poco ci importa se va bene anche per l'input sbagliato.
Ora funziona, grazie mille per tutto <3