Problem z odczytywaniem pliku txt

0

Witam, cały problem polega na jednym błędzie, którego nie wiem w sumie jak naprawić, czytam kod 10 raz i nadal nie wiem co mam źle. Pisze program w MVS, błędy oraz kod podaje niżej, a cały program ma za zadanie odczytać z pliku txt z pierwszej linijki ilość liczb rzeczywistych zapisanych w tym pliku, a nastepnie zapisac je do tablicy.
Plik txt:

5
4
3
3
2
1

Błędy:
Błąd (aktywny) E0028 wyrażenie musi mieć stałą wartość
Błąd C2131 wyrażenie nie zostało obliczone do stałej.

Kod:

#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;

int main()
{
	fstream plik;
	int dlugosc=0;
	plik.open("b.txt", ios::in);
	if (!plik.good())  cout << "Nie znaleziono pliku";

	while (plik.good())
	{
		plik >> dlugosc;
		int tab[dlugosc];
		for (int i = 0; i < dlugosc; i++)
		{
			plik >> tab[i];
			cout << tab[i] << '\n';
		}

	}
	plik.close();

	return 0;
}
8

Nie podałeś numerów linii (nawiasem mówiąc dla Ciebie to tylko kliknięcie, i już byłbyś na błędnym fragmencie), więc zgaduję.
Taka sekwencja, powszechnie używana przez początkujących, jest wg standardu nielegalna (choć niektóre kompilatory to wybaczają)
Deklarowanie tablicy musi być określone stałą (wyrażeniem stałym), a nie zmienną.

        plik >> dlugosc;
        int tab[dlugosc];

BTW to jest błąd kompilacji (a nie wykonania - powinieneś zacząć to odróżniać), nie dochodzi do żadnego przetwarzania, nijaki odczyt pliku nie zachodzi (czujesz, że temat ujawnia, że szukasz problemu nie tam, gdzie jest), i dane wejściowe nie mają znaczenia.

6

Wielkość tablicy musi być znana w trakcie kompilacji, a Ty wielkość podajesz w trakcie jego wykonywania. Stworzenie tablicy dynamicznej rozwiąże twój problem, ale proponuję użyć kontenera std::vector<int>.

4

Zwróciliście uwagę na problem, ale pozwolę sobie dopisać uwagę. Jest w kodzie linia int dlugosc=0; więc wartość zmiennej jest znana w trakcie kompilacji. Można nawet dopisać constexpr a w GCC użyć przełączników -Wall --pedantic i jedyne, co się pojawi, to ostrzeżenie, że standards ISO C++ zabrania deklaracji tablicy o zerowej długości. Jeśli podamy wartość większą od zera, żadnego ostrzeżenia nie będzie.
Choć gramatyka języka na to pozwala, to - zgodnie z sugestiami wyżej - warto się pilnować. Tak jak z nożem: przeznaczony jest do krojenia mięsa, więc niektórzy myślą, że ludzkie mięso też można tak kroić (nie róbcie tego, nie warto).

EDIT:
Chcąc zweryfikować post niżej przyjrzałem się kodowi i okazało się, że napisałem babola. Dałem do zrozumienia, że można dopisać constexpr do zmiennej a potem zmienić jej wartość. To nieprawda i próba takiej kompilacji się nie powiedzie :) . W podanym przez autora kodzie oczywiście nie można tak robić.

2

Jest tylko zainicjalizowana. Ale nie jest const/constexpr, więc w każdym momencie może się zmienić = nie jest znana w czasie kompilacji.

A jak dodasz constexpr to kompilacja się wywali na linijce plik >> dlugosc;

@Wayne:
Co robisz jak chcesz wczytać tekst z pliku, ale nie znasz jego długości? Używasz klasy std::string, która automatycznie przydzieli odpowiednią ilość pamięci.
Identycznie jest z tablicami. Jeśli nie wiesz ile elementów będziesz potrzebował, to używasz std::vector,

0
tajny_agent napisał(a):

Jest tylko zainicjalizowana. Ale nie jest const/constexpr, więc w każdym momencie może się zmienić = nie jest znana w czasie kompilacji.

A jak dodasz constexpr to kompilacja się wywali na linijce plik >> dlugosc;

