Program wyszukujący w pliku linie tekstu zawierające wyrazy ‘wzorzec’ podane jako kolejne argumenty.

0

Mam takie zadanie:

Plik: szukacz.c

Uruchamianie: ./szukacz <plik> <wzorzec1> [wzorzec2]...

Treść: Napisz program, który otworzy plik, którego ścieżka podana jest jako argument wywołania programu po czym, wyszuka w nim linie zawierające teksty ‘wzorzec’ podane jako kolejne argumenty.

Wyjście: ./szukacz lokomotywa.txt wagon buch
Linie zawierające słowo “wagon”:
I pełno ludzi w każdym wagonie,
A czwarty wagon pełen bananów,
A tych wagonów jest ze czterdzieści,
Szarpnęła wagony i ciągnie z mozołem,

Linie zawierające słowo “buch”:
Żar z rozgrzanego jej brzucha bucha:
Para - buch!
Że pędzi, że wali, że bucha buch, buch?

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

int main(int argc, char* argv[]) {

	if (argc < 3) {
		printf("Uzywaj tego tak: %s <plik> <wzorzec1> [wzorzec2]...", argv[0]);
		return 1;
	}

	FILE* tekst;
		tekst = fopen(argv[1], "r");

		if (tekst == NULL) {
			printf("Blad przy otwieraniu pliku %s", argv[1]);
			return 2;
		}
  return 0;
}


Na razie napisałam tyle i nie wiem dlaczego, ale nie znajduje mi tego pliku.
poza tym nawet jakby mi go w końcu otworzyło to nie za bardzo wiem co dalej...

1
  1. Popraw wcięcia.
  2. U mnie działa. 🤷
  3. Robisz sobie odpowiednio dużą tablicę na wczytywane linijki, korzystając z fgetshttps://en.cppreference.com/w/c/io/fgets ← wczytujesz linijki, używasz strstrhttps://en.cppreference.com/w/c/string/byte/strstr ← do znalezienia szukanego wzorca.
2

Na razie napisałam tyle i nie wiem dlaczego, ale nie znajduje mi tego pliku.

Strzał Szklanej Kuli: masz włączone ukrywanie rozszerzeń znanych plików w Eksploratorze, i Twój plik tak naprawdę nazywa się plik.txt.txt.

0

@Althorion:

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

int main(int argc, char* argv[]) {

	if (argc < 3) {
		printf("Uzywaj tego tak: %s <plik> <wzorzec1> [wzorzec2]...", argv[0]);
		return 1;
	}

	FILE* tekst;
		tekst = fopen(argv[1], "r");

		if (tekst == NULL) {
			printf("Blad przy otwieraniu pliku %s", argv[1]);
			return 2;
		}

    char buf[100];
    while (fgets(buf, sizeof buf, tekst) != NULL){
          printf("%s", buf);
    }

    printf("\n");
    if (feof(tekst)){
       puts("---------------Koniec pliku---------------");
            fclose( tekst );
        }

    int i;
    for(i=2; i<=argc+1; i++){
    char * wynik = strstr( buf, argv[i] );
        if(*wynik != NULL){
        printf("Znaleziono '%s' w linijce: \n", argv[i]);
        printf("%s", *wynik);
        }
    }
	return 0;
}


Pokazuje mi tekst z pliku, ale nie wyszukuje wyrazów. poza tym nie jestem pewna jak zrobić żeby po znalezieniu wyświetlało całą linijkę w której był ten wyraz?

0
    for(i=2; i<=argc+1; i++){
    char * wynik = strstr( buf, argv[i] );
        if(*wynik != NULL){
        printf("Znaleziono '%s' w linijce: \n", argv[i]);
        printf("%s", *wynik);
        }
    }

Ten for jest mocno z kosmosu. Po czym Ty chcesz iterować? Zauważ, gdzie wczytujesz tekst, i tam szukaj.

0

@Althorion:

