J'ai écrit cette fonction pour lire une ligne d'un fichier:
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;
}
La fonction lit le fichier correctement et, en utilisant printf, je constate que la chaîne constLine a également été lue correctement.
Cependant, si j’utilise la fonction, par exemple comme ça:
while (!feof(myFile)) {
const char *line = readLine(myFile);
printf("%s\n", line);
}
printf produit du charabia. Pourquoi?
Si votre tâche n'est pas d'inventer la fonction de lecture ligne par ligne, mais simplement de lire le fichier ligne par ligne, vous pouvez utiliser un extrait de code typique impliquant la fonction getline()
(voir la page de manuel ici ) :
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("/etc/motd", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
printf("Retrieved line of length %zu:\n", read);
printf("%s", line);
}
fclose(fp);
if (line)
free(line);
exit(EXIT_SUCCESS);
}
Dans votre fonction readLine
, vous renvoyez un pointeur sur le tableau line
(à proprement parler, un pointeur sur son premier caractère, mais la différence n'est pas pertinente ici). Comme il s’agit d’une variable automatique (c’est-à-dire «sur la pile»), la mémoire est récupérée au retour de la fonction. Vous voyez charabia parce que printf
a mis ses propres données dans la pile.
Vous devez renvoyer une mémoire tampon allouée dynamiquement à partir de la fonction. Vous en avez déjà un, c'est lineBuffer
; tout ce que vous avez à faire est de le tronquer à la longueur souhaitée.
lineBuffer[count] = '\0';
realloc(lineBuffer, count + 1);
return lineBuffer;
}
AJOUT&EACUTE;(réponse à la question suivante dans le commentaire): readLine
renvoie un pointeur sur les caractères constituant la ligne. Ce pointeur est ce dont vous avez besoin pour travailler avec le contenu de la ligne. C'est aussi ce que vous devez passer à free
lorsque vous avez fini d'utiliser la mémoire occupée par ces personnages. Voici comment utiliser la fonction readLine
:
char *line = readLine(file);
printf("LOG: read a line: %s\n", line);
if (strchr(line, 'a')) { puts("The line contains an a"); }
/* etc. */
free(line);
/* After this point, the memory allocated for the line has been reclaimed.
You can't use the value of `line` again (though you can assign a new value
to the `line` variable if you want). */
FILE* fp;
char buffer[255];
fp = fopen("file.txt", "r");
while(fgets(buffer, 255, (FILE*) fp)) {
printf("%s\n", buffer);
}
fclose(fp);
//open and get the file handle
FILE* fh;
fopen_s(&fh, filename, "r");
//check if file exists
if (fh == NULL){
printf("file does not exists %s", filename);
return 0;
}
//read line by line
const size_t line_size = 300;
char* line = malloc(line_size);
while (fgets(line, line_size, fh) != NULL) {
printf(line);
}
free(line); // dont forget to free heap memory
readLine()
renvoie le pointeur sur la variable locale, ce qui entraîne un comportement indéfini.
Pour vous déplacer, vous pouvez:
readLine()
line
en utilisant malloc()
- dans ce cas, line
sera persistantUtilisez fgets()
pour lire une ligne depuis un descripteur de fichier.
Certaines choses ne vont pas dans l'exemple:
fprintf(stderr, ....
fgetc()
plutôt que getc()
. getc()
est une macro, fgetc()
est une fonction appropriéegetc()
renvoie int
alors ch
doit être déclaré comme int
. Ceci est important car la comparaison avec EOF
sera gérée correctement. Certains jeux de caractères 8 bits utilisent 0xFF
comme caractère valide (par exemple, ISO-LATIN-1) et EOF
qui vaut -1, sera 0xFF
s'il est affecté à une char
.Il y a un débordement de tampon potentiel sur la ligne
lineBuffer[count] = '\0';
Si la ligne comporte exactement 128 caractères, count
vaut 128 au point qui est exécuté.
Comme d'autres l'ont fait remarquer, line
est un tableau déclaré localement. Vous ne pouvez pas y retourner un pointeur.
strncpy(count + 1)
copiera au maximum count + 1
caractères mais s’achèvera s’il détecte '\0'
. Parce que vous définissez lineBuffer[count]
sur '\0'
, vous savez qu’il n’obtiendra jamais count + 1
. Cependant, si tel était le cas, il ne mettrait pas de '\0'
de terminaison; Vous voyez souvent quelque chose comme ce qui suit:
char buffer [BUFFER_SIZE];
strncpy(buffer, sourceString, BUFFER_SIZE - 1);
buffer[BUFFER_SIZE - 1] = '\0';
si vous malloc()
une ligne à renvoyer (à la place de votre tableau char
local), votre type de retour doit être char*
- supprimez la const
.
void readLine(FILE* file, char* line, int limit)
{
int i;
int read;
read = fread(line, sizeof(char), limit, file);
line[read] = '\0';
for(i = 0; i <= read;i++)
{
if('\0' == line[i] || '\n' == line[i] || '\r' == line[i])
{
line[i] = '\0';
break;
}
}
if(i != read)
{
fseek(file, i - read + 1, SEEK_CUR);
}
}
qu'en est-il de celui-ci?
Voici mes quelques heures ... Lire tout le fichier ligne par ligne.
char * readline(FILE *fp, char *buffer)
{
int ch;
int i = 0;
size_t buff_len = 0;
buffer = malloc(buff_len + 1);
if (!buffer) return NULL; // Out of memory
while ((ch = fgetc(fp)) != '\n' && ch != EOF)
{
buff_len++;
void *tmp = realloc(buffer, buff_len + 1);
if (tmp == NULL)
{
free(buffer);
return NULL; // Out of memory
}
buffer = tmp;
buffer[i] = (char) ch;
i++;
}
buffer[i] = '\0';
// Detect end
if (ch == EOF && (i == 0 || ferror(fp)))
{
free(buffer);
return NULL;
}
return buffer;
}
void lineByline(FILE * file){
char *s;
while ((s = readline(file, 0)) != NULL)
{
puts(s);
free(s);
printf("\n");
}
}
int main()
{
char *fileName = "input-1.txt";
FILE* file = fopen(fileName, "r");
lineByline(file);
return 0;
}
const char *readLine(FILE *file, char* line) {
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);
return line;
}
char linebuffer[256];
while (!feof(myFile)) {
const char *line = readLine(myFile, linebuffer);
printf("%s\n", line);
}
notez que la variable 'line' est déclarée dans la fonction appelante puis transmise, donc votre fonction readLine
remplit la mémoire tampon prédéfinie et la renvoie simplement. C'est ainsi que fonctionnent la plupart des bibliothèques C.
À ma connaissance, il y a d'autres moyens:
char line[]
comme statique (static char line[MAX_LINE_LENGTH]
-> il conservera sa valeur APRES le retour de la fonction). -> mauvais, la fonction n'est pas réentrante, et une condition de concurrence peut se produire -> si vousappelez-la deux fois à partir de deux threads, elle remplacera ses résultatsmalloc()
ing la ligne de caractère [], et le libérant dans les fonctions d'appel -> trop coûteux malloc
s, et, déléguant la responsabilité de libérer le tampon à une autre fonction (la solution la plus élégante consiste à appeler malloc
et free
sur les tampons de la même fonction)btw, la diffusion 'explicite' de char*
à const char*
est redondante.
btw2, il n'y a pas besoin de malloc()
le lineBuffer, il suffit de le définir char lineBuffer[128]
, de sorte que vous n'avez pas besoin de le libérer
btw3 n'utilise pas de 'tableaux de piles de taille dynamique' (définissant le tableau comme étant char arrayName[some_nonconstant_variable]
), si vous ne savez pas exactement ce que vous faites, cela ne fonctionne que dans C99.
Vous devez utiliser les fonctions ANSI pour lire une ligne, par exemple. Fgets. Après avoir appelé, vous avez besoin de free () dans un contexte d’appel, par exemple:
...
const char *entirecontent=readLine(myFile);
puts(entirecontent);
free(entirecontent);
...
const char *readLine(FILE *file)
{
char *lineBuffer=calloc(1,1), line[128];
if ( !file || !lineBuffer )
{
fprintf(stderr,"an ErrorNo 1: ...");
exit(1);
}
for(; fgets(line,sizeof line,file) ; strcat(lineBuffer,line) )
{
if( strchr(line,'\n') ) *strchr(line,'\n')=0;
lineBuffer=realloc(lineBuffer,strlen(lineBuffer)+strlen(line)+1);
if( !lineBuffer )
{
fprintf(stderr,"an ErrorNo 2: ...");
exit(2);
}
}
return lineBuffer;
}
Implémenter une méthode pour lire et obtenir le contenu d'un fichier (input1.txt)
#include <stdio.h>
#include <stdlib.h>
void testGetFile() {
// open file
FILE *fp = fopen("input1.txt", "r");
size_t len = 255;
// need malloc memory for line, if not, segmentation fault error will occurred.
char *line = malloc(sizeof(char) * len);
// check if file exist (and you can open it) or not
if (fp == NULL) {
printf("can open file input1.txt!");
return;
}
while(fgets(line, len, fp) != NULL) {
printf("%s\n", line);
}
free(line);
}
J'espère que cette aide. Bonne codage!
Fournissez une fonction portable et générique _read_line
_ et vous pourrez traiter le contenu de la ligne ligne par ligne.
_#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void
read_line(const char *filename,
size_t linecap,
int delimiter,
void (*process_line)(const char *line, ssize_t linelen)) {
FILE *file = fopen(filename, "r");
if (!file) {
perror(filename);
return;
}
int c;
char *line = malloc(linecap);
if (0 == line) {
perror("linecap");
goto close_exit;
}
char *p = line;
ssize_t linelen;
while (EOF != (c = fgetc(file))) {
if (delimiter == c) {
*p = delimiter, *++p = 0;
process_line(line, linelen+1);
p = line;
linelen = 0;
} else {
*p++ = c;
linelen++;
}
}
free(line);
if (ferror(file)) {
perror(filename);
goto close_exit;
}
close_exit:
fclose(file);
}
void
print_line(const char *line, ssize_t linelen) {
fwrite(line, 1, linelen, stdout);
fflush(stdout);
}
int
main(int argc, char **argv) {
read_line("/a/b/c/some.txt", 16, '\n', print_line);
return 0;
}
_
Mon outil à partir de zéro:
FILE *pFile = fopen(your_file_path, "r");
int nbytes = 1024;
char *line = (char *) malloc(nbytes);
char *buf = (char *) malloc(nbytes);
size_t bytes_read;
int linesize = 0;
while (fgets(buf, nbytes, pFile) != NULL) {
bytes_read = strlen(buf);
// if line length larger than size of line buffer
if (linesize + bytes_read > nbytes) {
char *tmp = line;
nbytes += nbytes / 2;
line = (char *) malloc(nbytes);
memcpy(line, tmp, linesize);
free(tmp);
}
memcpy(line + linesize, buf, bytes_read);
linesize += bytes_read;
if (feof(pFile) || buf[bytes_read-1] == '\n') {
handle_line(line);
linesize = 0;
memset(line, '\0', nbytes);
}
}
free(buf);
free(line);
Vous commettez l’erreur de renvoyer un pointeur sur une variable automatique . La ligne de variable est allouée dans la pile et ne vit que tant que la fonction est en vie . Vous n’avez pas le droit de lui retourner un pointeur, dès qu'il reviendra, la mémoire sera donnée ailleurs.
const char* func x(){
char line[100];
return (const char*) line; //illegal
}
Pour éviter cela, vous devez soit retourner un pointeur à la mémoire qui réside sur le tas, par exemple. lineBuffer .__ et il devrait incomber à l'utilisateur d'appeler free () lorsqu'il en aura terminé . Sinon, vous pouvez demander à l'utilisateur de vous transmettre en argument une adresse mémoire sur laquelle écrire le contenu de la ligne.
Je veux un code de la terre 0 alors j'ai fait ceci pour lire le contenu du mot du dictionnaire ligne par ligne.
char temp_str [20]; // vous pouvez modifier la taille de la mémoire tampon selon vos besoins et la longueur d'une seule ligne dans un fichier.
Note J'ai initialisé le tampon avec un caractère nul chaque fois que je lis une ligne.
#include<stdio.h>
int main()
{
int i;
char temp_ch;
FILE *fp=fopen("data.txt","r");
while(temp_ch!=EOF)
{
i=0;
char temp_str[20]={'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
while(temp_ch!='\n')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
i++;
}
if(temp_ch=='\n')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
}
printf("%s",temp_str);
}
return 0;
}