Problem z odczytywaniem pliku txt

Problem z odczytywaniem pliku txt
Wayne
  • Rejestracja:ponad 5 lat
  • Ostatnio:ponad 3 lata
  • Postów:31
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:

Kopiuj
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:

Kopiuj
#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;
}
edytowany 1x, ostatnio: Wayne
AK
  • Rejestracja:prawie 7 lat
  • Ostatnio:około miesiąc
  • Postów:3561
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ą.

Kopiuj
        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.


Bo C to najlepszy język, każdy uczeń ci to powie
edytowany 4x, ostatnio: AnyKtokolwiek
Sunnydev
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Nether
  • Postów:235
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>.


lubię tylko w c++ i w rust i w go i w haskell. pythona nie lubię, javy też. c# toleruję.
Wayne
Ponownie rozwiązałeś mój problem, dziękuje raz jeszcze ;)
PerlMonk
  • Rejestracja:około 6 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Warszawa 🐪
  • Postów:1719
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ć.


Nie sztuka uciec gdy w dupie sztuciec. 🐪🐪🐪
edytowany 1x, ostatnio: PerlMonk
tajny_agent
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad rok
  • Postów:1340
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,


"I love C++. It's the best language in the world right now for me to write the code that i need and want to write"
~ Herb Sutter
edytowany 1x, ostatnio: tajny_agent
Wayne
Tak średnio to rozumiem, kompilator wywala, że potrzebuje stałej. Ale przecież ja potrzebuje zmienić wartość tej zmiennej, która znajduje sie w pierwszej linii pliku txt bo według definicji "Zmienne, które używają słowa kluczowego constexpr muszą zostać zainicjalizowane podczas ich tworzenia wartością stałą lub wyrażeniem, które da wartość stałą.", mógłbyś w takim razie troszke jaśniej wyjaśnić co i jak ?
tajny_agent
Odpowiadaj w postach
Wayne
  • Rejestracja:ponad 5 lat
  • Ostatnio:ponad 3 lata
  • Postów:31
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?

edytowany 1x, ostatnio: Wayne
AK
O ile nie masz wyraźnego zakazu używania w/w ze szkoły to warto zawsze używać.
tajny_agent
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad rok
  • Postów:1340
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.


"I love C++. It's the best language in the world right now for me to write the code that i need and want to write"
~ Herb Sutter
Wayne
  • Rejestracja:ponad 5 lat
  • Ostatnio:ponad 3 lata
  • Postów:31
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ąć.

MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:6 minut
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.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 2x, ostatnio: MarekR22
PerlMonk
  • Rejestracja:około 6 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Warszawa 🐪
  • Postów:1719
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++.


Nie sztuka uciec gdy w dupie sztuciec. 🐪🐪🐪

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.