Domanda Risolto (C) lvalue required as increment operand

nostyn

Utente Electrum
12 Gennaio 2017
284
25
83
126
Lo scopo di questa parte del codice e' quella di inserire all'interno di un array a cui posso accedere tutte le stringhe che non sono parametri "opzionali" ricevuti all'invocazione del programma.
C:
int main(int argc, char *argv[])
{
    char *argvS[argc];
    
    while(--argc >= 0 && *++argv != NULL) // So che il doppio controllo e' superfluo.
        if(/*se si tratta di parametri formali*/)
        {
            //...
        }
        else
            *argvS++ = *argv;
    *argvS = NULL;
    //...
    return 0;
}
Ho ragionato in questo modo: creo un vettore di puntatori a caratteri di nome argvS di dimensioni sufficienti da contenere eventualmente tutti gli indirizzi di argv , ad eccezione del primo ma includendo un ultimo indirizzo che sara' NULL. Successivamente tramite una selezione controllo quali siano le stringhe che mi interessano, prendo il loro indirizzo *argv e lo inserisco all'interno del mio vettore, per poi prepararlo al prossimo indirizzo con l'autoincremento e dunque *argvS++ .

Risultato: lvalue required as increment operand in *argvS++ = *argv;

Dove ho peccato? :oddio:
 
Ammettendo che il tuo codice venga effettivamente compilato senza errori, come fai a capire dove inizia argvS se lo stai modificando? Comunque, in C non è lecito assegnare un valore ad un array: gli array, come valore costante, puntano al primo dei loro elementi. Fare una cosa del genere?
C:
int obligatory_args(char **dest, int argc, char *argv[]) {
  int n = 0;

  for (int i = 0; i < argc; ++i)
    if (/* argv[i] is obligatory */)
      dest[n++] = argv[i];
    
  return n;
}

int main(int argc, char *argv[]) {
  char *argvS[argc];
  int argcS = obligatory_args(argvS, argc, argv);

  return 0;
}

Ti faccio inoltre notare che stai usando i VLA che sono una feature opzionale in C11.
 
  • Mi piace
Reazioni: nostyn
come fai a capire dove inizia argvS se lo stai modificando?
Nella versione non ridotta c'e' anche un'indice all'inizio del main che tiene traccia e poi sottrae gli indirizzi per tornare a quello iniziale. (Se non mi sono espresso bene dimmelo, riformulo)

Comunque, in C non è lecito assegnare un valore ad un array: gli array, come valore costante, puntano al primo dei loro elementi.
In altri esercizi con puntatori di vettori non ho avuto questo genere di problemi, la mia intenzione non e' quella di copiare valori ma per l'appunto indirizzi, come hai fatto nel tuo esempio. Domani con il testo alla mano ti diro' con piu' certezza. Quello che non capisco: dal momento che si puo' fare portandolo in una funzione separata, quell'operazione con **dest, potrei svolgerla direttamente nel main? In teoria non dovrebbe essere equivalente a char *dest[argc] = argvS; ?
 
Nella versione non ridotta c'e' anche un'indice all'inizio del main che tiene traccia e poi sottrae gli indirizzi per tornare a quello iniziale. (Se non mi sono espresso bene dimmelo, riformulo)
Posta il codice e ne discutiamo. È il ciclo while usato in quel modo che è un po' forzato, meglio un for.

Quello che non capisco: dal momento che si puo' fare portandolo in una funzione separata, quell'operazione con **dest, potrei svolgerla direttamente nel main? In teoria non dovrebbe essere equivalente a char *dest[argc] = argvS; ?
Non è creando una funzione separata che ho risolto il problema, quello l'ho fatto solo per chiarezza. In C non si può fare int a[5]; a++;. Nel tuo codice lo stai facendo, io invece no. L'istruzione a++; modifica il valore di a e non si può fare: gli array puntano al loro primo elemento.

C:
int main(int argc, char *argv[]) {
  int argcS = 0;
  char *argvS[argc];

  for (int i = 0; i < argc; i++)
    if (/* argv[i] is obligatory */)
      argvS[argcS++] = argv[i];

  return 0;
}
 
  • Mi piace
Reazioni: nostyn
Ultima modifica:
Non è creando una funzione separata che ho risolto il problema, quello l'ho fatto solo per chiarezza. In C non si può fare int a[5]; a++;. Nel tuo codice lo stai facendo, io invece no. L'istruzione a++; modifica il valore di a e non si può fare: gli array puntano al loro primo elemento.
Si, scusa, hai perfettamente ragione, per un momento ho dimenticato che effettivamente argvS fosse un vettore puntatori.. ho pensato che ci fossero delle proprieta' differenti all'interno dei vettori di caratteri.. credo di dovermi rivedere un po di cose. :matto: Do' di matto.
Messaggio unito automaticamente:

