paulo1205
(usa Ubuntu)
Enviado em 31/10/2013 - 16:15h
ianclever escreveu:
eu li seus comentários, e sim no caso o certo mesmo seria usar o do while, não sei se vc percebeu, para vc q já tem mais experiência pode até parecer bobagem,
Eu sei que você é iniciante, sim. Não o recrimino, nem a qualquer outra pessoa que venha aqui, por ser iniciante. Penso que o tempo gasto e a quantidade e qualidade de dicas que estou dando a você ao longo da discussão deveria ser um indicativo claro justamente de estímulo, não de recriminação.
Aliás, é justamente por você ser um iniciante que, entre minhas dicas, incluo várias recomendações para que você se afaste desde cedo de vícios de programação que podem lhe causar problemas mais a frente, principalmente na medida em que o tamanho dos seus programas crescer (sem exagero, se você seguir carreira na área, logo, logo seus programas terão alguns, ou mesmo muitos, milhares de linhas).
Como programador ou analista, você tem de saber compreender o problema como um todo e usar a técnica de ir dividindo, em etapas sucessivas, o problema em partes cada vez menores, identificando eliminando/agrupando possíveis redundâncias ao longo do processo, até chegar ao nível de instruções diretamente mapeáveis num programa. Só que
compete também a você conhecer as ferramentas de trabalho a sua disposição (i.e. as linguagens de programação, técnicas de codificação, padrões de projeto, ambientes de desenvolvimento, sistemas operacionais etc.), justamente para que o mapeamento de instruções seja feito da forma mais simples e eficiente possível.
mas, eu estou usando o while, pq eu não sei fazer uma forma mais compacta que o getchar para abrir o stdin para escrita(e sem dar bug), eu até pensei de abrir ele para leitura ou reabrir com freopen, só que eu não sei como retornar ele ao estado que ele estava antes de eu alterar, por isso eu usei o getchar para abrir o stdin para escrita, literalmente sujar o buffer, pegar o primeiro caractere, e depois o resto(se houver) com fgetc,pq o fgetc já pré supõe que eu tenha algo no stdin, se não tiver ele não vai ler nada(me corrija se eu estiver errado), e o que eu quero é abrir o stdin para eu escrever diretamente até que eu pressione enter e depois ler o que ficou lá.
se eu colocasse o getchar dentro do while ou do while ou for, ele vai abrir o stdin para eu digitar todas as vezes que passar no laço e não é isso que eu quero.
Como assim "abrir o stdin para escrita"? Nem
getchar () nem
fgetc () "abrem" coisa alguma, mas ambas consomem dados de um
stream de leitura previamente aberto.
stdin é um
stream de leitura global (uma variável global declarada em <stdio.h> e implementada pela biblioteca padrão) que o ambiente de execução de um programa em C abre automaticamente, e apenas uma vez, cada vez que o programa é executado, antes mesmo de se iniciar a execução de
main (). Por sua vez,
getchar() é um sinônimo de fgetc(stdin) .
Assim sendo, nada do que você disse no parágrafo anterior faz muito sentido.
Que material você está usando para aprender C? Talvez você tenha de trocar para algo melhor.
agora quanto a duplicação na verdade mesmo eu particularmente prefiro o \n longe da string em si, so coloquei ali pq vc mencionou o caso de alguém querer usa-lo, eu prefiro formatar do jeito que eu quero por fora mesmo, posso estar enganado, mas no meu caso caso(que não quero o \n) apesar de ser uma real perda de dados ignorar o \n, não seria menos trabalhoso(computacionalmente falando) já ignorá-lo direto no laço ao invés de adicioná-lo a string, alocar espaço para ele, depois criar outro laço procurar por ele remover, e realocar o espaço?
Como eu disse anteriormente, ter a marca de fim de linha é importante para saber se houve truncamento ou interrupção prematura do fluxo de leitura.
Imagine uma aplicação que leia um arquivo linha a linha e grave as linhas lidas num outro arquivo. Ela poderia ser grosseiramente implementada de um dos dos modos abaixo.
/* Modo 1: com uma função de leitura que retém o '\n'. */
char *line;
/* Usa o areadline() que eu implementei acima. */
while((line=areadline(input_file))!=NULL){
fputs(line, output_file);
free(line);
}
/* Modo 2: com uma função de leitura que descarta o '\n'. */
char *line;
/* Usa a areadline_nonl() que eu implementei acima. */
while((line=areadline_nonl(input_file))!=NULL){
fprintf(output_file, "%s\n", line);
free(line);
}
Pouca diferença, não é? O segundo código tem de forçar a impressão do '\n' ao final de cada linha. Mas isso implica que, se o arquivo de origem não tiver a marca de fim de linha na última linha do arquivo, o primeiro programa produz um arquivo de saída idêntico ao de entrada, ao passo que o segundo programa não teria como o fazer.
(Eu reconheço que o exemplo é simplório -- mas, por isso mesmo, penso que ele é bastante didático. Você poderia tentar fazer "bruxarias" com
feof (),
ferror () e a variável global
errno para tentar adivinhar se deveria ou não incluir o '\n' no arquivo de saída, mas receio que nunca teria total certeza de estar acertando na adivinhação. E você teria um código certamente muito mais comprido do que apenas 5 linhas (descontando as de comentários).)
Funções de bibliotecas são normalmente pensadas para ser tão úteis quanto possível, minimizando ao máximo a possibilidade produzir resultados errados. Pode parecer chocante a princípio, mas reter o '\n' dá mais chances de produzir resultados corretos do que a opção de descartá-lo.
Eu já estive no seu lugar. É óbvio que eu não nasci sabendo. Quando eu fazia um programa que tinha de ler textos de arquivos, eu achava "um saco" o fato de
fgets () reter o '\n', obrigando-me a extirpá-lo manualmente. Por que ela não era mais parecida com
gets ()? Eu preferia apelar a
fscanf () ou reimplementar, como você mesmo está fazendo ao longo desta discussão, uma "
gets () só minha para arquivos". Invariavelmente, eu tinha sempre muito mais trabalho reinventando a roda e caçando
bugs -- até porque eu não dominava as ferramentas ao meu alcance -- do que teria tido simplesmente escrevendo algo como a
chop_nl () que mostrei acima e usando-a nos lugares em que fosse necessária.
Depois eu compreendi -- claro que por "iluminação" recebida de terceiros mais experientes do que eu -- que a própria
gets () era uma aberração de segurança e exemplo máximo de péssimo projeto -- tanto que ela foi finalmente removida da última versão do padrão do C, de 2011. Para produzir programas mais seguros, tive de parar de usá-la até mesmo para ler de
stdin . E aí mesmo é que eu passei um tempo penando com minhas reinvenções da roda, pois aos
bugs de antes somavam-se agora os problemas de "lixo no
buffer ". Só com o tempo, e depois de muita cabeçada, eu constatei que
fgets () teria sido a melhor resposta desde o começo.
se eu for lendo do stdin direto com fgetc, fgets, etc. sem adicionar nada a ele não vai ler algo e vai me retornar ou EOF ou outra coisa do tipo?
Não compreendi o que você tentou dizer. Adicionar o quê a
stdin , e como?
pois é no caso quando eu postei a pergunta sobre o fgets, eu não sabia que ele era usado para ler arquivos e que fgets(string,tamanho,stdin) na verdade esta lendo de um stream chamado stdin(que no meu caso é o teclado), aí vc me falou do parâmetro %m do scanf, que fazia exatamente o que eu queria, a função que eu quero implementar não é uma função complexa para ler de diversas streams ou arquivos, eu quero somente ler uma string dinâmicamente( digitar uma string do tamanho que eu quiser sem passar o tamanho préviamente e ao final isso vai me retornar um vetor de char funcional(com \ 0 e tudo) , e que funcione tanto em GNU/Linux quanto em Windows, etc. ou seja a mesma coisa que o scanf("%m",&variavel); faria, com isso deixaria de ser uma particularidade só do GNU/Linux, pq como eu já disse até então não se tem( pelo menos eu não conheço)uma função pronta que faça isso no Windows, e muitos colegas meus la da faculdade usam esse maldito sistema, e esse problema já tem tomado muito tempo das aulas com uma coisa simples dessas, por isso eu resolvi acabar com esse problema, quando tiver 100% a função eu vou passar para todos lá da sala para acabar com esse problema e podermos nos preocupar com o que realmente interessa, por isso eu queria adicioná-lo a uma biblioteca, não precisa ser a padrão(obrigado pela correção eu falei besteira mesmo), mas uma biblioteca que seja reconhecida quando eu der um #include <biblioteca.h>
Eu entendo perfeitamente sua necessidade. Acho que quase todo mundo que trabalhou com strings em C já passou por isso.
Ao longo deste tópico eu mostrei duas soluções prontas para você ler e tentar entender:
my_fgets () e
areadline (). As duas funcionariam muito bem no Windows, também. Eu não quero sugerir que você as use de pronto, mas que as leia e procure compreendê-la totalmente, pois ambas têm coisas a lhe ensinar.
eu nunca criei uma biblioteca então não tenho noção de como mandar essa função para uma, e nem onde colocar essa biblioteca(vou dar uma pesquisada, mas aceito sugestões).
Uma biblioteca é simplesmente uma coleção de objetos pré-compilados que podem ser agregados ao seu programa. Procure ler sobre compilação em separado (
separate compilation ) e arquivos objeto (
object files ).
Existem vários tutoriais sobre criação de bibliotecas na Web. Googlando, achei este aqui (http://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html), que me pareceu razoável.