Desvendando o Código: Aprenda a Ler Linhas Aleatórias de um Arquivo em C!
Recentemente, retomei meus estudos em C e, desta vez, decidi criar um projeto prático para aprender os conceitos da linguagem à medida que surgiam. Optei por desenvolver um simples jogo de forca para ser jogado via linha de comando.
Após concluir todo o sistema, que pode ser visualizado em um repositório no meu GitHub, decidi que a palavra a ser adivinhada deveria ser escolhida aleatoriamente e sempre ser diferente a cada jogo. Inicialmente, considerei consultar uma API (ou até mesmo criar uma, se necessário) para obter uma palavra sempre que possível. No entanto, acabei optando por uma abordagem mais simples.
Então, vamos lá.
Lendo uma arquivo em C
Na linguagem C, para ler um arquivo, usamos a função fopen
, que está definida em stdio.h
, e que retorna um ponteiro para uma estrutura de dados mantida pelo sistema operacional, representando o arquivo aberto.
E ao final, usamos fclose
para fechar corretamente o arquivo, liberar memória se necessário e permitir que outros processos possam utilizar o mesmo arquivo sem problemas.
Isso é feito da seguinte forma:
int main()
{
FILE *file;
file = fopen("palavras.txt", "r");
if (file == NULL)
{
fprintf(stderr, "Error when trying to read file.\n");
return 1;
}
fclose(file);
return 0;
}
É sempre uma boa prática lidar com tratamento de erros. Por esse motivo, exibo uma mensagem de erro caso o ponteiro FILE
seja igual a NULL
, o que ocorre se houver algum problema na leitura ou se o arquivo não existir.
Contando o número de linhas
Para ler uma linha aleatória, precisamos primeiro determinar quantas linhas existem no arquivo para escolher um número de linha aleatório válido. Isso pode ser feito na própria função main, mas também podemos criar uma função separada para isso.
int countLines(FILE *file)
{
int count = 0;
int caractere;
while ((caractere = fgetc(file)) != EOF)
{
if (caractere == '\n')
{
count++;
}
}
rewind(file);
return count;
}
Nessa função, recebemos como argumento um ponteiro para FILE
e retornamos um inteiro que representa o número de linhas no arquivo.
Dentro da função, criamos duas variáveis: count
, que armazenará o total de linhas, e caractere
, uma variável temporária para armazenar cada caractere do texto para realizar as verificações necessárias.
Em seguida, usamos um laço de repetição while
para ler cada caractere do texto usando a função fgetc
e verificar se o caractere é diferente do marcador que indica o fim do arquivo, representado pela constante EOF
. Se o caractere lido for o marcador de fim de arquivo, o laço é encerrado.
Dentro do laço while
, verificamos se cada caractere é um caractere de quebra de linha (\n
). Se for, incrementamos a variável que representa o total de linhas.
Após verificar cada caractere, o ponteiro do arquivo estará no final. Portanto, utilizamos a função rewind
para voltar o ponteiro para o início do arquivo.
Finalmente, retornamos a variável count
, que agora contém o total de linhas no arquivo.
Gerando um número (pseudo) aleatório
Agora que sabemos quantas linhas existem no arquivo, podemos gerar um número aleatório apropriado. No entanto, antes disso, é crucial definir uma semente de geração apropriada para garantir que o número gerado seja sempre diferente em cada inicialização do programa.
Para isso, utilizamos a função srand
, definida em stdlib.h
, e passamos o tempo atual do sistema usando a função time
(definida em time.h
) como parâmetro, utilizando NULL
. Essa etapa pode ser realizada na própria função main
, logo no início do programa.
...
int main()
{
+ srand(time(NULL));
FILE *file;
file = fopen("palavras.txt", "r");
if (file == NULL)
{
fprintf(stderr, "Error when trying to read file.\n");
return 1;
}
fclose(file);
return 0;
}
Vamos criar as variáveis que representarão a linha escolhida e a linha aleatória. Para isso, usaremos a função rand
, que gera um número aleatório entre 0 e RAND_MAX
(uma constante definida pelo sistema que representa o maior número possível que pode ser gerado aleatoriamente). No entanto, para garantir que o número fique entre 1 e o número total de linhas, precisaremos fazer alguns ajustes. Veja como fazer isso:
...
int main()
{
srand(time(NULL));
FILE *file;
file = fopen("palavras.txt", "r");
if (file == NULL)
{
fprintf(stderr, "Error when trying to read file.\n");
return 1;
}
+ int lines = countLines(file);
+ int randomLine = rand() % lines + 1;
fclose(file);
return 0;
}
Basicamente, restringimos o número aleatório entre 0 e o número total de linhas usando o operador de módulo da divisão e, em seguida, adicionamos 1 ao resultado para que o valor comece a partir da primeira linha.
Lendo a linha aleatória
Agora que temos todas as variáveis definidas, podemos percorrer o arquivo novamente até alcançar a linha definida e ler o seu valor.
+#define MAX_LINE_LEN 100
...
int main()
{
srand(time(NULL));
FILE *file;
file = fopen("palavras.txt", "r");
if (file == NULL)
{
fprintf(stderr, "Error when trying to read file.\n");
return 1;
}
int lines = countLines(file);
int randomLine = rand() % lines + 1;
+ char line[MAX_LINE_LEN];
+ int count = 0;
+ while (count < randomLine && fgets(line, MAX_LINE_LEN, file) != NULL)
+ {
+ count++;
+ }
+ printf("Linha aleatória: %s\n", line);
fclose(file);
return 0;
}
Neste código, criamos uma variável do tipo array de caracteres para armazenar o valor da linha. Esperamos que cada linha tenha até 100 caracteres. Caso contrário, você pode ajustar esse valor na definição da constante MAX_LINE_LEN
.
Em seguida, criamos uma variável inteira para armazenar a contagem de linhas. No loop while
, verificamos se a contagem é menor que a linha escolhida. Se for, continuamos lendo as linhas. Quando chegamos à linha escolhida, lemos o valor dela.
No mesmo loop while
, utilizamos a comparação fgets(line, MAX_LINE_LEN, file) != NULL
para ler a linha inteira, adicionar o conteúdo na variável line
, e verificar se o conteúdo é diferente de NULL
. Se for NULL
, chegamos ao final do arquivo, e o valor da variável line
será o conteúdo da última linha.
Ao final, esse será o nosso código:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_LINE_LEN 100
int countLines(FILE *file)
{
int count = 0;
int caractere;
while ((caractere = fgetc(file)) != EOF)
{
if (caractere == '\n')
{
count++;
}
}
rewind(file);
return count;
}
int main()
{
srand(time(NULL));
FILE *file;
file = fopen("palavras.txt", "r");
if (file == NULL)
{
fprintf(stderr, "Error when trying to read file.\n");
return 1;
}
int lines = countLines(file);
int randomLine = rand() % lines + 1;
char line[MAX_LINE_LEN];
int count = 0;
while (count < randomLine && fgets(line, MAX_LINE_LEN, file) != NULL)
{
count++;
}
printf("Linha aleatória: %s\n", line);
fclose(file);
return 0;
}
Agora basta criar um arquivo palavras.txt
, com pelo menos uma palavra, no mesmo diretório que o seu arquivo C, compilar e rodar o seu programa.
Caso você queira ver o meu jogo da forca, basta acessar esse repositório.
Este foi um pequeno exemplo de um programa escrito na linguagem C. O objetivo é apresentar um pouco mais desta linguagem e mostrar como alguns problemas podem ser resolvidos de forma fácil se entendermos a lógica por trás.
Até a próxima e obrigado pelos peixes!