Pozycje liter w pliku tekstowym.

Odpowiedz Nowy wątek
2011-07-30 09:52
0

Witam. Napisałem program, który pobiera od użytkownika nazwę pliku do otwarcia oraz umożliwia podanie podanie położenia w pliku i wyświetla część pliku od tego miejsca do najbliższego znaku nowej linii. Oto kod:

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define MAX 41
 
int main(void)
{
    FILE *wsk;
    int i;
    long int a;
    char nazwa[MAX];
    char ch;
 
    puts("Podaj nazwe pliku");
    puts("Wprowadz pusta linie aby zakonczyc");
    if (gets(nazwa) != NULL && nazwa[0] != '\0')
    {
        if ((wsk = fopen(nazwa, "r")) == NULL)
        {
            puts("Blad otwarcia pliku");
            exit(1);
        }
        puts("Podaj polozenie w pliku");
        while (scanf("%ld", &a) == 1)
        {
            if (fseek(wsk, a, SEEK_SET) != 0)
            {
                puts("Wyszedles poza granice pliku!");
                puts("Podaj polozenie pliku");
                puts("Wprowadz dana nienumeryczna aby zakonczyc");
                continue;
            }
            else
            {
                while((ch = getc(wsk)) != EOF && ch != '\n')
                {
                    putc(ch, stdout);
                }
            }
            puts("\nPodaj polozenie pliku");
            puts("Wprowadz dana nienumeryczna aby zakonczyc");
        }
    }
    getchar();
    getchar();
    return 0;
}

I tutaj mam parę pytań. Przykładowo w pliku zapisano coś takiego:

ABCDEFGHIJKLMNO
PRSTUWXYZ

Podając np. 0 wszystko jest ok i program wyświetla ABCDEFGHIJKLMNO, jednak kiedy np podam 15 lub 16 to wyświetla mi się coś takiego:

Podaj polozenie w pliku
15

Podaj polozenie pliku.
Wprowadz dana nienumeryczna aby zakonczyc

I chodzi mi tutaj dokładnie o ten Enter po 15. Program tak jakby odczytywał przy 15 i 16 znak nowej linii czy coś takiego. Po wprowadzeniu 15 w miejsce w pliku zostaje ustawione po literze O. Czyli w miejscu gdzie nic dalej nie ma. Moim zdaniem wpisanie 15 powinno spowodować przejście przed P i odczytanie PRSTUWXYZ. Jednak linijkę PRSTUWXYZ otrzymuję dopiero po wpisaniu 17. Czemu się tak dzieje?

Kolejne moje pytanie dotyczy wartości zwracanej przez fseek. Przeczytałem, że gdy wszystko jest ok fseek zwraca 0 a gdy coś poszło nie tak, np. próba przekroczenia granicy pliku zwraca -1. Więc napisałem coś takiego:

if (fseek(wsk, a, SEEK_SET) != 0)
{
    puts("Wyszedles poza granice pliku!");
    puts("Podaj polozenie pliku");
    puts("Wprowadz dana nienumeryczna aby zakonczyc");
    continue;
}

Wydawało by mi się, że w przypadku gdy wpiszę np. 50 (co jest poza granicą wcześniej podanego pliku tekstowego) program powinien wyświetlić to co jest w pętli i przejść od nowa do pobrania miejsca w pliku. Jednak tak się nie dzieje i po wpisaniu 50 otrzymuję coś takiego jak powyżej:

Podaj polozenie w pliku
50

Podaj polozenie pliku.
Wprowadz dana nienumeryczna aby zakonczyc

I ostatnie moje pytanie dotyczy funkcji scanf. W pętli while (scanf("%ld", &a) == 1) odczytywane są wartości do momentu wprowadzenia np. jakiejś litery. Jednak np. gdy wprowadzę zamiast jednej wartości, trzy: 2 4 6 to wyświetla mi się wszystko potem trzy razy. Te wartości 4 i 6 widać pozostają w buforze i potem są odczytywane, jednak wolałbym żeby scanf odczytywał tylko jedną wartość a resztę np. porzucał. Czy istniej taka możliwość?

Pozostało 580 znaków

2011-07-30 21:27
Kumashiro
1
olek1 napisał(a)

I chodzi mi tutaj dokładnie o ten Enter po 15. Program tak jakby odczytywał przy 15 i 16 znak nowej linii czy coś takiego.

No, ale sam mu każesz wstawiać znak nowej linii:

puts("\nPodaj polozenie pliku");

Normalnie, jak wypisujesz znaki, znak nowej linii z puts() jest umieszczany za nimi, dzięki czemu napis "Podaj..." pojawia się niżej. Kiedy z pliku odczytasz '\n', nie wypisujesz go na wyjściu, ale tak czy siak ląduje tam znak z puts().

