[英]Can C's fgets be coaxed to work with a string *not* from a file?
具体来说, 此处的代码示例效果很好,但仅当字符串存储在文件中时才有效。
有时我需要它来处理生成的字符串(存储在字符串变量中),但是我无法说服fgets的第三个参数来处理字符串变量,因为它是指向FILE结构的指针 。
或者也许有一个功能相当于可以在字符串上使用的fgets?
有什么建议? 谢谢!
本着劈砍快速答案的精神,这里是我刚写的“sgets”。 它试图模拟fgets但使用字符串输入。
编辑修复了Monte指出的错误(谢谢)。 疯狂地输入一个实用程序,同时认为至少有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 );
}
标准C库不提供该功能。
但AT&T的安全/快速I / O库确实启用了内存流,并提供了使用FILE API及其扩展的包装代码。 最后一次更新是从2005年2月开始的,所以要么他们最终解决了所有的错误,要么现在卢克·威尔逊在工资单上就不能维持它:-(
包可以在这里下载 。
sscanf应该这样做。 当然,语义是不同的。
如果字符串已在内存中,你可以记号化的换行符(或者使用strtok
,如果你没事与变异的字符串,如果不需要担心重入,或使用手动strchr
和复制到一个单独的缓冲区你自己)。
你不会得到stdio函数通常会给你的平台相关换行转换,但是,如果内存中的字符串使用CRLF行终止符,则需要特别小心。
使用管道,然后使用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;
}
您需要做的就是对字符串中的行结尾执行线性搜索。 这是一个小程序,可以帮助您开始编写自己的字符串流类。
#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;
}
我修改了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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.