9

具体来说,此处的代码示例效果很好,但仅当字符串存储在文件中时。

有时我需要它来处理生成的字符串(存储在字符串变量中),但我无法说服 fgets 的第三个参数使用字符串变量,因为它是指向 FILE 结构的指针

或者也许有一个与 fgets 等效的功能可以用于字符串?

有什么建议么?谢谢!

4

7 回答 7

10

本着拼凑快速答案的精神,这里是我刚刚写的“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 );
}
于 2010-01-15T03:15:26.193 回答
4

标准 C 库不提供该功能。

但是 AT&T 的安全/快速 I/O 库确实启用了内存流,并且还提供了包装代码以使用 FILE API 及其扩展。最后一次更新是从 2005 年 2 月开始的,所以他们要么终于解决了所有的错误,要么现在卢克威尔逊在工资单上,他们再也负担不起维护它了:-(

包可以在这里下载

于 2010-01-15T02:06:02.377 回答
3

sscanf应该这样做。当然语义不同。

于 2010-01-15T02:07:08.687 回答
3

使用管道,然后打开管道fdopen以获得 a 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;
}
于 2010-01-15T03:32:49.033 回答
2

If the string is already in memory, you could tokenize on newlines (either with strtok if you're okay with mutating the string and if don't need to worry about re-entrancy, or by manually using strchr and copying to a separate buffer yourself).

You wouldn't get platform-dependent newline conversion that the stdio functions would normally give you, however, so some extra care would be needed if your strings in memory use, say, CRLF line terminators.

于 2010-01-15T02:45:38.660 回答
1

您需要做的就是对字符串中的行尾执行线性搜索。这是一个小程序,可帮助您开始编写自己的字符串流类。

#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;
}
于 2010-01-15T03:01:54.473 回答
0

我修改了 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 
于 2014-01-04T11:03:34.407 回答