3
respostas

[Bug] Escrita no arquivo gerando caracteres Null conforme o número total de palavras ao escrever uma nova palavra

Salve galerinha, estou tendo um bug (mas que não impede nem atrapalha o funcionamento do jogo da forca) onde ao escrever uma nova palavra, ele pula a linha, escreve ela normalmente, mas na frente da palavra anterior, ele adiciona um caractere Nulo * quantidade atual de linhas/palavras no arquivo. Alguém saberia por que isso ocorre, e como posso corrigir esse comportamento?

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Garanta sua matrícula hoje e ganhe + 2 meses grátis

Continue sua jornada tech com ainda mais tempo para aprender e evoluir

Quero aproveitar agora
3 respostas

Olá Murilo! Como vai?

Esse comportamento pode estar ocorrendo devido ao uso do modo de abertura do arquivo e à forma como o ponteiro do arquivo está sendo manipulado. Quando você abre o arquivo no modo "r+", ele permite leitura e escrita, mas não necessariamente posiciona o ponteiro no final do arquivo para a escrita.

Aqui estão algumas sugestões para corrigir o problema:

  1. Verifique o Modo de Abertura do Arquivo:
    Certifique-se de que está usando o modo correto para a operação desejada. Para adicionar ao final do arquivo sem sobrescrever, o modo "a" pode ser mais apropriado, mas como você também precisa ler e modificar o início, o "r+" é necessário.

  2. Manipule o Ponteiro Corretamente:
    Quando você usa fseek(f, 0, SEEK_END);, o ponteiro deve ir para o final do arquivo, mas verifique se isso está sendo feito corretamente antes de fprintf.

  3. Verifique o Uso de fprintf:
    Certifique-se de que está usando o fprintf corretamente para adicionar um \n antes da nova palavra, para garantir que ela seja escrita em uma nova linha.

  4. Verifique o Buffer:
    Pode ser interessante adicionar um fflush(f); após o fprintf para garantir que o buffer seja escrito no arquivo corretamente.

Aqui está um exemplo de como você pode ajustar o código:

void adicionapalavra() {
    char quer;

    printf("Você deseja adicionar uma nova palavra no jogo (S/N)?");
    scanf(" %c", &quer);

    if(quer == 'S') {
        char novapalavra[20];

        printf("Digite a nova palavra, em letras maiúsculas: ");
        scanf("%s", novapalavra);

        FILE* f;

        f = fopen("palavras.txt", "r+");
        if(f == 0) {
            printf("Banco de dados de palavras não disponível\n\n");
            exit(1);
        }

        int qtd;
        fscanf(f, "%d", &qtd);
        qtd++;
        fseek(f, 0, SEEK_SET);
        fprintf(f, "%d", qtd);

        fseek(f, 0, SEEK_END);
        fprintf(f, "\n%s", novapalavra);

        fclose(f);
    }
}

Espero que isso ajude a resolver o problema dos caracteres nulos. Bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Boa noite, estou seguindo conforme o código do curso mesmo, mas tentei aplicar também suas sugestões, e não rolou :/

Oi, Murilo!

Certo, então tente resolver escrevendo sempre em modo texto e regravando o arquivo inteiro ao atualizar o cabeçalho (quantidade de palavras). Use fprintf/fputs (e não fwrite de buffers fixos) e evite fseek além do fim.

Ajuste seu código assim:


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

#define MAXPAL  64
#define LINHA   256

// Lê todas as palavras (ignorando a 1ª linha do contador)
static size_t ler_palavras(const char *path, char ***out) {
    FILE *f = fopen(path, "r");
    if (!f) return 0;

    char **v = NULL;
    size_t n = 0, cap = 0;
    char linha[LINHA];

    // descarta a 1ª linha (contador)
    if (!fgets(linha, sizeof(linha), f)) { fclose(f); return 0; }

    while (fgets(linha, sizeof(linha), f)) {
        // remove \r\n
        linha[strcspn(linha, "\r\n")] = '\0';
        if (*linha == '\0') continue;

        if (n == cap) {
            cap = cap ? cap * 2 : 16;
            char **nv = realloc(v, cap * sizeof(*nv));
            if (!nv) { fclose(f); free(v); return 0; }
            v = nv;
        }
        v[n] = strdup(linha);
        if (!v[n]) { fclose(f); for (size_t i=0;i<n;i++) free(v[i]); free(v); return 0; }
        n++;
    }

    fclose(f);
    *out = v;
    return n;
}

// Regrava o arquivo do zero: contador + palavras (texto puro, sem NUL)
static int gravar_tudo(const char *path, char **v, size_t n) {
    FILE *f = fopen(path, "w");  // <-- TRUNCA o arquivo, elimina lixo/NUL
    if (!f) return -1;

    // contador + quebra de linha (garante alinhamento correto)
    if (fprintf(f, "%zu\n", n) < 0) { fclose(f); return -1; }

    for (size_t i = 0; i < n; i++) {
        if (fprintf(f, "%s\n", v[i]) < 0) { fclose(f); return -1; }
    }

    // fflush opcional; fclose já faz flush
    if (fclose(f) != 0) return -1;
    return 0;
}

int adiciona_palavra(const char *path, const char *nova) {
    char **v = NULL;
    size_t n = ler_palavras(path, &v);

    // adiciona no vetor em memória
    char *dup = strdup(nova);
    if (!dup) { for (size_t i=0;i<n;i++) free(v[i]); free(v); return -1; }
    // normaliza quebra de linha se houver
    dup[strcspn(dup, "\r\n")] = '\0';

    // valida tamanho para evitar estouro (opcional)
    if (strlen(dup) == 0 || strlen(dup) > MAXPAL) {
        for (size_t i=0;i<n;i++) free(v[i]); free(v); free(dup);
        return -2; // inválida
    }

    char **nv = realloc(v, (n + 1) * sizeof(*nv));
    if (!nv) { for (size_t i=0;i<n;i++) free(v[i]); free(v); free(dup); return -1; }
    v = nv;
    v[n++] = dup;

    // regrava tudo (contador + todas as linhas)
    int rc = gravar_tudo(path, v, n);

    for (size_t i=0;i<n;i++) free(v[i]);
    free(v);
    return rc;
}

/* Uso:
   if (adiciona_palavra("palavras.txt", "EXEMPLO") != 0) {
       fprintf(stderr, "falha ao adicionar palavra\n");
   }
*/

Por que isso elimina os NULs?

  • Modo texto ("r", "w") e fprintf escrevem apenas os bytes visíveis (sem '\0').
  • Truncar com "w" remove qualquer resquício antigo, evitando bytes NUL sobrando.
  • Nada de fwrite(buf, sizeof(buf), 1, ...) com buffers maiores que a palavra: isso insere '\0' até o tamanho do buffer.
  • Cabeçalho sempre com \n: fprintf(f, "%zu\n", n) evita deslocamento estranho da primeira palavra.

Fico à disposição.