paulo1205
(usa Ubuntu)
Enviado em 17/09/2013 - 05:41h
ianclever escreveu:
gente é o seguinte, eu já estou de saco cheio de ter que criar uma variável(vetor) string, para depois ter que ler com fgets, ou getchar, ou gets, ou qualquer outra coisa assim, então quero dar uma melhorada nessa função e fazẽ-la alocar isso dinâmicamente em tempo de execução, mas para não precisar reinventar a roda eu quero melhorar da parte que já existe, eu quero saber se alguém tem o código completo da função fgets, já que na biblioteca stdio só tem o protótipo, tá la assim:
extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream);
onde eu acho a função completa? alguma dica?
Se você quer uma função que aloque memória dinamicamente na entrada, pode usar, no Linux, a própria
scanf (), pois a GNU LibC (glibc) implementa uma extensão que faz a alocação de ponteiros de caracteres na leitura de strings, por meio do modificador "m", aplicado às conversões "%s" ou "%[...]".
O exemplo abaixo deve lhe dar uma ideia de como fazer uma leitura genérica de uma string ocupando uma linha inteira, inclusive mostrando como tratar possíveis entradas inesperadas.
char *line_ptr;
int n, a, b;
a=b=-1;
n=scanf("%m[^\n]%n%*1[\n]%n", &line_ptr, &a, &b);
if(n==1){
/*
Leitura bem sucedida de uma string.
line_ptr recebeu o valor de um de ponteiro alocado com malloc(), que
tem o tamanho suficiente para acomodar todos os caracteres digitados
antes da marca de fim de linha. ESSE PONTEIRO DEVE SER POSTERIORMENTE
LIBERADO ATRAVÉS DE UMA CHAMADA ``free(line_ptr)´´.
*/
/*
Caso interesse, o if abaixo permite saber se o final da leitura se deu
pela presença da marca de fim de linha ou outra causa (que pode ser
fim de arquivo ou erro -- muitos utilitários do UNIX, incluindo wc, grep,
awk e o próprio compilador C, não consideram que a última linha do arquivo
é uma linha completa se faltar o "\n" nessa linha, mesmo sendo a última;
por exemplo, "echo -n OI | wc -l" produz o resultado "0").
*/
if(b>a){
/* Fim de linha foi encontrado. */
}
else{
/*
Fim de linha não encontrado. Toma as providências cabíveis, talvez
usando feof() e ferror().
*/
}
/*
Usa line_ptr.
*/
free(line_ptr); /* <--- MUITO IMPORTANTE!! */
}
else if(n==0){
/*
O usuário digitou uma linha vazia (i.e., teclou <ENTER> sem digitar
coisa alguma.
O ponteiro line_ptr não foi alterado, e portanto não se deve chamar
``free(line_ptr)´´.
*/
}
else if(n==EOF){
/*
Fim de arquivo ou erro de leitura antes mesmo de ler qualquer caráter.
A variável gloval errno (de <errno.h>) contém a causa do erro.
O ponteiro line_ptr não foi alterado, e portanto não se deve chamar
``free(line_ptr)´´.
*/
}
É óbvio o exemplo acima está expandido. Se não lhe interessar testar e tratar todos os possíveis cenários de execução, você pode omitir as partes que não interessarem, tanto do código como da string de formatação de
scanf (). Só não recomendo deixar de testar o valor de retorno, pois é crítico saber se você poderá/deverá chamar free() sobre o ponteiro que poderá ter sido alocado ou não.
O problema com essa abordagem é que ela só funciona na glibc (basicamente no Linux), e somente em versões mais recentes (>= 2.7). Versões um pouco mais antigas da glibc usavam "%as" ou "%a[...]" em lugar de "%ms" e "%m[...]", mas isso foi modificado por causa de confusão com a conversão "%a", especificada pelo padrão ISO C de 1999, que a emprega para ler números de ponto flutuante hexadecimais. Em outros sistemas, é improvável que essa funcionalidade esteja disponível sob qualquer roupagem.
Se você quiser implementar uma coisa nova, minha sugestão é que não toque na implementação da função padronizada
fgets (), mas que, ao invés disso, a utilize como peça na construção da sua nova implementação.