@St3ve , scusa la domanda sciocca.
Se un vettore e' un puntatore all'indirizzo del primo elemento dell'insieme dei valori che contiene, perche' qui:
C:
int main(int argc, char *argv[]) {
  int argcS = 0;
  char *argvS[argc];

  for (int i = 0; i < argc; i++)
    if (/* argv[i] is obligatory */)
      argvS[argcS++] = argv[i];

  return 0;
}
non posso scrivere cosi?
C:
int main(int argc, char *argv[]) {
  int argcS = 0;
  char **argvS; // <----------

  for (int i = 0; i < argc; i++)
    if (/* argv[i] is obligatory */)
      argvS[argcS++] = argv[i];

  return 0;
}
Il che tra l'altro viene anche accettato dal compilatore senza warning, ma poi porta ad un crash del programma.
Perche' qui ad esempio mandi come argomento *argvS[] e come parametro e' indicato come **dest e non *dest[] ?
C:
int obligatory_args(char **dest, int argc, char *argv[]) {
  int n = 0;

  for (int i = 0; i < argc; ++i)
    if (/* argv[i] is obligatory */)
      dest[n++] = argv[i];
   
  return n;
}

int main(int argc, char *argv[]) {
  char *argvS[argc];
  int argcS = obligatory_args(argvS, argc, argv);

  return 0;
}
 
Se un vettore e' un puntatore all'indirizzo del primo elemento dell'insieme dei valori che contiene, perche' qui:
C:
int main(int argc, char *argv[]) {
int argcS = 0;
char *argvS[argc];

for (int i = 0; i < argc; i++)
if (/* argv[i] is obligatory */)
argvS[argcS++] = argv[i];

return 0;
}
non posso scrivere cosi?
C:
int main(int argc, char *argv[]) {
int argcS = 0;
char **argvS; // <----------

for (int i = 0; i < argc; i++)
if (/* argv[i] is obligatory */)
argvS[argcS++] = argv[i];

return 0;
}
Il che tra l'altro viene anche accettato dal compilatore senza warning, ma poi porta ad un crash del programma.
Un array è una sequenza contigua di oggetti dello stesso tipo, un puntatore è una variabile che ha per valore un indirizzo. Gli array formano di fatto un loro tipo, esattamente come float e int, e un array di 5 interi ha tipo diverso di un array di 6 interi; però arrays decay into pointers: gli array vengono trattati come puntatori.

Il primo codice è corretto perché hai un'array di argc elementi e con argv[i] accedi al suo i-esimo elemento (ammesso che non sia out of bound). Il secondo codice è sbagliato perché hai un puntatore: non hai una sequenza contigua di oggetti dello stesso tipo, hai una variabile che contiene un indirizzo che per di più non è nemmeno inizializzata. Nel secondo caso, con la sintassi argv[i] stai accedendo alla variabile che è localizzata i * sizeof(int) bytes dopo il valore in argv: se argv è vagamente simile ad un array di argc elementi (e.g., hai usato la malloc) allora nessun problema, altrimenti rischi di accedere ad un area di memoria che non ti appartiene (segmentation fault). Arrays decay into pointers significa che puoi trattare gli array come fossero puntatori, non che puoi trattare i puntatori come fossero array. Tieni bene a mente che array e i puntatori sono due cose concettualmente molto diverse: in quasi tutti i linguaggi esistono gli array, ma in pochi linguaggi esistono i puntatori.

Perche' qui ad esempio mandi come argomento *argvS[] e come parametro e' indicato come **dest e non *dest[] ?
Se usati come parametri int *dest[] e int **dest sono pressoché identici, per essere precisi int *dest[] è come dire const int **dest. È un caso particolare che vale per i parametri delle funzioni, però hai ragione... sarei potuto essere più preciso.
 
  • Mi piace
Reazioni: nostyn
significa che puoi trattare gli array come fossero puntatori, non che puoi trattare i puntatori come fossero array.
Questo era un concetto che non avevo ancora consolidato, questa sola affermazione fa capire piu' di tanti esercizi.

però hai ragione... sarei potuto essere più preciso.
Assolutamente no, hai risposto al mio quesito e sei stato esaustivo come sempre :sisi: Purtroppo non tutto sta scritto sui libri e risento della mancanza di un professionista che possa chiarirmi alcuni quesiti, ma pazienza, la pratica rende perfetti, continuo a fare esercizi e documentarmi, conto di riuscire a comprendere a pieno i puntatori nel corso di questa settimana. Come sempre grazie dei chiarimenti! ^^