2010-01-15 7 views
7

In particolare, il codice di esempio here funziona in modo ottimale, ma solo quando la stringa è archiviata in un file.I file di Can C possono essere persuasi a lavorare con una stringa * non * da un file?

A volte ho bisogno di elaborare una stringa generata (memorizzata in una variabile stringa), ma ho difficoltà a convincere il terzo parametro di fgets a lavorare con variabili stringa perché è a pointer to a FILE structure.

O forse c'è un equivalente funzionale a fget che può essere utilizzato sulle stringhe?

Qualche suggerimento? Grazie!

+1

stai bene con la stringa di essere modificato? –

+0

Credo di si. Ho solo bisogno di un modo per rendere il primo campione di codice che ho collegato per accettare input da un file o da una stringa. –

risposta

9

Nello spirito di hacking insieme risposte rapide, ecco "sgets" che ho appena scritto. Tenta di emulare fget ma con input di stringa.

Modifica Risolto un bug rilevato da Monte (grazie). Digitando tipicamente un'utilità mentre si crede che almeno altre 15 persone con la stessa identica idea stiano freneticamente facendo la stessa cosa, non conduce a codice ben collaudato. Bad me. La versione originale includeva il carattere di nuova riga nella chiamata successiva.

char *sgets(char * str, int num, char **input) 
{ 
    char *next = *input; 
    int numread = 0; 

    while (numread + 1 < num && *next) { 
     int isnewline = (*next == '\n'); 
     *str++ = *next++; 
     numread++; 
     // newline terminates the line but is included 
     if (isnewline) 
      break; 
    } 

    if (numread == 0) 
     return NULL; // "eof" 

    // must have hit the null terminator or end of line 
    *str = '\0'; // null terminate this tring 
    // set up input for next call 
    *input = next; 
    return str; 
} 


int main(int argc, char* argv[]) 
{ 
    // quick and dirty test 
    char *str = "abc\ndefghitjklksd\na\n12345\n12345\n123456\nabc\n\n"; 
    char buf[5]; 

    while (sgets(buf, sizeof(buf), &str)) 
     printf("'%s'\n", buf); 
} 
+1

Ottenere un avviso del compilatore strano sulla stringa letterale principale dall'esempio: "avviso: conversione deprecata dalla costante di stringa a" char * "". Google è mio amico, ma non l'ho ancora risolto. Modifica: Sembrerebbe che ho compilato questo come C++, quindi l'avviso. Ma, ancora, per curiosità, sono interessato a come questo sarebbe stato affrontato. –

+0

OK, per la compilazione C++ felicità ho fatto il seguente "const": "char * sgets", "char ** input", "char * next", "char * str". –

+0

Sembra corretto. E hai ragione; L'ho compilato come app di test C quindi non ho notato quegli avvertimenti. –

4

La libreria C standard non fornisce questa funzionalità.

