Uruchamianie programu z argumentami początkowymi.

Uruchamianie programu z argumentami początkowymi.
WA
  • Rejestracja:około 8 lat
  • Ostatnio:ponad 6 lat
  • Postów:15
0

Witam,
mam do napisania program w C, który w zależności od wybranej opcji (wpisanej jako parametr) ma wykonywać inną rzecz. Program ma mieć 4 opcje oznaczone jako "-i" (zamiana stdin z plikiem podanym jako kolejny argument, czyli rozumiem, że ma otwierać dany plik, pobierać znaki i wyświetlać je na ekran), "-o" (tak samo jak -i, tylko zamiast pobierać znaki, wpisujemy coś z klawiatury i zapisujemy do podanego w argumencie pliku), "-O" (podobnie jak -o ale tutaj dopisujemy, zamiast nadpisywać), "-q" (ignorowanie komunikatów o błędach). Czyli wywołanie programu w konsoli to przykładowo ./nazwa_programu -i plik1 -o plik2, albo np. ./nazwa_programu -i -O plik. No i udało mi się napisać coś takiego:

Kopiuj
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int main(int argc, char *argv[]){
	char s;
	FILE *plik;
	int i=1;
	printf("%d\n",argc);
	while(i<argc){
		if(strcmp(argv[i],"-i")==0){
			plik = fopen(argv[i+1],"r");
			while(fscanf(plik,"%c",&s)!=EOF){
				printf("%c",s);
			}
		fclose(plik);
		}
		if(strcmp(argv[i],"-o")==0){
			plik = fopen(argv[i+1],"w");
			while(s!='\n'){
				scanf("%c",&s);
				fprintf(plik,"%c",s);	
			}
		fclose(plik);
		}
		if(strcmp(argv[i],"-O")==0){
			plik = fopen(argv[i+1],"a");
			while(s!='\n'){
				scanf("%c",&s);
				fprintf(plik,"%c",s);
			}
		fclose(plik);
		}
		i+=2;
	}
	if(argc==1){
		printf("Wczytaj znaki: ");
		while(1){
			scanf("%c",&s);
			printf("%c",s);
		}
	}	
	return 0;
}

no i generalnie każda z trzech opcji (-q jeszcze nie dodawałem) działa poprawnie, ale wyłącznie jeśli uruchamiamy program tylko z jedną opcją, czyli np. ./nazwa_programu -i plik, ale jak już chce dołączyć dowolną kolejną opcję to już nie działa tak jak trzeba. Jeśli np. uruchomię ./nazwa_programu -i plik1 -O plik1, to program pobierze z pliku plik1 znaki, wypisze je na ekran, ale już nie wykona drugiej opcji, czyli nie nadpisze potem do pliku plik1, tzn. w ogóle nie można potem już nic pisać z klawiatury w konsoli. I teraz moje pytanie brzmi, jak to można zmodyfikować, albo w ogóle napisać żeby można było te wszystkie opcje łączyć (wykonywać jedna po drugiej)? Poza tym sposób jaki zastosowałem w tym kodzie nie jest zbyt uniwersalny, bo na sztywno przyjąłem, że podczas wywołania zawsze będzie jakaś opcja i potem nazwa pliku, a więc dla indeksów nieparzystych mam te opcje, a dla parzystych pliki (w sensie w tablicy argv[]), ale jeśli miałbym np. wywołanie postaci ./nazwa_programu -o -i plik, to wtedy ten sposób nie zadziała, bo tam gdzie jest "-i" będzie chciał otwierać plik (to jest argv[2] - czyli indeks parzysty).
Także podsumowując przede wszystkim jak poprawić ten kod, aby móc wykonywać wszystkie podane opcje po sobie oraz ewentualnie jak zmodyfikować, aby ten program był bardziej uniwersalny? Dziękuję za wszelkie wskazówki

edytowany 1x, ostatnio: Waszok
Bartosz36
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 3 lata
  • Postów:348
0

Przede wszystkim dlaczego:

Kopiuj
i+=2;

W ten zaczynając od drugiego elementu (czyli argumentu po nazwie) od razu przeskakujesz do czwartego, którego możliwe nawet, że nie podałeś... Spróbuj inkrementować licznik i++;

A co do uniwersalności... jest wiele sposobów, ale przede wszystkim myśl o programie jak o kolejnych etapach/elementach/cegłówkach/klockach... Zrób funkcję pobierającą kolejny argument, funkcję sprawdzającą liczbę argumentów, ich formę, zrób funkcje parsujące odpowiednie argumenty, a może i uniwersalną dla wszystkich? Może jakiś switch() case w środku?


ExtendedVector czyli std::vector<T> z wygodą List<T> z .NET (ForEach, FindAll, itd...)
WA
  • Rejestracja:około 8 lat
  • Ostatnio:ponad 6 lat
  • Postów:15
0
Kopiuj
i+=2;

dlatego, że tak jak napisałem na sztywno przyjąłem, że najpierw jest opcja, potem plik i tak na przemian, więc jakbym inkrementował o 1, to wpisując ./nazwa_programu -i -o plik, to argv[1]="-i", czyli w odpowiednim ifie miałbym

Kopiuj
plik = fopen(argv[i+1],"r")

a w tym przypadku i+1=2, a więc próbowałbym otworzyć "-o", bo argv[2]="-o" - od razu dostałbym błąd.
O zastosowaniu swich() case myślałem, ale nie wiem jak go użyć w tym przypadku.
Wiesz dlaczego ten kod nie działa tak jak trzeba, tzn. dlaczego nie mogę uruchomić programu z więcej niż jedną opcją?