olek1 napisał(a)

Po wprowadzeniu 15 w miejsce w pliku zostaje ustawione po literze O. Czyli w miejscu gdzie nic dalej nie ma.

Zawsze dalej coś jest, o ile nie jest to koniec pliku.

olek1 napisał(a)

Moim zdaniem wpisanie 15 powinno spowodować przejście przed P i odczytanie PRSTUWXYZ.

Nie. Pod offsetem 15 znajduje się znak nowej linii, a w warunku Twojej pętli stoi, że ma ona się zakończyć w takim przypadku.

olek1 napisał(a)

Jednak linijkę PRSTUWXYZ otrzymuję dopiero po wpisaniu 17. Czemu się tak dzieje?

Otwórz sobie ten plik w edytorze heksadecymalnym. Zobaczysz wtedy jak on wygląda... "fizycznie".

olek1 napisał(a)

Kolejne moje pytanie dotyczy wartości zwracanej przez fseek. Przeczytałem, że gdy wszystko jest ok fseek zwraca 0 a gdy coś poszło nie tak, np. próba przekroczenia granicy pliku zwraca -1.

Nie wiem gdzie to wyczytałeś, ale zmień źródło informacji. fseek() poza granicę pliku zwraca 0, nie -1.

#include <stdio.h>
 
int  main(void) {
    FILE        *in;
    int         retval;
 
    in = fopen("test.dat", "r");
    retval = fseek(in, 50, SEEK_SET);
    fclose(in);
 
    printf("%d\n", retval);
    return 0;
}
[email protected] ~/tmp $ stat test.dat | grep Size
  Size: 26              Blocks: 8          IO Block: 4096   regular file
[email protected] ~/tmp $ ./test
0
olek1 napisał(a)

I ostatnie moje pytanie dotyczy funkcji scanf. W pętli while (scanf("%ld", &a) == 1) odczytywane są wartości do momentu wprowadzenia np. jakiejś litery. Jednak np. gdy wprowadzę zamiast jednej wartości, trzy: 2 4 6 to wyświetla mi się wszystko potem trzy razy. Te wartości 4 i 6 widać pozostają w buforze i potem są odczytywane, jednak wolałbym żeby scanf odczytywał tylko jedną wartość a resztę np. porzucał. Czy istniej taka możliwość?

Tak, istnieje.

Pozostało 580 znaków

2011-07-31 10:04
0
Kumashiro napisał(a)

Nie wiem gdzie to wyczytałeś, ale zmień źródło informacji. fseek() poza granicę pliku zwraca 0, nie -1.

Wszędzie tak pisze. W książce Stephena Praty, na wikibooks: http://pl.wikibooks.org/wiki/C/fseek I chyba jest to prawda, że jak wszystko jest ok to zwraca 0 bo jak zmienię warunek w programie na

if (fseek(wsk, a, SEEK_SET) == 0)

To mi zawsze wypisuje, że wyszedłem poza plik.
Zauważyłem też, że jak wpiszę liczbę ujemną np. -15 to wtedy wywala mi błąd pliku, a jak np. 80 to nie wypisuje nic. Czyli koniec pliku nie jest po wpisanych danych? Tak jak u mnie np. po Z?

ABCDEFGHIJKLMNO
PRSTUWXYZ

Kumashiro napisał(a)

Tak, istnieje.

Znalazłem coś na ten temat, że "%*d" porzuca dane wczytane przez scanf. Jednak jak dodam na koniec

                        {
                                while((ch = getc(wsk)) != EOF && ch != '\n')
                                {
                                        putc(ch, stdout);
                                }
                        }
                        puts("\nPodaj polozenie pliku");
                        puts("Wprowadz dana nienumeryczna aby zakonczyc");
                        scanf("%*d");

To porzuca tylko jedną wartość, czyli jak wpiszę np. trzy to wyświetli 2.

edytowany 1x, ostatnio: olek1, 2011-07-31 10:04

Pozostało 580 znaków

2011-07-31 11:11
Kumashiro
1
olek1 napisał(a)
Kumashiro napisał(a)

Nie wiem gdzie to wyczytałeś, ale zmień źródło informacji. fseek() poza granicę pliku zwraca 0, nie -1.

Wszędzie tak pisze. W książce Stephena Praty, na wikibooks: http://pl.wikibooks.org/wiki/C/fseek

Praty nie posiadam, ale pod linkiem na Wikibooks nie ma słowa o tym, że wyjechanie poza rozmiar pliku jest błędem. Ten opis nawet nie używa stałych SEEK_*...

olek1 napisał(a)

I chyba jest to prawda, że jak wszystko jest ok to zwraca 0 bo jak zmienię warunek w programie na

if (fseek(wsk, a, SEEK_SET) == 0)

To mi zawsze wypisuje, że wyszedłem poza plik.

Udowodniłem Ci, że jednak nie jest to prawdą, kod i listing wyjścia masz wyżej :)
Twoja zmiana w warunku także jest dowodem na to, że fseek() poza koniec pliku zwraca 0, nie -1.

olek1 napisał(a)

Zauważyłem też, że jak wpiszę liczbę ujemną np. -15 to wtedy wywala mi błąd pliku, a jak np. 80 to nie wypisuje nic. Czyli koniec pliku nie jest po wpisanych danych? Tak jak u mnie np. po Z?

Jest, ale próba wyjechania poza koniec pliku nie jest błędem, w przeciwieństwie do wyjechania przed początek.

olek1 napisał(a)

Znalazłem coś na ten temat, że "%*d" porzuca dane wczytane przez scanf. Jednak jak dodam na koniec

[...]

To porzuca tylko jedną wartość, czyli jak wpiszę np. trzy to wyświetli 2.

Ja mam inną propozycję. Najpierw wczytaj input od usera (jako tablicę znaków; '\n' kończy wejście), a potem skonwertuj to na wartość liczbową. Wtedy "1 2 3" będzie nieprawidłowe.

Pozostało 580 znaków

2011-07-31 13:16
0
Kumashiro napisał(a)

Praty nie posiadam, ale pod linkiem na Wikibooks nie ma słowa o tym, że wyjechanie poza rozmiar pliku jest błędem. Ten opis nawet nie używa stałych SEEK_*...

W Pracie pisze dokładnie tak: "Wartościami zwracanymi przez fseek() są: 0, gdy wszystko jest w porządku, i -1, gdy wystąpił błąd, taki jak próba przekroczenia granic pliku.
Jednak już chyba już wiem o co chodzi, próba wyjechania poza koniec pliku a poza jego granice to dwie różne rzeczy.

Kumashiro napisał(a)

Twoja zmiana w warunku także jest dowodem na to, że fseek() poza koniec pliku zwraca 0, nie -1.

Nie napisałem wcześniej, że gdy ustawię warunek na:

if (fseek(wsk, a, SEEK_SET) == 0)

i wpiszę np. 4 to otrzymuję "Wyszedles poza granice pliku!".

A to:

Zauważyłem też, że jak wpiszę liczbę ujemną np. -15 to wtedy wywala mi błąd pliku, a jak np. 80 to nie wypisuje nic. Czyli koniec pliku nie jest po wpisanych danych? Tak jak u mnie np. po Z?

dotyczyło warunku

if (fseek(wsk, a, SEEK_SET) != 0)
Kumashiro napisał(a)

Jest, ale próba wyjechania poza koniec pliku nie jest błędem, w przeciwieństwie do wyjechania przed początek.

Chyba już wiem o co chodzi. Dzięki za odpowiedź

Co do tej konwersji napisałem coś takiego:

                puts("Podaj polozenie w pliku");
        while (scanf("%s", a) != EOF)
                {
                    liczba = strtol(a, &koniec, 10);
                        if (fseek(wsk, liczba, SEEK_SET) != 0)
                        {
                                puts("Wyszedles poza granice pliku!");
                                puts("Podaj polozenie pliku");
                                puts("CTRL + Z - wyjscie");
                                continue;
                        }
                        else
                        {
                                while((ch = getc(wsk)) != EOF && ch != '\n')
                                {
                                        putc(ch, stdout);
                                }
                        }
                        puts("\nPodaj polozenie pliku");
                        puts("CTRL + Z - wyjscie");
                }

Ale w a pozostaje i tak ten cały ciąg i jest wykonywany tyle razy ile cyfr wprowadzę.

edytowany 3x, ostatnio: olek1, 2011-07-31 14:02

Pozostało 580 znaków

2011-07-31 17:07
Kumashiro
olek1 napisał(a)

Co do tej konwersji napisałem coś takiego:

[...]

Ale w a pozostaje i tak ten cały ciąg i jest wykonywany tyle razy ile cyfr wprowadzę.

Nie używaj scanf() :)

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
 
int main(void) {
    long    inval;
    char    input[100], *dend;
 
    input[99] = 0;
    while ( 1 ) {
        if ( fgets(input, sizeof(input) - 1, stdin) == NULL )
            break;
 
        errno = 0;
        inval = strtol(input, &dend, 10);
        if ( errno || (*dend != '\n') ) {
            fprintf(stderr, "Błędna wartość: %s", input);
            continue;
        };
 
        if ( dend == input ) {
            fprintf(stderr, "Nie podano wartości\n")
            continue;
        };
 
        if ( inval == 0 )   /* Wpisanie `0' kończy zabawę */
            break;
 
        printf("> %li\n", inval);
    };
 
    return 0;
}

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0