int i = 2;
    while(i<=argc+1){
    char * wynik;
    wynik = strstr( buf, argv[i] );
        if(*wynik != NULL){
        printf("Znaleziono '%s' w linijce: \n", argv[i]);
        printf("%s", wynik);
        }
        else{
            i++;
        }

?

0

OK, to spróbujmy od innej strony. Parę linijek wyżej masz:

char buf[100];
while (fgets(buf, sizeof buf, tekst) != NULL) {
    printf("%s", buf);
}

Odpowiedz sobie najpierw na te pytania:

  1. Co robi ta pętla?
  2. Gdzie lądują linijki wczytywanego tekstu?
  3. Gdzie się kończy „widoczność” każdej z linijek tekstu?
  4. Co będzie w buf po zakończeniu tej pętli?

I jak już się z tym uporasz, popatrz na tego Twojego whilea z posta wyżej:

int i = 2;
    while(i<=argc+1){
    char * wynik;
    wynik = strstr( buf, argv[i] );
        if(*wynik != NULL){
        printf("Znaleziono '%s' w linijce: \n", argv[i]);
        printf("%s", wynik);
        }
        else{
            i++;
        }

I teraz:

  1. Co to za wcięcia, na bogów!?
  2. Dlaczego od i = 2? Czym jest tutaj i?
  3. Czym jest argc?
  4. Jaki ma zwiąek argv z zawartością pliku?
  5. Po czym tak naprawdę iterujesz i czemu?

To powinno Ci pozwolić dostrzec, co jest nie tak, i dlaczego. Idealnie też, jak to naprawić. Jeśli nie, wróć z odpowiedziami na powyższe pytania i swoimi pytaniami.

0

@Althorion:
Domyślam się, że linijki tekstu lądują w buf, ale są nadpisywane za każdym razem jak robi się pętla, przez co po jej zakończeniu będzie tam tylko ostatnia linijka. Nie rozumiem jednak co dokładnie oznacza buf[100]? Tablice znaków? Czemu wszystko działa tak samo nawet przy buf[2], ale przy buf[1] juz nie?
"i" dałam na 2 bo jest to pierwszy z wyrazów których szukam (z wiersza poleceń), a następnie szuka kolejnych?

0

To nie jest odpowiedź na wszystkie pytania, ale dobra. Zakładam, że to wynika z tego, że na pozostałe nie byłeś w stanie odpowiedzieć, a nie z tego, że Ci się nie chciało — bo gdyby tak było, zmarnowałbyś nie tylko mój, ale i swój czas…

Zakładasz dobrze, fgets wczytuje tekst do buf, bo tak mu kazałeś w linijce fgets(buf, sizeof buf, tekst). Jak mówi dokumentacja, funkcja ta wczyta co najwyżej sizeof buf minus jeden znaków do buf, skończy na znaku nowej linii jeśli wcześniej niż sizeof buf minus jeden, z pliku tekst.

char buf[100] jest definicją stuelementowej tablicy charów o nazwie buf. O tablicach powinieneś mieć wykład na pierwszych czy drugich zajęciach, przeczytaj sobie notatki z nich jeszcze raz, żeby sobie przypomnieć, jak to tam działa. Gdzieś w tamtych okolicach powinna być też zawarta wiedza o tym, co C rozumie poprzez stringi — tablice charów zakończone NULL-em, czyli znakiem o wartości zero, zapisywanym w C jako \0.

Czemu działa przy buf[2]: buf[2] rezerwuje miejsce tylko dla dwóch znaków (z czego jeden zostanie przeznaczony na NULL-a, stąd to „minus jeden” dwa paragrafy wyżej), z czego użyteczny jest jeden (ten pierwszy). Technicznie rzecz biorąc to wystarcza, żeby móc przepisać tekst. Co prawda, nie linijka po linijce (bo na raz jest tam tylko jeden znak), ale zawsze. buf[1] to jednak tylko jeden znak. Tam się NULL znaleźć musi, żeby oznaczyć koniec stringa. I jak on już tam trafi, to nic innego nie wejdzie… więc kaplica. Ogólnie, tutaj chcesz mieć tyle miejsca, ile potrzebujesz, żeby weszła najdłuższa z linijek. Można dać i te sto na zapas, brzmi jak sensowna wartość. Można w ogóle zaszaleć i dać kilka tysięcy, też się nic nie stanie — pojedynczy char ma rozmiar bajta, a kilka kilobajtów to dla współczesnych komputerów nic. Dopiero jak dojdziesz do okolic dziesiątek milionów, to to zacznie być potencjalny problem.

"i" dałam na 2 bo jest to pierwszy z wyrazów których szukam (z wiersza poleceń), a następnie szuka kolejnych?

A gdzie masz szukać tych wyrazów? W wierszu poleceń, czy w pliku?

0

@Althorion:
przecież 2 wyraz z wiersza poleceń to właśnie ten wyraz którego szukam w pliku?
potem 3 itd.

0

A to ja przepraszam w takim razie, źle zobaczyłem treść — myślałem, że jest tylko jeden wzorzec do wyszukania, a nie więcej. To OK — ta część pętli jest w takim razie jak najbardziej w porządku. Problemem jest więc tylko to, że znajduje się w złym miejscu — nie tam, gdzie buf chwilowo trzyma tekst. Gdzie trzyma, zauważyłeś już wcześniej, więc zostaje Ci ją przenieść w odpowiednie miejsce.

0
#include <stdlib.h>
#include <string.h>

int main(int argc, char* argv[]) {

	if (argc < 3) {
		printf("Uzywaj tego tak: %s <plik> <wzorzec1> [wzorzec2]...", argv[0]);
		return 1;
	}

	FILE* tekst;
		tekst = fopen(argv[1], "r");

		if (tekst == NULL) {
			printf("Blad przy otwieraniu pliku %s", argv[1]);
			return 2;
		}

    char buf[100];
    int i = 2;
    char * wynik;
    while (fgets(buf, sizeof buf, tekst) != NULL){
        while(i<=argc+1){
        wynik = strstr( buf, argv[i] );
            if(*wynik != NULL){
                printf("Znaleziono '%s' w linijce: \n", argv[i]);
                printf("%s", wynik);
            }
            else{
            i++;
            }
        }
    }

    fclose( tekst );
	return 0;
}


teraz nic nie pokazuje...

1

@Althorion, przepraszam ale wg mnie powinieneś jeszcze raz uważnie przeczytać zadanie, łącznie z przykładem.

1

Kompilator sam znajduje problem (tylko ostrzeżenia trzeba mieć włączone):

prog.c: In function 'main':
prog.c:27:23: warning: comparison between pointer and integer
   27 |             if(*wynik != NULL){

Ja bym radził podzielić kod na mniejsze funkcje.
https://wandbox.org/permlink/VTxICXc3rPaL3du5

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