Błąd w wyświetlaniu zawartości pliku

1

Witam.
Taka ciekawostka
Zawartość pliku do wczytania
Problem pojawia się po próbie wczytania tekstu.

Ala ma kota i ten kot jest bardzo rudy.
Kot ten jest zadbany.
I lubi pic mleko.

Kod wykonywany:

#include <iostream>
#include <string.h>
using namespace std;

unsigned char tablica[260];

int main() {
            FILE *my_file = fopen("1.txt", "rb");

            int k = 0;
            while (!feof(my_file)) {
                                        int z = fgetc(my_file);
      
                                        printf("%c,",z);
	                                    k++;}
    
            fclose(my_file);

            cout << "Rozmiar pliku to: " << k-1 << " bajtow";

            return 0;}

Wynik:
tmp1.jpg
Kod drugi:

#include <iostream>
#include <string.h>
using namespace std;

unsigned char tablica[260];

int main() {
            FILE *my_file = fopen("1.txt", "rb");

            int k = 0;
            while (!feof(my_file)) {
                                        int z = fgetc(my_file);
      
                                        printf(",%c",z);
	                                    k++;}
    
            fclose(my_file);

            cout << "Rozmiar pliku to: " << k-1 << " bajtow";

            return 0;}

tmp2.jpg
Błędny zapis binarny

Zamieniam printf("%c,",z); na printf(",%c",z); i kompiluje poprawnie.
Błędny zapis (ze znakiem 44 za literą)
tmp3.jpg
I poprawny (ze znakiem 44 przed literą)
tmp4.jpg

Już dobrze mareczku masz

//błędny wynik - litera A z przodu  , (44) za nią
01000001,00101100,01101100,00101100,01100001,00101100,00100000,00101100,01101101,00101100,01100001,00101100,00100000,00101100,01101011,00101100,01101111,00101100,01110100,00101100,01100001,00101100,00100000,00101100,01101001,00101100,00100000,00101100,01110100,00101100,01100101,00101100,01101110,00101100,00100000,00101100,01101011,00101100,01101111,00101100,01110100,00101100,00100000,00101100,01101010,00101100,01100101,00101100,01110011,00101100,01110100,00101100,00100000,00101100,01100010,00101100,01100001,00101100,01110010,00101100,01100100,00101100,01111010,00101100,01101111,00101100,00100000,00101100,01110010,00101100,01110101,00101100,01100100,00101100,01111001,00101100,00101110,00101100,00001101,00101100,00001010,00101100,01001011,00101100,01101111,00101100,01110100,00101100,00100000,00101100,01110100,00101100,01100101,00101100,01101110,00101100,00100000,00101100,01101010,00101100,01100101,00101100,01110011,00101100,01110100,00101100,00100000,00101100,01111010,00101100,01100001,00101100,01100100,00101100,01100010,00101100,01100001,00101100,01101110,00101100,01111001,00101100,00101110,00101100,00001101,00101100,00001010,00101100,01001001,00101100,00100000,00101100,01101100,00101100,01110101,00101100,01100010,00101100,01101001,00101100,00100000,00101100,01110000,00101100,01101001,00101100,01100011,00101100,00100000,00101100,01101101,00101100,01101100,00101100,01100101,00101100,01101011,00101100,01101111,00101100,00101110,00101100,11111111,00101100,Rozmiar pliku to: 81 bajtow

poprawnie wyświetlony

