Eu escrevi esta função para ler uma linha de um arquivo:
const char *readLine(FILE *file) {
if (file == NULL) {
printf("Error: file pointer is null.");
exit(1);
}
int maximumLineLength = 128;
char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);
if (lineBuffer == NULL) {
printf("Error allocating memory for line buffer.");
exit(1);
}
char ch = getc(file);
int count = 0;
while ((ch != '\n') && (ch != EOF)) {
if (count == maximumLineLength) {
maximumLineLength += 128;
lineBuffer = realloc(lineBuffer, maximumLineLength);
if (lineBuffer == NULL) {
printf("Error reallocating space for line buffer.");
exit(1);
}
}
lineBuffer[count] = ch;
count++;
ch = getc(file);
}
lineBuffer[count] = '\0';
char line[count + 1];
strncpy(line, lineBuffer, (count + 1));
free(lineBuffer);
const char *constLine = line;
return constLine;
}
A função lê o arquivo corretamente e, usando printf, vejo que a string constLine também foi lida corretamente.
No entanto, se eu usar a função, por exemplo:
while (!feof(myFile)) {
const char *line = readLine(myFile);
printf("%s\n", line);
}
printf produz sem sentido. Por quê?
fgets
vez defgetc
. Você está lendo caractere por caractere em vez de linha por linha.getline()
faz parte do POSIX 2008. Pode haver plataformas semelhantes ao POSIX sem ele, especialmente se elas não suportam o restante do POSIX 2008, mas dentro do mundo dos sistemas POSIX,getline()
é bastante portátil atualmente.Respostas:
Se sua tarefa não é inventar a função de leitura linha a linha, mas apenas para ler o arquivo linha por linha, você pode usar um trecho de código típico envolvendo a
getline()
função (consulte a página do manual aqui ):fonte
getline
é específico ao GNU libc, ou seja, ao Linux. No entanto, se a intenção é ter uma função de leitura de linha (em vez de aprender C), existem várias funções de leitura de linha de domínio público disponíveis na Web.if(line)
cheque é supérfluo. Ligarfree(NULL)
é essencialmente um não-op.fonte
(FILE*) fp
? Já nãofp
é umFILE *
e tambémfopen()
retorna umFILE *
?getline
é uma boa alternativa. Concordo que oFILE *
elenco é desnecessário.fp
parafilePointer
uma maior clareza.Em sua
readLine
função, você retorna um ponteiro para aline
matriz (Estritamente falando, um ponteiro para seu primeiro caractere, mas a diferença é irrelevante aqui). Como é uma variável automática (ou seja, está “na pilha”), a memória é recuperada quando a função retorna. Você vê bobagens porqueprintf
colocou suas próprias coisas na pilha.Você precisa retornar um buffer alocado dinamicamente da função Você já tem um, é
lineBuffer
; tudo o que você precisa fazer é truncá-lo no comprimento desejado.ADICIONADO (resposta à pergunta de acompanhamento no comentário):
readLine
retorna um ponteiro para os caracteres que compõem a linha. Esse ponteiro é o que você precisa para trabalhar com o conteúdo da linha. É também para isso que você deve passarfree
quando terminar de usar a memória usada por esses caracteres. Veja como você pode usar areadLine
função:fonte
fonte
fopen_s
torna o código não portável.printf
procurará especificadores de formato e não imprimirá sinais de porcentagem e os seguintes caracteres como estão . Bytes nulos farão desaparecer todos os caracteres no restante da linha. (Não me diga nulo bytes não pode acontecer!)readLine()
retorna o ponteiro para a variável local, o que causa um comportamento indefinido.Para se locomover, você pode:
readLine()
line
usomalloc()
- neste casoline
, será persistentefonte
Use
fgets()
para ler uma linha de um identificador de arquivo.fonte
Algumas coisas estão erradas com o exemplo:
fprintf(stderr, ....
fgetc()
e nãogetc()
.getc()
é uma macro,fgetc()
é uma função adequadagetc()
retorna umint
soch
deve ser declarado como umint
. Isso é importante, pois a comparação comEOF
será tratada corretamente. Alguns conjuntos de caracteres de 8 bits usam0xFF
como um caractere válido (ISO-LATIN-1 seria um exemplo) eEOF
que é -1, será0xFF
se atribuído a achar
.Existe um potencial estouro de buffer na linha
Se a linha tiver exatamente 128 caracteres,
count
será 128 no ponto que é executado.Como outros já apontaram,
line
é uma matriz declarada localmente. Você não pode retornar um ponteiro para ele.strncpy(count + 1)
irá copiar a maioria doscount + 1
personagens, mas terminará se bate'\0'
Porque você definirlineBuffer[count]
para'\0'
que você sabe que nunca vai conseguircount + 1
. No entanto, se o fizesse, não colocaria uma terminação'\0'
, então você precisa fazê-lo. Você costuma ver algo como o seguinte:se você tem
malloc()
uma linha para retornar (no lugar de suachar
matriz local ), seu tipo de retorno deve serchar*
- solte oconst
.fonte
que tal este?
fonte
Aqui estão minhas várias horas ... Lendo todo o arquivo linha por linha.
fonte
fgetc
vez defgets
?note que a variável 'line' é declarada na função de chamada e depois passada, então sua
readLine
função preenche o buffer predefinido e apenas o retorna. É assim que a maioria das bibliotecas C funciona.Existem outras maneiras pelas quais estou ciente:
char line[]
como estático (static char line[MAX_LINE_LENGTH]
-> manterá seu valor APÓS retornar da função). -> ruim, a função não é reentrada, e a condição de corrida pode ocorrer -> se você chamá-lo duas vezes a partir de dois threads, substituirá seus resultadosmalloc()
adicionando a linha char [] e liberando-a nas funções de chamada -> muitosmalloc
s caros , e delegando a responsabilidade de liberar o buffer para outra função (a solução mais elegante é chamarmalloc
efree
em qualquer buffer na mesma função)btw, a conversão "explícita" de
char*
paraconst char*
é redundante.btw2, não há necessidade
malloc()
do lineBuffer, apenas defina-ochar lineBuffer[128]
, para que você não precise liberá -lobtw3 não usa 'matrizes de pilha de tamanho dinâmico' (definindo a matriz como
char arrayName[some_nonconstant_variable]
), se você não sabe exatamente o que está fazendo, ele funciona apenas no C99.fonte
Você deve usar as funções ANSI para ler uma linha, por exemplo. objetos. Depois de ligar, você precisa de free () no contexto de chamada, por exemplo:
fonte
Implementar método para ler e obter conteúdo de um arquivo (input1.txt)
Espero que esta ajuda. Feliz codificação!
fonte
Você comete o erro de retornar um ponteiro para uma variável automática. A linha variável é alocada na pilha e dura apenas enquanto a função durar. Você não tem permissão para retornar um ponteiro para ele, porque assim que ele retornar, a memória será entregue em outro lugar.
Para evitar isso, você retorna um ponteiro para a memória que reside na pilha, por exemplo. lineBuffer e deve ser responsabilidade do usuário ligar para free () quando ele terminar. Como alternativa, você pode pedir ao usuário para passar como argumento um endereço de memória no qual escrever o conteúdo da linha.
fonte
Eu quero um código do chão 0, então eu fiz isso para ler o conteúdo da palavra do dicionário linha por linha.
char temp_str [20]; // você pode alterar o tamanho do buffer de acordo com seus requisitos E o comprimento de uma única linha em um arquivo.
Nota : Inicializei o buffer Com o caractere Nulo toda vez que leio a linha.
fonte
int main() {
code
char temp_str [20] = {'\ 0'};code
c preencherá automaticamente cada slot com um terminador nulo, pois a maneira como as declarações da matriz funcionam é que, se uma matriz for inicializada com menos elementos que a matriz contém, o último elemento preencherá os elementos restantes.char temp_str[20] = {0}
também preenche toda a matriz de caracteres com terminadores nulos.Meu implemento do zero:
fonte
fgets
que poderia ser usada.Forneça uma
getdelim
função portátil e genérica , teste passado via msvc, clang, gcc.fonte
fgets
existe?getdelim
permite delimitadores personalizados. Também notei que não há limite de comprimento de linha - nesse caso, você pode usar a pilha comgetline
. (Ambos descritos aqui: man7.org/linux/man-pages/man3/getline.3.html )getdelim
egetline
foi padronizada no POSIX.1-2008, alguém menciona nesta página).fgets
também é padrão c, e não específico do Linux