Можно ли уговорить f C'а работать со строкой * не * из файла? - PullRequest
8 голосов
/ 15 января 2010

В частности, пример кода здесь прекрасно работает, но только когда строка хранится в файле.

Иногда мне нужно обрабатывать сгенерированную строку (хранящуюся в строковой переменной), но у меня возникают проблемы при убеждении третьего параметра fgets для работы со строковыми переменными, поскольку это указатель на структуру FILE .

Или, может быть, есть функциональный эквивалент fgets, который можно использовать со строками?

Есть предложения? Спасибо!

Ответы [ 7 ]

9 голосов
/ 15 января 2010

В духе взлома быстрых ответов, вот "sgets", которые я только что написал. Он пытается эмулировать fgets, но со строковым вводом.

Редактировать Исправлена ​​ошибка, на которую указывал Монте (спасибо). Безумно печатая утилиту, полагая, что по крайней мере 15 других людей с точно такой же идеей отчаянно делают то же самое, это не приводит к хорошо протестированному коду. Плохо мне. Исходная версия включала символ новой строки в последующем вызове.

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 );
}
4 голосов
/ 15 января 2010

Стандартная библиотека C не обеспечивает эту функциональность.

Но библиотека AT & T safe / fast I / O разрешает потоки памяти, а также предоставляет код оболочки для использования FILE API с их расширениями. Последнее обновление относится к февралю 2005 года, поэтому либо они наконец-то исправили все ошибки, либо они больше не могут позволить себе их поддерживать сейчас, когда Люк Уилсон находится в платежной ведомости : - (

Пакет можно скачать здесь .

3 голосов
/ 15 января 2010

sscanf должен это сделать. Конечно, семантика различна.

2 голосов
/ 15 января 2010

Используйте трубу, а затем откройте трубу с помощью fdopen, чтобы получить FILE *, затем прочитайте из нее.


#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;
}
2 голосов
/ 15 января 2010

Если строка уже находится в памяти, вы можете токенизировать символы новой строки (либо с помощью strtok, если у вас все в порядке с изменением строки и если вам не нужно беспокоиться о повторном входе, либо вручную с помощью strchr и копирование в отдельный буфер самостоятельно.)

Однако вы не получите зависящее от платформы преобразование новой строки, которое обычно предоставляют функции stdio, поэтому потребуется некоторая дополнительная осторожность, если ваши строки в памяти используют, скажем, терминаторы строки CRLF.

1 голос
/ 15 января 2010

Все, что вам нужно сделать, это выполнить линейный поиск концов строк в строке. Вот небольшая программа, которая поможет вам начать писать собственный класс потоковой передачи.

#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;
}
0 голосов
/ 04 января 2014

я изменил исходный код функции fgets:

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;

}

и основная функция:

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;
}

и вывод:

outBuf:this 
...