00101100,01000001,00101100,01101100,00101100,01100001,00101100,00100000,00101100,01101101,00101100,01100001,00101100,00100000,00101100,01101011,00101100,01101111,00101100,01110100,00101100,01100001,00101100,00100000,00101100,01101001,00101100,00100000,00101100,01110100,00101100,01100101,00101100,01101110,00101100,00100000,00101100,01101011,00101100,01101111,00101100,01110100,00101100,00100000,00101100,01101010,00101100,01100101,00101100,01110011,00101100,01110100,00101100,00100000,00101100,01100010,00101100,01100001,00101100,01110010,00101100,01100100,00101100,01111010,00101100,01101111,00101100,00100000,00101100,01110010,00101100,01110101,00101100,01100100,00101100,01111001,00101100,00101110,00101100,00001101,00101100,00001010,00101100,01001011,00101100,01101111,00101100,01110100,00101100,00100000,00101100,01110100,00101100,01100101,00101100,01101110,00101100,00100000,00101100,01101010,00101100,01100101,00101100,01110011,00101100,01110100,00101100,00100000,00101100,01111010,00101100,01100001,00101100,01100100,00101100,01100010,00101100,01100001,00101100,01101110,00101100,01111001,00101100,00101110,00101100,00001101,00101100,00001010,00101100,01001001,00101100,00100000,00101100,01101100,00101100,01110101,00101100,01100010,00101100,01101001,00101100,00100000,00101100,01110000,00101100,01101001,00101100,01100011,00101100,00100000,00101100,01101101,00101100,01101100,00101100,01100101,00101100,01101011,00101100,01101111,00101100,00101110,00101100,11111111,Rozmiar pliku to: 81 bajtow
1

Zapewne na początku pliku jest Byte Order Mark (BOM).
Najlepiej załącz plik do pytania, zamiast copy paste do treści.
Jaki system, jaki kompilator, jakie ustawienia locale?

1

https://godbolt.org/z/W8bnezzeq

Pokaż hexem zawartość pliku.

xxd 1.txt
1

zachęcam do zainstalowania notepad++ , w menu "encoding" jest wiele przydatnych elementów
a drugi przydany program to np. HxD

0
MarekR22 napisał(a):

Zapewne na początku pliku jest Byte Order Mark (BOM).
Najlepiej załącz plik do pytania, zamiast copy paste do treści.
Jaki system, jaki kompilator, jakie ustawienia locale?

tmp5.jpg

0

Spróbuj ten kod:

#include <iostream>
#include <cstring>

unsigned char tablica[260];

int main()
{
    static const char FileName[] = "1.txt";
    FILE* my_file = fopen(FileName, "rb");
    if (!my_file)
    {
        std::perror(FileName);
        return 1;
    }
    int k = 0;
    int z;
    while ((z = fgetc(my_file)) != EOF) {
        if (z < 0)
        {
            printf(" 0x%x ", z);
        } else {
            printf("%c,", z);
        }
        k++;
    }

    fclose(my_file);

    std::cout << "Rozmiar pliku to: " << k - 1 << " bajtow";

    return 0;
}
0

Wynik tego " printf(" 0x%x ", z);"
tmp5.jpg

0

To kod w konkursie ?

Jesli tak, i jeśli to konkurs na najbrzydszy konglomerat C/C++, to wygrałeś.

Skąd maniera binarny tryb czytania pliku, a przez fgetc() ?
W tej nazwie 'c' to character, i uwierz mi są ku temu niepomijalne powody

0

Co było błedem? Bo to dosyć Ciekawe.

Czemu plik tekstowy czytasz jako binary? Na windows to chyba ma znaczenie, np. Carrige return może chyba narobić syfu.

Niestety nie mam windy więc nie mam jak sprawdzić, jestem na wakacjach i ciężko się pisze z tel.

plik powodujący błędy powinien być zamieszczony w zipie do pobrania dla każdego. Imho błąd jest w pliku.

Pozdrawiam, jednak czasem napiszesz coś ciekawego. Bo zazwyczaj to jest tragedia ;)

0

@ksh:
Masz
1.txt

tmp1.jpg

0
MarekR22 napisał(a):

Spróbuj ten kod:

#include <iostream>
#include <cstring>

unsigned char tablica[260];

int main()
{
    static const char FileName[] = "1.txt";
    FILE* my_file = fopen(FileName, "rb");
    if (!my_file)
    {
        std::perror(FileName);
        return 1;
    }
    int k = 0;
    int z;
    while ((z = fgetc(my_file)) != EOF) {
        if (z < 0)
        {
            printf(" 0x%x ", z);
        } else {
            printf("%c,", z);
        }
        k++;
    }

    fclose(my_file);

    std::cout << "Rozmiar pliku to: " << k - 1 << " bajtow";

    return 0;
}

