Przechodzenie przez plik tekstowy linia po linii w C
Pracowałem nad małym ćwiczeniem dla mojej klasy CIS i jestem bardzo zdezorientowany metodami C używanymi do odczytu z pliku. Wszystko, co naprawdę muszę zrobić, to odczytać plik linia po linii i wykorzystać informacje zebrane z każdej linii, aby wykonać kilka manipulacji. Próbowałem użyć metody getline i innych bez powodzenia. Mój kod jest obecnie następujący:
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;
}
W tej chwili dostaję błąd seg z metodą sscanf i nie jestem pewien dlaczego. Jestem totalnym C noobem i po prostu zastanawiam się, czy jest coś, co mi umyka. Dzięki
4 answers
Tak wiele problemów w tak niewielu linijkach. Pewnie o niektórych zapomniałem:
- argv [0] jest nazwą programu, a nie pierwszym argumentem;
- Jeśli chcesz odczytać zmienną, musisz przydzielić jej pamięć
- nigdy nie pętla na feof, jedna pętla na funkcji IO, dopóki nie zawiedzie, feof służy do określenia przyczyny niepowodzenia,
- sscanf służy do parsowania linii, jeśli chcesz parsować plik, użyj fscanf,
- "%s" zatrzyma się na pierwszej spacji jako format ?scanf family
- Aby odczytać linię, standardową funkcją jest fgets,
- zwrócenie 1 z głównego oznacza awarię
Więc
#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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-10 14:21:42
Aby odczytać linię z pliku, należy użyć funkcji fgets
: odczytuje łańcuch znaków z podanego pliku do znaku nowej linii lub EOF
.
Użycie sscanf
w Twoim kodzie w ogóle nie zadziała, ponieważ używasz {[3] } jako ciągu formatującego do odczytu z line
do stałego ciągu literalnego %s
.
Powodem SEGV jest to, że zapisujesz do nie przydzielonej pamięci wskazywanej przez line
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-09 06:11:55
Załóżmy, że masz do czynienia z innym ogranicznikiem, np. tabulatorem \t
, zamiast znaku nowego wiersza \n
.
Bardziej ogólnym podejściem do ograniczników jest użycie getc()
, który chwyta jedną postać na raz.
Zauważ, że getc()
zwraca int
, abyśmy mogli sprawdzić równość z EOF
.
Po Drugie, definiujemy tablicę line[BUFFER_MAX_LENGTH]
Typu char
, aby przechowywać do BUFFER_MAX_LENGTH-1
znaków na stosie (musimy zapisać ten ostatni znak dla \0
terminatora charakter).
Użycie tablicy pozwala uniknąć konieczności używania malloc
i free
do tworzenia wskaźnika znakowego o odpowiedniej długości na stercie.
#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;
}
Jeśli musisz użyć char *
, możesz nadal używać tego kodu, ale strdup()
tablica line[]
, gdy zostanie wypełniona wartością wejściową linii. Musisz free
ten zduplikowany ciąg, gdy skończysz z nim, albo dostaniesz wyciek pamięci:
#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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-10 22:00:00
Oprócz innych odpowiedzi, w najnowszej bibliotece C (zgodnej z Posix 2008), możesz użyć getline . Zobacz tę odpowiedź (na powiązane pytanie).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:24