Ma AT & T safe/fast I/O library abilita i flussi di memoria e fornisce anche il codice wrapper per utilizzare l'API FILE con le relative estensioni. L'ultimo aggiornamento è da febbraio 2005 affinché sia ​​finalmente risolti tutti i bug o non possono più permettersi di mantenere, ora che Luke Wilson is on the payroll :-(

il pacchetto può essere downloaded here.

+0

rocce sfio! Joe Bob dice di controllarlo. –

3

sscanf dovrebbe farlo. naturalmente la semantica sono diversi.

+2

Non sscanf si fermerà su uno spazio bianco invece che su una nuova riga? –

2

Se la stringa è già in memoria, si potrebbe tokenize su nuove righe (sia con strtok se stai bene con mutando la stringa e se non c'è bisogno di preoccuparsi di ri-entrancy, o manualmente utilizzando strchr e copiandoli autonomamente in un buffer separato.

Non si otterrebbe la conversione di nuova riga dipendente dalla piattaforma che le funzioni stdio normalmente forniranno, tuttavia, sarebbe necessario prestare maggiore attenzione se le stringhe in memoria utilizzano, ad esempio, terminatori di riga CRLF.

1

Tutto ciò che devi fare è eseguire una ricerca lineare per le terminazioni di riga nella stringa. Ecco un piccolo programma per iniziare a scrivere la tua classe di streaming di stringhe.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

typedef struct StringStream StringStream; 

struct StringStream { 
    const char *data; 
    const char *position; 
}; 

StringStream * 
stringstream_new(const char *data) 
{ 
    StringStream *self = malloc(sizeof (StringStream)); 

    self->data = self->position = data; 

    return self; 
} 

void 
stringstream_delete(StringStream *self) 
{ 
    free(self); 
} 

char * 
stringstream_gets(char *s, int n, StringStream *self) 
{ 
    const char * eol; 
    int i, len; 

    if (NULL == self->position || '\0' == *self->position) 
     return NULL; 

    eol = strchr(self->position, '\n'); 

    if (eol) { 
     len = eol - self->position + 1; 
     len = len <= n ? len : n - 1; 

     for (i = 0; i < len; ++i) 
      s[i] = *self->position++; 

    } else { 
     for (i = 0; *self->position && i < n; ++i) 
      s[i] = *self->position++; 
      if ('\0' == *self->position) 
       self->position = NULL; 
      else 
       ++self->position; 
    } 

    s[i] = '\0'; 

    return s; 
} 

int 
main(int argc, char * argv[]) 
{ 
    static const int LEN = 100; 
    static const char TEST_STRING[] = 
     "line 0\n" 
     "line 1\n" 
     "line 2\n" 
     "line 3\n" 
     "line 4\n" 
     "line 5\n" 
     "line 6\n" 
     "line 7\n" 
     "line 8\n" 
     "line 9\n"; 

    StringStream *stream; 
    char buf[LEN]; 

    stream = stringstream_new(TEST_STRING); 

    while (stringstream_gets(buf, LEN, stream)) 
     printf("gets: %s\n", buf); 

    stringstream_delete(stream); 

    return 0; 
} 
2

utilizzare un tubo, e quindi aprire il tubo con fdopen per ottenere un FILE *, quindi leggere da questo.


#include <stdio.h> 

int main (int argc, char *argv[]) 
{ 
    int pipes[2]; 
    FILE *write; 
    FILE *read; 
    char buffer[1000]; 

    pipe (pipes); 

    read = fdopen (pipes[0], "r"); 
    write = fdopen (pipes[1], "w"); 
    fputs ("My\nlong\nstring\nin\nmany\nlines\n", write); 
    fclose (write); 

    while (fgets (buffer, sizeof(buffer), read) != NULL) 
    { 
     printf ("Found a line: %s", buffer); 
    } 

    fclose (read); 

    return 0; 
} 
+0

Nessun controllo degli errori e utilizzo di nomi di variabili ambigue, cattivo, cattivo, molto cattivo! (-1) – dreamlax

+0

Cosa succede quando My \ nlong \ nstring \ nspre \ nla \ npipe \ nbuffer? – jhfrontz

+0

@jhfrontz: Il tuo \ nprogramma \ nwill \ nprobabilmente \ nblocco \ nquando \ ncancante \ n 'fputs'. – dreamlax

0

Ho modificato il codice della funzione fgets fonte:

size_t my_fgets(inBuf , n , outBuf) 
unsigned char *inBuf; 
size_t n; 
unsigned char *outBuf; 
{ 
    size_t len = 0; 
    unsigned char *s; 
    unsigned char *p, *t; 

    if (n <= 0)    /* sanity check */ 
      return (-1); 

    p = inBuf; 
    s = outBuf; 

    n--;     /* leave space for NUL */ 

    while (n != 0) { 

     len = n; 
     t = memchr((void *)p, '\n', strlen(p)); 

     //printf ("'p' found at position %d.\n", t -p + 1); 

     if (t != NULL) { 
      len = ++t -p; 
      (void)memcpy((void *)s, (void *)p, len); 
      s[len] = 0; 
      return len; 
     } 

     (void)memcpy((void *)s, (void *)p, len); 
     s += len; 
     n -= len; 

    } 

    *s = 0; 

    return len; 

} 

e funzione principale:

int main(void) 
{ 
    char *inBuf = "this \n" 
        "is \n" 
        "test \n"; 

    char outBuf[1024]; 

    my_fgets(inBuf,strlen(inBuf),outBuf); 
    printf("outBuf:%s \n",outBuf); 

    return 0; 
} 

e uscita:

outBuf:this 
Problemi correlati