J'ai travaillé sur un petit exercice pour ma classe de SIC et je suis très déconcerté par les méthodes que C utilise pour lire dans un fichier. Tout ce que j'ai vraiment besoin de faire est de lire un fichier ligne par ligne et d’utiliser les informations recueillies à partir de chaque ligne pour effectuer quelques manipulations. J'ai essayé d'utiliser la méthode getline et d'autres sans succès. Mon code est actuellement le suivant:
int main(char *argc, char* argv[]){
const char *filename = argv[0];
FILE *file = fopen(filename, "r");
char *line = NULL;
while(!feof(file)){
sscanf(line, filename, "%s");
printf("%s\n", line);
}
return 1;
}
À l’heure actuelle, la méthode sscanf pose un problème grave et je ne sais pas pourquoi. Je suis un C noob total et je me demande juste s'il y avait quelque chose de grand qui me manquait. Merci
Tant de problèmes en si peu de lignes. J'en oublie probablement quelques-uns:
Alors
#include <stdio.h>
int main(int argc, char* argv[])
{
char const* const fileName = argv[1]; /* should check that argc > 1 */
FILE* file = fopen(fileName, "r"); /* should check the result */
char line[256];
while (fgets(line, sizeof(line), file)) {
/* note that fgets don't strip the terminating \n, checking its
presence would allow to handle lines longer that sizeof(line) */
printf("%s", line);
}
/* may check feof here to make a difference between eof and io failure -- network
timeout for instance */
fclose(file);
return 0;
}
Pour lire une ligne d'un fichier, vous devez utiliser la fonction fgets
: Elle lit une chaîne du fichier spécifié jusqu'à un caractère de nouvelle ligne ou EOF
.
L'utilisation de sscanf
dans votre code ne fonctionnerait pas du tout, puisque vous utilisez filename
comme chaîne de format pour la lecture de line
dans un littéral de chaîne constant %s
.
La raison de SEGV est que vous écrivez dans la mémoire non allouée indiquée par line
.
Supposons que vous traitez avec un autre délimiteur, tel qu'un onglet _\t
_, au lieu d'une nouvelle ligne _\n
_.
Une approche plus générale des délimiteurs consiste à utiliser getc()
, qui saisit un caractère à la fois.
Notez que getc()
retourne un int
, afin que nous puissions vérifier son égalité avec EOF
.
Deuxièmement, nous définissons un tableau _line[BUFFER_MAX_LENGTH]
_ de type char
, afin de stocker jusqu’à _BUFFER_MAX_LENGTH-1
_ caractères sur la pile (nous devons sauvegarder ce dernier caractère pour un _\0
_ terminateur personnage).
L'utilisation d'un tableau évite d'avoir à utiliser malloc
et free
pour créer un pointeur de caractère de la bonne longueur sur le tas.
_#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
{
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
if (argc == 2)
file = fopen(argv[1], "r");
else {
fprintf(stderr, "error: wrong number of arguments\n"
"usage: %s textfile\n", argv[0]);
return EXIT_FAILURE;
}
if (!file) {
fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
return EXIT_FAILURE;
}
/* get a character from the file pointer */
while(tempChar = fgetc(file))
{
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH) {
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
return EXIT_FAILURE;
}
/* test character value */
if (tempChar == EOF) {
line[tempCharIdx] = '\0';
fprintf(stdout, "%s\n", line);
break;
}
else if (tempChar == '\n') {
line[tempCharIdx] = '\0';
tempCharIdx = 0U;
fprintf(stdout, "%s\n", line);
continue;
}
else
line[tempCharIdx++] = (char)tempChar;
}
return EXIT_SUCCESS;
}
_
Si vous devez utiliser un _char *
_, vous pouvez toujours utiliser ce code, mais vous strdup()
le tableau _line[]
_, une fois qu'il est rempli avec une valeur de ligne d'entrée. Vous devez free
cette chaîne dupliquée une fois que vous avez terminé, ou vous obtiendrez une fuite de mémoire:
_#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
{
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
char *dynamicLine = NULL;
if (argc == 2)
file = fopen(argv[1], "r");
else {
fprintf(stderr, "error: wrong number of arguments\n"
"usage: %s textfile\n", argv[0]);
return EXIT_FAILURE;
}
if (!file) {
fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
return EXIT_FAILURE;
}
while(tempChar = fgetc(file))
{
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH) {
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
return EXIT_FAILURE;
}
/* test character value */
if (tempChar == EOF) {
line[tempCharIdx] = '\0';
dynamicLine = strdup(line);
fprintf(stdout, "%s\n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
break;
}
else if (tempChar == '\n') {
line[tempCharIdx] = '\0';
tempCharIdx = 0U;
dynamicLine = strdup(line);
fprintf(stdout, "%s\n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
continue;
}
else
line[tempCharIdx++] = (char)tempChar;
}
return EXIT_SUCCESS;
}
_
En plus des autres réponses, sur une bibliothèque C récente (conforme à Posix 2008), vous pouvez utiliser getline . Voir cette réponse (à une question connexe).