Estou tentando manipular corretamente a entrada do usuário em C, principalmente ao ler um caminho de arquivo do usuário.
No entanto, tenho algumas preocupações:
- Como refatorar esse código para lidar com alocação dinâmica de memória?
- Como devo lidar corretamente com a alocação de memória dinâmica para entrada do usuário quando o comprimento é desconhecido?
- Qual é a maneira mais segura de aceitar entradas do usuário para caminhos de arquivo?
Meu código atual:
#include <stdio.h>
int main() {
char filePath[1024];
printf("Please provide file to encrypt (File Path): ");
scanf("%1024s", filePath); // Is this safe?
printf("You entered: %s\n", filePath);
return 0;
}
Encontrei uma fonte no site da Microsoft sugerindo que eu especifique uma largura para o %s
especificador de formato em scanf
(por exemplo, %1024s
em vez de %s
), mas ainda é um tamanho fixo e quero que ele seja alocado dinamicamente.
Conforme observado nos comentários, seria melhor utilizar a
fgets
função de biblioteca padrão que permite especificar o tamanho do buffer para evitar problemas de estouro de buffer.Usar
scanf
with%s
com ou sem um especificador de largura também restringirá você a ler uma string delimitada por espaços em branco. Isso proíbe espaços na sua entrada.Se você quiser ler uma linha inteira de tamanho desconhecido, precisará sair da biblioteca padrão ou reinventar a roda você mesmo. Não deve ser difícil. Eu preparei o seguinte em alguns minutos, e talvez haja espaço para melhorias, mas isso também não levaria muito tempo.
O processo chave é alocar um buffer inicial, então ler nele caractere por caractere até atingir
EOF
ou uma nova linha. Se o comprimento atingir os limites do seu buffer, realoque.Duas armadilhas comuns de gerenciamento de memória com isso:
realloc
, o que pode precisar copiar seu buffer a cada vez . Isso é caro. Aumente por um fator de 2 1 (multiplicado) e suas chamadas pararealloc
serão logarítmicas. Começar com um tamanho de orçamento inicial maior também é uma opção.realloc
o teste que ele obteve sucesso antes de atribuir ao buffer original. Se você não fizer isso erealloc
falhar, você não conseguirá acessar a memória alocada originalmente, levando a um vazamento de memória.Um refinamento adicional disso pode ser usar um
size_t
ponteiro como argumento e permitir que a função grave o comprimento da string lida em uma variável, de modo que o tamanho da string de entrada não precise ser calculado posteriormente comstrlen
.1 A taxa de crescimento de memória ideal é uma questão de algum debate. Veja: Qual é a taxa de crescimento ideal para um array alocado dinamicamente?
Tente usar,
getline(&buffer,&size,stdin);
pois ele aloca memória dinamicamente para a entrada.Você pode simplesmente ter um código funcional com algo assim: