Strumień wejściowy stdin i ponowne jego wykorzystanie

0

Mam problem ze strumieniem wejściowym, otóż drugie wykorzystanie strumienia "stdin" nic nie wypluwa. W związku z tym funkcja fgetc po odczytaniu znaku chyba kasuje lub usuwa cyklicznie dane z bufora/strumienia. Problem polega na tym, że chce policzyć ile w strumieniu wejściowym jest wierszy i później zaalokować pamięć na wskaźnik do wskaźników aby zapisać tam poszczególne linie wykorzystując funkcję getline(). Tak więc muszę 2X "przelecieć" strumień ;)
Podaje kod:

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


int main(int argc, const char* argv[]) {


	size_t total = 0;
	size_t sizeline = 0;
	char** lines = NULL;
	int f = 0;
	int i = 0;
	int n = 0;
	char c = 0;

	while(!feof(stdin)) {
		c = fgetc(stdin);
		if(c == '\n')
			++i;
	}

	fseek(stdin, 0, 0);
// rewind(stdin);

	printf("Allocated memory for pointer to pointers: %i\n", i);
	printf("Size of pointer: %lu\n", sizeof(char*));
	lines = (char**)malloc(i * sizeof(char*));
	i = 0;

	while(!(f = feof(stdin))) {

		sizeline = getline(lines + i, &total, stdin);
		printf("number: %i | sizeline: %lu | total: %lu | value: %s\n", i, sizeline, total, *(lines+i));
		// remove end of line
		lines[i][strlen(lines[i]) - 1] = 0;
		if(strcmp("!quit", *(lines + i)) == 0)
			break;

		++i;
	}

	while(n < i) {
		printf("%s\n", *(lines+n));
		if(*(lines+n) != NULL)
			free(*(lines+n));
		++n;
	}


	free(lines);

	return 0;


}

0
  1. Twój pomysł 2 krotnego lecenia jest głupi.
  2. EndOfFile. Co chcesz czytać, jak już nie ma?
0

To jest nie istotne czy jest glupi mi chodzi o to co sie dzieje ze strumieniem przewinac na poczatek nie moge to nic nie daje. Takie kwestie robie "na nie na glupio" przez dynamiczne zwiekszanie wskaznika do wskaznika no ale mnie interesuje ten konkretny przypadek.

0
macsurf napisał(a):

Problem polega na tym, że chce policzyć ile w strumieniu wejściowym jest wierszy i później zaalokować pamięć na wskaźnik do wskaźników aby zapisać tam poszczególne linie wykorzystując funkcję getline(). Tak więc muszę 2X "przelecieć" strumień ;)

Możesz raz, ale innym sposobem. Wykorzystaj tutaj listę dwukierunkową i dopiero podczas czytania ze standardowego strumienia umieszczaj w niej poszczególne linie. Może pomoże Ci ten mały przykład poniżej:

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

#define BUFFER_SIZE 256

struct Node
{
	char line[BUFFER_SIZE];
	struct Node* next;
	struct Node* prev;
};

struct List
{
	struct Node* head;
	struct Node* tail;
	size_t size;
};

struct Node* createNode(const char line[BUFFER_SIZE], struct Node* parentNode)
{
	struct Node* node = malloc(sizeof(struct Node));

	strcpy(node->line, line);
	node->next = NULL;
	node->prev = parentNode;

	if(parentNode != NULL)
	{
		parentNode->next = node;
	}

	return node;
}

void addLineToList(struct List* list, const char line[BUFFER_SIZE])
{
	list->tail = (list->head == NULL) ? list->head = createNode(line, NULL) : createNode(line, list->tail);
	++list->size;
}

void printList(struct List* list)
{
	struct Node* node = list->head;

	printf("Lines: %u\n", list->size);

	while(node)
	{
		printf("Line: %s", node->line);
		node = node->next;
	}
}

void deleteList(struct List* list)
{
	struct Node* node = list->tail;

	while(node)
	{
		struct Node* prevNode = node->prev;

		free(node);
		node = prevNode;
	}
}

void addLinesToList(struct List* list, FILE* file)
{
	char text[BUFFER_SIZE];

	while(fgets(text, BUFFER_SIZE, file) != NULL)
	{
		addLineToList(list, text);
	}
}

int main()
{
	struct List lineList = { NULL, NULL, 0u };

	//addLinesToList(&lineList, fopen("data.txt", "r"));
	addLinesToList(&lineList, stdin);
	printList(&lineList);
	deleteList(&lineList);

	return 0;
}

https://ideone.com/A4oAoZ

0

Zgadza się ale to tylko zmiana struktury przechowującej linie ze strumienia, myślałem na przekierowaniu strumienia do pliku poprzez funkcję freopen(), bo jednak to co wydedukowałem jest prawdziwe, czytanie z stdin powoduje, że nie można odczytać go ponownie bo jest już pusty. Co innego jeśli strumień odczytujemy z pliku wtedy oczywiście nie ma problemu, aby wskaźnik przestawić na początek. Zresztą z freopen() jakoś mi nie wychodzi.

0

Sam sobie utrudniasz.
Czytaj strumieniowo odpowiednio allokuj pamięć:

char line[512];
int linesMaxCount = 128;
int linesCount = 0;
char **lines = (char **)malloc(sizeof(char *)*linesMaxCount);
while (fgets(line, sizeof(line), stdin)!=NULL) {
     if (linesCount==linesMaxCount) {
           linesMaxCount += 128;
           lines = realloc(lines, sizeof(char *)*linesMaxCount);
     }
     lines[linesCount] = (char *)malloc(sizeof(char)*(strlen(line)+1));
     strcpy(lines[linesCount], line);
     ++linesCount;
}
0

Ale o tym już pisałem, to akurat nie jest żadna filozofia :) Można też zapisać do pliku tymczasowego i tam obliczyć ile jest linii i raz przydzielić pamięć dla konkretnej ilości linii. Niestety stdin nie można ponownie odczytać tak więc zostają te rozwiązania o których tutaj wspomnieliśmy. Chyba, że są jeszcze jakieś sztuczki o których nie wiem :)

0

A przypadkiem nie chodzi Ci o ungetc ?

1 użytkowników online, w tym zalogowanych: 0, gości: 1