V2:

#include <iostream>
#include <cstring>

int main()
{
    static const char FileName[] = "1.txt";
    FILE* my_file = fopen(FileName, "rb");
    if (!my_file)
    {
        std::perror(FileName);
        return 1;
    }
    int k = 0;
    int z;
    while ((z = fgetc(my_file)) != EOF) {
        if (z < 0 || z > 127)
        {
            printf(" 0x%x ", z);
        } else {
            printf("%c,", z);
        }
        k++;
    }

    fclose(my_file);

    std::cout << "Rozmiar pliku to: " << k - 1 << " bajtow";

    return 0;
}
  1. prosiłem, byś załączył plik wejściowy nadal go nie widzę.
  2. założyłem, że znaki none ASCII będą zwracane przez fgets jak ujemne. Najwyraźniej się myliłem. Po tej zmianie wszystkie znaki nie ASCII bedą wyświetlone jako hex.

https://godbolt.org/z/Kq4q63Ts4

0
,,l,a, ,m,a, ,k,o,t,a, ,i, ,t,e,n, ,k,o,t, ,j,e,s,t, ,b,a,r,d,z,o, ,r,u,d,y,.,
,K,o,t, ,t,e,n, ,j,e,s,t, ,z,a,d,b,a,n,y,.,
,I, ,l,u,b,i, ,p,i,c, ,m,l,e,k,o,.,Rozmiar pliku to: 80 bajtow
--------------------------------
Process exited after 0.1643 seconds with return value 0
Press any key to continue . . .
1

Dziwne!
Ten plik nie ma BOM lub znaków none-ASCII
Przez jakiś czas odtwarzałem problem u siebie na clang 15.0.0 MacOS, ale po paru eksperymentach działa normalnie i nie jestem w stanie wrócić do stanu z błedem.

0
MarekR22 napisał(a):

Dziwne!
Ten plik nie ma BOM lub znaków none-ASCII
Przez jakiś czas odtwarzałem problem u siebie na clang 15.0.0 MacOS, ale po paru eksperymentach działa normalnie i nie jestem w stanie wrócić do stanu z błedem.

Problem jest w wyświetleniu, dane wczytuje prawidłowo.
Namierzyć chyba to można jedynie analizując zapis bitowy jaki dałem na początku.

Jak wyświetlisz cokolwiek (np. spację) przed wejściem do pętli to ignoruje ten znak.

2

Ok znowu odtwarzam:
Mam na moim terminalu wychodzi coś takiego:

$ ./a.out | xxd
00000000: 412c 6c2c 612c 202c 6d2c 612c 202c 6b2c  A,l,a, ,m,a, ,k,
00000010: 6f2c 742c 612c 202c 692c 202c 742c 652c  o,t,a, ,i, ,t,e,
00000020: 6e2c 202c 6b2c 6f2c 742c 202c 6a2c 652c  n, ,k,o,t, ,j,e,
00000030: 732c 742c 202c 622c 612c 722c 642c 7a2c  s,t, ,b,a,r,d,z,
00000040: 6f2c 202c 722c 752c 642c 792c 2e2c 0d2c  o, ,r,u,d,y,.,.,
00000050: 0a2c 4b2c 6f2c 742c 202c 742c 652c 6e2c  .,K,o,t, ,t,e,n,
00000060: 202c 6a2c 652c 732c 742c 202c 7a2c 612c   ,j,e,s,t, ,z,a,
00000070: 642c 622c 612c 6e2c 792c 2e2c 0d2c 0a2c  d,b,a,n,y,.,.,.,
00000080: 492c 202c 6c2c 752c 622c 692c 202c 702c  I, ,l,u,b,i, ,p,
00000090: 692c 632c 202c 6d2c 6c2c 652c 6b2c 6f2c  i,c, ,m,l,e,k,o,
000000a0: 2e2c 526f 7a6d 6961 7220 706c 696b 7520  .,Rozmiar pliku 
000000b0: 746f 3a20 3830 2062 616a 746f 77         to: 80 bajtow
$ ./a.out 
,,l,a, ,m,a, ,k,o,t,a, ,i, ,t,e,n, ,k,o,t, ,j,e,s,t, ,b,a,r,d,z,o, ,r,u,d,y,.,
,K,o,t, ,t,e,n, ,j,e,s,t, ,z,a,d,b,a,n,y,.,
,I, ,l,u,b,i, ,p,i,c, ,m,l,e,k,o,.,Rozmiar pliku to: 80 bajtow$ 

Nie mam pojęcia o co chodzi.

2

Problem jest spowodowany przez znak CR na końcu linii będący częścią windowsowego końca linii: CR LF.
Wystarczy zmienić linię

if (z < 0 || z > 127)

na

if( z < 0 || z > 127 || z == 13 )

i wszystko działa poprawnie.
Skoro CR to ‛powrót karetki’, to może być jakiś problem z przejściem do nowej linii z pierwszego znaku wyjścia (gdy nie ma poprzedzających znaków).

0
overcq napisał(a):

Problem jest spowodowany przez znak CR na końcu linii będący częścią windowsowego końca linii: CR LF.
Wystarczy zmienić linię

if (z < 0 || z > 127)

na

if( z < 0 || z > 127 || z == 13 )

i wszystko działa poprawnie.
Skoro CR to ‛powrót karetki’, to może być jakiś problem z przejściem do nowej linii z pierwszego znaku wyjścia (gdy nie ma poprzedzających znaków).

Hm, właśnie zauważyłem, że poprawiasz nie mój kod. Ale masz rację, odczytałem 4 pierwsze znaki i wczytało poprawnie. Nie mniej obchodzenie danego kodu nie jest chyba tym co zawodowcy robią, bo obejść to można na milion sposobów.

Ale ogólnie usuwam "," i działa poprawnie.

6

Ten ‚błąd’ to jest poprawne zachowanie.
Zauważ, że wypisujesz tekst “Ala ma kota i ten kot jest bardzo rudy.”. Następnie wypisujesz ‛powrót karetki’, która wraca na początek linii. Wtedy nadpisujesz już wypisaną literę “A” znakiem przecinka (CR czyli ‛powrót karetki’ nie jest wyświetlany jako znak funkcją “printf”). Wtedy wypisujesz LF czyli przejście do nowej linii. W kolejnych liniach już był wypisany przecinek jako pierwszy znak, więc zostaje on zastąpiony tym samym znakiem. Wszystko wyjaśnione.

1

Czyli krótko mówiąc kod jest poprawny w sensie że prawidłowo czyta plik.
Problem jest z reprezentacją tego na ekranie, wszystkie znaki < 32 to znaki sterujące
https://pl.wikipedia.org/wiki/Kod_steruj%C4%85cy

Znak #13 wraca na początek linii ale podobnie znak #9 zrobi tabulację, znak #8 usunie ostatni znak, znak #7 spowoduje sygnał dźwiękowy a znak #27 zacznie escape sequence co w niektórych terminalach pozwala na zmianę koloru tekstu i tła.
Para #13#10 (\r\n) zazwyczaj występuje razem i przenosi kursor najpierw na początek linii i o jedną linijkę w dół. Ty rozdzielasz te znaki przecinkiem więc przecinek trafia w inne miejsce niż byś tego chciał.
Najlepiej zamień wszystkie kody sterujące (0-31,127) na spację lub jakiś znak specjalny zanim będziesz próbował to wyświetlić na ekranie.

To nie jest "obchodzenie" problemu tylko poprawne obsłużenie przypadku.

0

Wynik działania kodu po usunięciu przecinka

Ala ma kota i ten kot jest bardzo rudy.
Kot ten jest zadbany.
I lubi pic mleko. Rozmiar pliku to: 81 bajtow
--------------------------------
Process exited after 0.1819 seconds with return value 0
Press any key to continue . . .

