Niepoprawne wczytywanie wejścia przez scanf/cin

1

Cześć!
Mam problem z wczytywaniem wejścia w C++, prawdopodobnie jest to jakaś głupota, ale że nie mam dużej styczności z C++, to nie mogę sobie poradzić.
Oto minimalny kod powodujący problem:

#include <cstdio>
int N, M;

int main() {
	scanf("%d %d", &N, &M);
	printf("Pierwsza linia: %d %d\n", N, M);
	for (int i = 0;i < M;++i) {
		int start, end, weight;
		scanf("%d %d %d", &start, &end, &weight);
		printf("Krawedz %d z %d do %d o wadze %d\n", i, start, end, weight);
		fflush(stdout);
	}
	return 0;
} 

Wczytuję po kolei liczby z pliku i wypisuję je. Plik wejściowy jest w załączniku, jest on dość spory, na mniejszych plikach problemu nie widzę.

Problem jest następujący: w linii 305-306 wejścia mam coś takiego:

235 299 1570
546 129 1935

Jednocześnie program dla tych linii wypisuje:

Krawedz 303 z 235 do 299 o wadze 1570546
Krawedz 304 z 129 do 1935 o wadze 129

Czyli wczytał 1570, zignorował znak nowej linii i dokleił 546 do liczby. Sprawdzałem w Notepad++ i jest tam normalny znak nowej linii (CRLF). Program odpalam z PS tak:
cat "orders05.in" | .\Rozkazy.exe | out-file -encoding ascii "orders05.ans"
Jednocześnie jeżeli w VS 2015 w konfiguracji projektu ustawię w parametrach debugowania przekierowanie pliku jako standardowe wejście i odpalę program przez CTRL+F5, to wszystko jest wczytywane poprawnie. Problem występuje tylko przy uruchamianiu programu z konsoli, próbowałem różnych buildów (debug/release, 32/64 bitowy), próbowałem odpalać program z PS i CMD, za każdym razem jest ten sam błąd. Wrzuciłem kod na ideone i wkleiłem tam plik wejściowy — tam problem nie występuje. Próbowałem zmienić scanf na cin, nie pomogło.

Nie mam pojęcia, co jest nie tak. W załącznikach dodaję też skompilowaną binarkę w trybie debug x64 wraz z symbolami, gdyby ktoś chciał ją dokładniej podebugować. Będę wdzięczny za jakieś sugestie.

0

Spróbuj obejrzeć plik wejściowy hex edytorem w tej okolice.

5

Nazwy zmiennych globalnych powinny zaczynać się od //

0

Hex edytor też twierdzi, że jest tam 0D0A (CRLF).

0

co zwraca scanf?

        int ret=scanf("%d %d %d", &start, &end, &weight);
        printf("Krawedz %d (%d) z %d do %d o wadze %d\n", i, ret, start, end, weight);
0

Po zmianie kodu na:

int scanResult = scanf("%d %d %d", &start, &end, &weight);
printf("%d: wczytano %d elementow, krawedz z %d do %d o wadze %d\n", i, scanResult, start, end, weight); 

wynik to

303: wczytano 3 elementow, krawedz z 235 do 299 o wadze 1570546
304: wczytano 3 elementow, krawedz z 129 do 1935 o wadze 129

Czyli wczytuje tak samo i twierdzi, że wczytał trzy elementy (o ile dobrze rozumiem scanf).

Ponadto po skompilowaniu w VS 2012 i zmianie toolsetu na Visual Studio 2012 (v110) program działa poprawnie także z konsoli. Zaczynam podejrzewać, że trafiłem na jakiś bug, ale nie wiem, jak się upewnić.

1

Przy trafeniu na bug - nie upewnisz się, nie ma takiej możliwości, ewentualnie sprawdź (znowu w hex edytorze) czy ten felerny wiersz nie trafia przypadkiem na koniec początek bufora o rozmiarze jakieś potęgi dwójki:
1024, 2048 itp.

1

To może być to. Felerny znak jest pod adresem 0x00001000, sprawdziłem też adres 0x00002000, tam też jest biały znak i pojawia się zły odczyt, podobnie pod adresem 0x00005000.
Czy ktoś mógłby spróbować odtworzyć problem u siebie? Mam Visual Studio Enterprise 2015, wersja 14.0.24720.00 Update 1.

0

Btw, dlaczego używasz stdio w C++? Odpal to na iostream i zobacz. I odpal to w innym języku jeszcze, pythonie jakimś czy innej javie. Jeśli masz inny kompilator - odpal na innym kompilatorze.

0

A dlaczego nie, przecież jest to normalna część C++. Poza tym napisałem, że „próbowałem zmienić scanf na cin, nie pomogło”, kwestię innych kompilatorów też poruszyłem od razu (ideone).

0

Szukał może ktoś czy nie ma już zgłoszonego bug-a?
Jak dla mnie to jest duży fail i trzeba zgłosić ASAP, bo może to doprowadzić do poważnych przekłamań w ważnym kodzie.
Najlepiej napisać unit test i im wysłać.
Jeśli ktoś zgłosi to niech zapoda tu linka.
Swoją dragą niesamowite, pierwszy wątek na tym forum, który faktycznie natknął się na błąd w implementacji standardowej biblioteki, paluch w górę się należy.

A co do miejsca wystąpienia błędu to bajt 0x0d wypada pod adresem 0xfff a bajt 0x0A pod adresem 0x1000 :) więc sekwencja końca linii wypada na granicy równego adresu.

0

Napisałem PW do @krwq, on chyba pracuje w MS, to może będzie w stanie nas pokierować. Próbowałem googlować, ale nic sensownego nie znalazłem.

2

Jeśli możesz edytować raport to go popraw. Część "opis" powinna od razu przejść do rzeczy. Np:

scanf ignores end of line sequence "\r\n" if character \n is at the 0x1000 position or its multiplicity.

#include <cstdio>
 
int main() {
    int N, M;
    scanf("%d %d", &N, &M);
    for (int i = 0;i < M;++i) {
        int a, b, c;
        scanf("%d %d %d", &a, &b, &c);
        if (c>10000)
        {
            fprintf(stderr, "failed file doesn't contain such big values\n see line nr: %d", i+2);
            return 1;
        }
    }
    return 0;
}

including test data which reproduces the problem

Chrzanienie o Ctrl-F5 to traktowanie kogoś kto jest profesjonalistą jak totalnego idiotę.

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