@Wayne:
Co robisz jak chcesz wczytać tekst z pliku, ale nie znasz jego długości? Używasz klasy std::string, która automatycznie przydzieli odpowiednią ilość pamięci.
Identycznie jest z tablicami. Jeśli nie wiesz ile elementów będziesz potrzebował, to używasz std::vector,

Jeżeli moge jeszcze zapytać to jest jakaś konkretna różnica między tablicami dynamicznymi, a wektorami? Która z nich jest bardziej optymalna?

2

Wektor jest tablicą dynamiczną. Plusy:

  • "wbudowany" rozmiar i pojemność. Nie musisz tych danych przesyłać oddzielnym argumentem
  • Automatyczne zarządzanie pamięcią. Nie musisz pamiętać o rozszerzaniu czy zwalnianiu pamięci
  • Jako składowa klasy umożliwia stosowanie Rule of Zero
  • Kopiowanie jest banalne (vector<int> nums{1,2,3,4,5}; vector<int> copy = nums;)
  • Prostsze użycie z <algorithm> czy range-for
  • Klasa z biblioteki standardowej, więc zaimplementowana przez łebskich gości i na dodatek solidnie przetestowana.

Używając gołych tablic to wszystko musisz zaimplementować samemu.

0
tajny_agent napisał(a):

Wektor jest tablicą dynamiczną. Plusy:

  • "wbudowany" rozmiar i pojemność. Nie musisz tych danych przesyłać oddzielnym argumentem
  • Automatyczne zarządzanie pamięcią. Nie musisz pamiętać o rozszerzaniu czy zwalnianiu pamięci
  • Jako składowa klasy umożliwia stosowanie Rule of Zero
  • Kopiowanie jest banalne (vector<int> nums{1,2,3,4,5}; vector<int> copy = nums;)
  • Prostsze użycie z <algorithm> czy range-for
  • Klasa z biblioteki standardowej, więc zaimplementowana przez łebskich gości i na dodatek solidnie przetestowana.

Używając gołych tablic to wszystko musisz zaimplementować samemu.

Okej wszystko jasne, dziękuje za dosadne wytłumaczenie, a sam temat można zamknąć.

2
PerlMonk napisał(a):

Zwróciliście uwagę na problem, ale pozwolę sobie dopisać uwagę. Jest w kodzie linia int dlugosc=0; więc wartość zmiennej jest znana w trakcie kompilacji. Można nawet dopisać constexpr a w GCC użyć przełączników -Wall --pedantic i jedyne, co się pojawi, to ostrzeżenie, że standards ISO C++ zabrania deklaracji tablicy o zerowej długości. Jeśli podamy wartość większą od zera, żadnego ostrzeżenia nie będzie.
Choć gramatyka języka na to pozwala, to - zgodnie z sugestiami wyżej - warto się pilnować. Tak jak z nożem: przeznaczony jest do krojenia mięsa, więc niektórzy myślą, że ludzkie mięso też można tak kroić (nie róbcie tego, nie warto).

EDIT:
Chcąc zweryfikować post niżej przyjrzałem się kodowi i okazało się, że napisałem babola. Dałem do zrozumienia, że można dopisać constexpr do zmiennej a potem zmienić jej wartość. To nieprawda i próba takiej kompilacji się nie powiedzie :) . W podanym przez autora kodzie oczywiście nie można tak robić.

Sprawa jest bardziej skomplikowana.
Pod gcc to się skompiluje nawet w orginale.
Generalnie standard C++ nie dopuszcza VLA, więc zgodnie ze standardem C++ nie powinno się kompilować.
Jednak w gcc to się kompiluje, bo by pozwolić na mieszanie C++ i C.
VLA jest dostępne od C99, które gcc wspiera. Domyślne opcje kompilatora gcc czynią VLA dostępne w kodzie C++.
Demo z wyłączonym VLA.

MSVC wspiera bardzo starą wersje C: C90, przez co nie ma tam wcale VLA, bez względu na ustawienia kompilatora i stąd błąd kompilatora opisany przez OP.

1
MarekR22 napisał(a):

Sprawa jest bardziej skomplikowana.

Dlatego wtrąciłem uwagę. Dziękuję za rozwinięcie tematu. Potem ten wątek może coś wnieść w czyjąś naukę C++.

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