Czemu tu tu nie robi tego samego?

0
overcq napisał(a):

Ten ‚błąd’ to jest poprawne zachowanie.
Zauważ, że wypisujesz tekst “Ala ma kota i ten kot jest bardzo rudy.”. Następnie wypisujesz ‛powrót karetki’, która wraca na początek linii. Wtedy nadpisujesz już wypisaną literę “A” znakiem przecinka (CR czyli ‛powrót karetki’ nie jest wyświetlany jako znak funkcją “printf”). Wtedy wypisujesz LF czyli przejście do nowej linii. W kolejnych liniach już był wypisany przecinek jako pierwszy znak, więc zostaje on zastąpiony tym samym znakiem. Wszystko wyjaśnione.

Jak śmiesz podważać podstawy religijne.
Nasz apostoł wyższosci C nad resztą języków zapewnia, że obsługuje tryby binarne "jak stary"

Ja wszystko czytam binarnie. Nie rozumiem trybu tekstowego. — johnny_Be_good 2023-09-27 11:45

A na serio: @overcq gratuluję wnikliwości i wiedzy

2

Żeby było śmiesznie - gdyby plik był poprawnie otwarty w trybie tekstowym, to problemu najprawdopodobniej (nie mam Windows i nie chce mi się sprawdzać ;)) by nie było:

https://stackoverflow.com/a/230878

I believe that most platforms will ignore the "t" option or the "text-mode" option when dealing with streams. On windows,
however, this is not the case. If you take a look at the description of the fopen() function at: MSDN, you will see that
specifying the "t" option will have the following effect:

  • line feeds ('\n') will be translated to '\r\n" sequences on output
  • carriage return/line feed sequences will be translated to line feeds on input.

Link do MSDN-a z tamtej odpowiedzi już nie działa:

https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen?view=msvc-170

0
obscurity napisał(a):

Czyli krótko mówiąc kod jest poprawny w sensie że prawidłowo czyta plik.
Problem jest z reprezentacją tego na ekranie, wszystkie znaki < 32 to znaki sterujące
https://pl.wikipedia.org/wiki/Kod_steruj%C4%85cy

Znak #13 wraca na początek linii ale podobnie znak #9 zrobi tabulację, znak #8 usunie ostatni znak, znak #7 spowoduje sygnał dźwiękowy a znak #27 zacznie escape sequence co w niektórych terminalach pozwala na zmianę koloru tekstu i tła.
Para #13#10 (\r\n) zazwyczaj występuje razem i przenosi kursor najpierw na początek linii i o jedną linijkę w dół. Ty rozdzielasz te znaki przecinkiem więc przecinek trafia w inne miejsce niż byś tego chciał.
Najlepiej zamień wszystkie kody sterujące (0-31) na spację lub jakiś znak specjalny zanim będziesz próbował to wyświetlić na ekranie.

To nie jest "obchodzenie" problemu tylko poprawne obsłużenie przypadku.

Jak wykładzik to wykładzik

Null character (ASCII 0): \u0000

Start of Header (ASCII 1): \u0001

Start of Text (ASCII 2): \u0002

End of Text (ASCII 3): \u0003

End of Transmission (ASCII 4): \u0004

Enquiry (ASCII 5): \u0005

Acknowledge (ASCII 6): \u0006

Bell (ASCII 7): \u0007

Backspace (ASCII 8): \u0008

Horizontal Tab (ASCII 9): \u0009

Line Feed (ASCII 10): \u000A

Vertical Tab (ASCII 11): \u000B

Form Feed (ASCII 12): \u000C

Carriage Return (ASCII 13): \u000D

Shift Out (ASCII 14): \u000E

Shift In (ASCII 15): \u000F

Data Link Escape (ASCII 16): \u0010

Device Control 1 (ASCII 17): \u0011

Device Control 2 (ASCII 18): \u0012

Device Control 3 (ASCII 19): \u0013

Device Control 4 (ASCII 20): \u0014

Negative Acknowledge (ASCII 21): \u0015

Synchronous Idle (ASCII 22): \u0016

End of Transmission Block (ASCII 23): \u0017

Cancel (ASCII 24): \u0018

End of Medium (ASCII 25): \u0019

Substitute (ASCII 26): \u001A

Escape (ASCII 27): \u001B

File Separator (ASCII 28): \u001C

Group Separator (ASCII 29): \u001D

Record Separator (ASCII 30): \u001E

Unit Separator (ASCII 31): \u001F
1

Jak masz problemy z przyswojeniem wyjaśnienia, to zobacz cos się dzieje jak spowolni się program:

#include <iostream>
#include <cstring>
#include <thread>
#include <chrono>

int main()
{
    static const char FileName[] = "1.txt";
    FILE* my_file = fopen(FileName, "rb");
    if (!my_file)
    {
        std::perror(FileName);
        return 1;
    }
    int z;
    while ((z = fgetc(my_file)) != EOF) {
        printf("%c", z);
        fflush(stdout);
        std::this_thread::sleep_for(std::chrono::seconds{1});
        printf(",");
        fflush(stdout);
        std::this_thread::sleep_for(std::chrono::seconds{1});
    }

    fclose(my_file);

    return 0;
}

A się pojawi, a potem gdy napis dojdzie do końca linii to A zostanie nadpisane przez przecinek.

0

@MarekR22:
"Jak masz problemy z przyswojeniem wyjaśnienia, to zobacz cos się dzieje jak spowolni się program:"

Patrz:
Wszystko spowolnione.

tmp1.jpg
Jeszcze dodam wyświetlanie binarne, hex, emulator dysku twardego, obsługę zapisu/odczytu przez php, taka zabawka.
Chyba całą zawartość będzie zapisywał przez php jako wirtualny dysk jawny lub niejawny. Może i stan działania programu..
btw chodzi o to
tmp1.jpg

0

no tylko że ten twój "emulator" nie odtwarza zachowania prawdziwego terminala, jeszcze to musisz zaimplementować

0
johnny_Be_good napisał(a):

Patrz:
Wszystko spowolnione.

Niby na co mam patrzeć na statycznym obrazku, skoro w tej poprawce chodzi o to by zobaczyć na konsoli zmiany w czasie.
Najpierw wypisze się powoli napis: A,l,a, ,m,a, ,k,o,t,a, ,i, ,t,e,n, ,k,o,t, ,j,e,s,t, ,b,a,r,d,z,o, ,r,u,d,y,.,
Potem A zmieni się na , a następnie bezie wypisywana kolejna linia.

0

@obscurity:
O to Ci chodziło? Że printf() ma uruchamiać funkcje jak odczyta znaki sterujące? Chyba da radę zrobić.
Żeby zrobił powrót karetki to chyba potrzebuje odczytać liczbę złamań linii i wczytać pierwszy znak po ostatniej.
Tabulację sam dodał.
W sumie mogę dodać własne znaki sterujące. sky is the limit.

1.jpg

2.jpg![3.jpg]

(https://4programmers.net/uploads/120447/A1wsTjWOv5l6RP50eHwrWwEL7sJOp7umXD4eSE0U.jpg)
3.jpg

Tutaj zapisuję do pliku 3 litery (A,B,C) potem je kopiuje i wyświetlam w jednym podglądzie normalnym a w drugim dziesiętnym.4.jpg6.jpg

0
johnny_Be_good napisał(a):

@obscurity:
O to Ci chodziło? Że printf() ma uruchamiać funkcje jak odczyta znaki sterujące? Chyba da radę zrobić.
Żeby zrobił powrót karetki to chyba potrzebuje odczytać liczbę złamań linii i wczytać pierwszy znak po ostatniej.
Tabulację sam dodał.
W sumie mogę dodać własne znaki sterujące. sky is the limit.

1.jpg
2.jpg

Co to jest za edytor? ( ಠ_ಠ)

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