Domanda

Ho eseguito in un certo codice e si chiedeva che cosa lo sviluppatore originale era fino a. Qui di seguito è un programma semplificato utilizzando questo schema:

      #include <stdio.h>

      int main()  {     

      char title[80] = "mytitle";      
      char title2[80] = "mayataiatale";      
      char mystring[80]; 

      /* hugh ? */
      sscanf(title,"%[^a]",mystring);
      printf("%s\n",mystring); /* Output is "mytitle" */


      /* hugh ? */
      sscanf(title2,"%[^a]",mystring); /* Output is "m" */
      printf("%s\n",mystring);


      return 0;  
  }

Il per scanf ha informazioni rilevanti, ma sto avendo difficoltà leggerlo. Qual è lo scopo di utilizzare questo tipo di notazione? Che cosa sta cercando di realizzare?

È stato utile?

Soluzione

Il motivo principale per le classi di caratteri è così che la notazione% s si ferma al primo carattere di spazio bianco, anche se si specifica lunghezze di campo, e si molto spesso non lo vogliono a. In tal caso, la notazione classe di caratteri può essere estremamente utile.

Si consideri questo codice per leggere una riga di un massimo di 10 caratteri, scartando ogni eccesso, ma mantenendo gli spazi:

#include <ctype.h>
#include <stdio.h>

int main(void)
{
    char buffer[10+1] = "";
    int rc;
    while ((rc = scanf("%10[^\n]%*[^\n]", buffer)) >= 0)
    {
            int c = getchar();
            printf("rc = %d\n", rc);
            if (rc >= 0)
                    printf("buffer = <<%s>>\n", buffer);
            buffer[0] = '\0';
    }
    printf("rc = %d\n", rc);
    return(0);
}

Questo è stato effettivamente esempio di codice per una discussione su comp.lang.c.moderated (circa giugno 2004) relativi a getline() varianti.


Almeno una certa confusione regna. Il primo identificatore di formato, %10[^\n], legge fino a 10 caratteri non newline e sono assegnati al buffer, oltre ad nullo finale. Il secondo identificatore di formato, %*[^\n] contiene il carattere soppressione assegnazione (*) e legge zero o più caratteri rimanenti non nuova riga dall'ingresso. Quando la funzione scanf() completa, l'ingresso è puntato verso il successivo carattere di nuova riga. Il corpo del ciclo legge e stampa quel personaggio, in modo che quando il riavvio del ciclo, l'ingresso sta guardando l'inizio della riga successiva. Il processo si ripete poi. Se la linea è più corta di 10 caratteri, quindi tali caratteri vengono copiate nel buffer, e il formato delle 'zero o più non newlines' processi di zero non nuove righe.

Altri suggerimenti

I costrutti come %[a] e %[^a] esistono in modo che scanf() possono essere usate come una sorta di analizzatore lessicale. Questi sono specie di %s, ma invece di raccogliere un arco di altrettanti caratteri "filante" possibile, raccolgono solo un arco di caratteri come descritto dalla classe di caratteri. Ci potrebbero essere casi in cui la scrittura %[a-zA-Z0-9] potrebbe avere un senso, ma non sono sicuro che vedo un caso d'uso convincente per le classi complementari con scanf().

IMHO, scanf() non è semplicemente lo strumento giusto per questo lavoro. Ogni volta che ho deciso di utilizzare una delle sue caratteristiche più potenti, ho finito alla fine strappa e all'attuazione della capacità in un modo diverso. In alcuni casi, che significava utilizzare lex di scrivere un vero e proprio analizzatore lessicale, ma di solito facendo riga alla volta di I / O e la rottura grossolanamente in token con strtok() prima di fare la conversione del valore è stato sufficiente.

Modifica ho finito strappandogli scanf() genere perché di fronte a utenti insistere sulla fornitura di input corretto, semplicemente non è bravo a aiutare il programma di dare un buon feedback in merito al problema, e avere un assemblatore print "Errore, terminato". come unico messaggio di errore non è stato utile andare oltre bene con il mio utente. (Me, in questo caso).

E 'come i set di caratteri da espressioni regolari; [0-9] corrisponde a una stringa di cifre, [^aeiou] corrisponde a tutto ciò che non è una vocale minuscola, ecc.

Ci sono tutti i tipi di usi, come ad esempio tirando fuori i numeri, identificatori, pezzi di spazi bianchi, ecc.

Si può leggere su di esso nel ISO / IEC9899 standard disponibile on-line.

Ecco un paragrafo Cito dal documento circa [ (Pagina 286):

  

Partite una sequenza non vuota di caratteri da un insieme di attesa   caratteri.

     

L'indicatore di conversione comprende tutti i caratteri successivi della   stringa di formato, fino ad includere la staffa destra corrispondente (]). Il   caratteri tra le parentesi (Scanlist) compongono la scanset,   a meno che il carattere dopo la parentesi di sinistra è un accento circonflesso (^), in   qual caso lo scanset contiene tutti i caratteri che non compaiono in   la lista di scansione tra l'accento circonflesso e la staffa destra. Se la   conversione specificatore inizia con [] o [^], la staffa di destra   personaggio è nella lista di scansione e il successivo parentesi destra   carattere è la staffa destra corrispondenza che termina la specifica;   altrimenti la prima seguente carattere parentesi destra è quella che   termina la specifica. Se un - carattere è nella lista di scansione e non è   il primo, né il secondo in cui il primo carattere è un ^, né la   ultimo carattere, il comportamento è definito dall'implementazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top