edytowany 2x, ostatnio: Waszok
Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
0

Zacznij od napisania tej aplikacji tak, aby nie było tam kopiuj-wklej.


Bartosz36
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 3 lata
  • Postów:348
0

No dobra, to od początku:

  • Co otrzymujesz, gdy uruchamiasz ten program z większą ilością parametrów? Program kończy się normalnie? Przestaje działać?
  • Czy udaje Ci się otworzyć podany plik?
  • Dlaczego zmienna s nie jest zainicjalizowana jakąś wartością? To może powodować problemy! Nadaj jej przynajmniej wartość zero...

ExtendedVector czyli std::vector<T> z wygodą List<T> z .NET (ForEach, FindAll, itd...)
WA
  • Rejestracja:około 8 lat
  • Ostatnio:ponad 6 lat
  • Postów:15
0

No więc, tak jak pisałem, jeśli jest jedna opcja to wszystko działa ok.
Jeśli natomiast uruchomię to następująco: ./nazwa_programu -i plik -o plik, to pierwsza opcja się wykonuje tzn. otwiera dany plik sczytuje znaki i wypisuje na ekran, potem chyba otwiera plik ponownie (aby wykonać opcję -o) ale nie mam możliwości nic wpisać z klawiatury, po prostu program kończy działanie, a wynikiem jest to co sczytało w opcji -i. A domyślam się, że program otwiera plik dla opcji -o, bo wszystko co w nim do tej pory było zostaje usunięte (po wykonaniu programu plik jest pusty), czyli tak jakby program właśnie otworzył plik, przygotował go odpowiednio, ale ponieważ nic nie mogę podać z klawiatury to plik ostatecznie jest pusty.
Z pozostałymi opcjami jest podobnie, czyli zwykle jedna (niekoniecznie pierwsza) się wykonuje, a pozostałe nie lub nie do końca, ale zawsze program się kończy bez żadnych błędów.

Zainicjowanie zmiennej s nic nie pomogło.

edytowany 2x, ostatnio: Waszok
WA
  • Rejestracja:około 8 lat
  • Ostatnio:ponad 6 lat
  • Postów:15
0

Nadanie początkowej wartości zmiennej s nic nie pomaga, ustawiłem:

Kopiuj
char s = 0;

i wszystko jest bez zmian

Bartosz36
  • Rejestracja:ponad 10 lat
  • Ostatnio:ponad 3 lata
  • Postów:348
1

Problem polega na tym, że Twoja zmienna s jest dostępna dla wszystkich opcji, znajduje się na samej górze głównej funkcji.
Natomiast ten warunek:

Kopiuj
            while( s != '\n' ){
                scanf( "%c", &s );
                fprintf( plik, "%c", s );
            }

Skutecznie uniemożliwia Ci wpisanie znaków, ponieważ wciąż przechowuje znak z pliku...
Rozwiązaniem jest umieszczenie zmiennej w każdym z tych procesów/opcji lub przynajmniej utworzenie jej w kolejnej iteracji pętli głównej.

Pomogę... Coś takiego:

Kopiuj
    while( i<argc ){
        char s = 0;
        if( strcmp( argv[ i ], "-i" ) == 0 ){
            plik = fopen( argv[ i + 1 ], "r" );
            while( fscanf( plik, "%c", &s ) != EOF ){
                printf( "%c", s );
            }
            fclose( plik );
        }
/* Tutaj dalszy Twój kod... */

może rozwiązać problem.
(nie zapomnij też dodać zmiennej s dla:

Kopiuj
    if( argc == 1 ){
        char s = 0;
        printf( "Wczytaj znaki: " );
        while( 1 ){
            scanf( "%c", &s );
            printf( "%c", s );
        }
    }

ExtendedVector czyli std::vector<T> z wygodą List<T> z .NET (ForEach, FindAll, itd...)
edytowany 1x, ostatnio: Bartosz36
WA
  • Rejestracja:około 8 lat
  • Ostatnio:ponad 6 lat
  • Postów:15
0

Ok, tak właśnie zrobiłem i teraz działa! Dziękuję.
Teraz jednak warto zmodyfikować kod, tak aby na sztywno nie mieć określonej tej reguły wpisywania opcja/plik opcja/plik itd, tylko właśnie aby móc inkrementować i o 1 i w dowolnej formie podawać te argumenty, czyli zamiast np. ./nazwa_pliku -i plik -O plik móc podać ./nazwa_pliku -i -O plik.
Poza tym fajnie jakby "\n" nie kończyło wpisywania, ale żeby móc je kończyć jakoś inaczej, np. jakimś innym przyciskiem, typu "ESC", bo jeśli chciałbym wpisać do pliku kilka linii tekstu, to potrzebuję "enter" a w tym momencie po wciśnięciu "enter" kończy się całe wpisywanie z klawiatury ...
.

Potat0x
  • Rejestracja:ponad 8 lat
  • Ostatnio:18 dni
  • Postów:370
0

Możesz też użyć getopt, tu masz więcej info i przykład http://man7.org/linux/man-pages/man3/getopt.3.html

hauleth
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:16 dni
0

@Waszok: mała porada. stdin traktuj jak plik. Dzięki temu piszesz:

Kopiuj
FILE* infile;
if (from_stdin) {
  infile = stdin;
} else {
  infile = fopen(file, "r");
}

if (infile == NULL) error("Cannot open file", quiet);

FILE* outfile;
if (to_stdout) {
  outfile = stdout;
} else {
  outfile = fopen(file, append ? "a" : "w");
}

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)