Может ли C fgets уговорить работать со строкой * not * из файла?

124
8

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


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


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


Любые предложения? Спасибо!

спросил(а) 2021-01-25T14:01:54+03:00 4 месяца, 2 недели назад
1
Решение
139

В духе взлома быстрых ответов, вот "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 );
}

ответил(а) 2021-01-25T14:01:54+03:00 4 месяца, 2 недели назад
98

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


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

Пакет может быть загружен здесь.

ответил(а) 2021-01-25T14:01:54+03:00 4 месяца, 2 недели назад
88

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

ответил(а) 2021-01-25T14:01:54+03:00 4 месяца, 2 недели назад
76

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


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

ответил(а) 2021-01-25T14:01:54+03:00 4 месяца, 2 недели назад
77

Используйте трубу, а затем откройте канал с помощью 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;
}

ответил(а) 2021-01-25T14:01:54+03:00 4 месяца, 2 недели назад
63

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


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

ответил(а) 2021-01-25T14:01:54+03:00 4 месяца, 2 недели назад
44

i измененный исходный код функции 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 

ответил(а) 2021-01-25T14:01:54+03:00 4 месяца, 2 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема