[c]nowy wiersz, główna funkcja, linux

Awatar użytkownika
Sokół
Użytkownik
Użytkownik
Posty: 451
Rejestracja: 17 wrz 2006, o 19:22
Płeć: Mężczyzna
Lokalizacja: Zielona Góra
Podziękował: 15 razy
Pomógł: 55 razy

[c]nowy wiersz, główna funkcja, linux

Post autor: Sokół »

Podaj przykładowy tekst, ze źle wstawionymi enterami, jaki powoduje wynik, a jaki jest oczekiwany.
madaf007
Użytkownik
Użytkownik
Posty: 131
Rejestracja: 4 wrz 2008, o 17:01
Płeć: Mężczyzna
Lokalizacja: Wrocław
Podziękował: 33 razy

[c]nowy wiersz, główna funkcja, linux

Post autor: madaf007 »

Np. chce przerobić taki tekst:
Litwo Ojczyzno moja ty jestes jak zdrowie Ile cie trzeba cenic ten tylko sie dowie Kto cie stracil
Dzis pieknosc twa w calej ozdobie Widze i opisuje bo tesknie po tobie Panno swieta co Jasnej bronisz Czestochowy I w Ostrej swiecisz Bramie Ty co grod zamkowy Nowogrodzki ochraniasz z jego wiernym ludem Jak mnie dziecko do zdrowia powrocilas cudem Gdy od placzacej matki pod Twoja opieke Ofiarowany martwa podnioslem powieke I zaraz moglem pieszo do Twych
Chciałbym np. żeby jeden wiersz miał maksymalnie 20 znaków
Litwo Ojczyzno moja
ty jestes jak
zdrowie Ile cie trzeba
cenic ten tylko sie
dowie Kto cie stracil
Dzis pieknosc twa w
calej ozdobie Widze
i opisuje bo tesknie
po tobie Panno
swieta co Jasnej bronisz
Czestochowy I w
Ostrej swiecisz Bramie
Ty co grod zamkowy
Nowogrodzki
ochraniasz z jego wiernym
ludem Jak mnie dziecko
do zdrowia
powrocilas cudem Gdy od
placzacej matki pod
Twoja opieke Ofiarowany
martwa podnioslem
powieke I zaraz moglem
pieszo do Twych
Więcej niż 20 znaków mają miedzy innymi wersy:
swieta co Jasnej bronisz
ochraniasz z jego wiernym
powrocilas cudem Gdy od
Może coś nie tak mam z kodem, jeśli tak to mnie skarćcie:

Kod: Zaznacz cały

void newline(char zdanie[], int miejsce)
{
   int spacja=-1;
   int i=0;
   int dlugosc=strlen(zdanie);

          for(i=0; i<dlugosc; ++i)
	  {
                   if(zdanie[i]==' ')
                       spacja=i;
                   if((i % miejsce)==0 && zdanie[i]!='\n')
                            {
                               zdanie[spacja]='\n';
                            }
          }
}
Jeszcze tak przy okazji, jak zwykle czegoś nie wiem;] Otóż muszę jeszcze pododawać marginesy. I za nic nie mam pojęcia jak wstawić dodatkowe spacje na początku każdego wiersza... udaje mi się jedynie w pierwszym wierszu, a dalej nie chce nic ruszyć.
Awatar użytkownika
Sokół
Użytkownik
Użytkownik
Posty: 451
Rejestracja: 17 wrz 2006, o 19:22
Płeć: Mężczyzna
Lokalizacja: Zielona Góra
Podziękował: 15 razy
Pomógł: 55 razy

[c]nowy wiersz, główna funkcja, linux

Post autor: Sokół »

Ok, to już wiadomo co jest nie tak.
Załóżmy, że pętla leci od początku, na 15 pozycji jest spacja, a dalej wyraz, który kończy się na 23-tej pozycji. Program wstawi enter na 16 pozycji. Następnie w tekście jest kilka zwykłych wyrazów, z czego jeden kończy się na 39 pozycji (czyli na miejscu 40 jest spacja). Program wstawi więc enter w miejsce ostatniej spacji przed lub w miejsce, znaku o pozycji 40, czyli na miejscu 40. W rezultacie, drugi wiersz ma ponad 20 znaków (od 17 pozycji do 40 - ze znakiem nowej linii).

Jeśli w wersie ma być maks 20 znaków, to w pętli for dodaj zmienną licznik, która na początku będzie miała wartość 0. Inkrementuj ją wraz z każdym kolejnym przebiegiem pętli i w samej pętli napisz warunek, że kiedy licznik będzie równy maks. ilości znaków w wersie, to ma postawić znak nowej linii w ostatniej spacji, a samą zmienną licznik wyzerować. Po takiej operacji znowu będzie odliczała znaki, od ostatniego znaku nowej linii, aż do osiągnięcia wartości maks. znaków wersie, wtedy znowu nastąpi wpisanie entera i wyzerowanie licznika. Zabezpiecz odpowiednio się w razie występowania długich wyrazów, tzn. żeby nie było sytuacji, że dwa razy enter w tym samym miejscu albo coś. Niech wtedy jakoś przenosi ten wyraz, nie wiem jakie rozwiązanie przewidujesz

Co do marginesów, jak to nazywasz, zobacz jakie w C są operacje na stałych znakowych, tzn. kopiowanie jednej do drugiej etc. Stwórz stringa wynikowego, gdzie będziesz dodawał każdy wers już w wersji finalnej (ze spacjami). Kiedy podzielisz tekst na wersy, możesz pętlą sprawdzać ile znaków znajduje się w takim wersie, zobacz ile spacji brakuje na początku (bo rozumiem, że wiersz ma być uzupełniany spacjami, tak żeby ostatecznie było 20 znaków?) i dopisz tyle spacji do stringu wynikowego, a następnie przekopiuj cały wiersz. Nie ukrywam, że wskaźniki byłyby bardzo pomocne, mógłbyś kopiować stringi precyzyjnie od danego miejsca do danego miejsca, w odpowiednie miejsce w pamięci.
madaf007
Użytkownik
Użytkownik
Posty: 131
Rejestracja: 4 wrz 2008, o 17:01
Płeć: Mężczyzna
Lokalizacja: Wrocław
Podziękował: 33 razy

[c]nowy wiersz, główna funkcja, linux

Post autor: madaf007 »

Ale mi to coś ciężko wchodzi. Sposób Twój jest opisany bardzo zrozumiale. Wiem o co chodzi, ale jeśli już mam przenieść to na C, to mam ogromne problemy. No ale do rzeczy. Funkcja, która stworzyłem na podstawie Twoich rad wygląda następująco:

Kod: Zaznacz cały

void newline(char zdanie[], int miejsce)
{
   int spacja=-1;
   int i=0;
   int dlugosc=strlen(zdanie);
              int j=0;

          for(i=0; i<dlugosc; ++i,++j)
	  {
                   if(zdanie[i]==' ')
                   {
                       spacja=i;
                   }
                   if(j==miejsce)
                   {
                               zdanie[spacja]='\n';
                               j=0;
                   }
           }
}
Nie dostosowałem się dokładnie tak jak napisałeś, bo nie wiedziałem jak licznik ma inkrementować będąc zadeklarowany w pętli. Ale jak na to patrze co napisałem to powinno być już dobrze, ale niestety działa tak jak poprzednio.

EDIT:
Już wiem, czemu działa tak samo jak poprzednio. Po prostu j=0, ale znów liczy od miejsce, a nie od ostatniej spacji. Próbowałem podstawić (spacja=j)==0; ale wtedy tylko w pierwszej linijce robi się znak nowej linii, dalej nie leci.
Awatar użytkownika
Sokół
Użytkownik
Użytkownik
Posty: 451
Rejestracja: 17 wrz 2006, o 19:22
Płeć: Mężczyzna
Lokalizacja: Zielona Góra
Podziękował: 15 razy
Pomógł: 55 razy

[c]nowy wiersz, główna funkcja, linux

Post autor: Sokół »

Rzeczywiście, bo j=0 jest w warunku kiedy j==miejsce, a za pierwszym razem ten warunek zachodzi, kiedy 'i' równe jest maksymalnej ilości znaków w wersie.
Zamiast zmieniać j wartością 0 w pętli for, napisz:

Kod: Zaznacz cały

j=i-spacja
bo dla pewnego j==miejsce, na -tej pozycji może być jakiś znak, czyli jeszcze jakieś słowo. Ostatnia spacja jest kilka pozycji przed -tą, więc nie ma sensu wtedy ustawiać wartość zmiennej j na 0, wtedy nie będzie liczyć ile znaków temu była spacja. Zapisując j=i-spacja uwzględniasz, że przed i po -tej pozycji jest słowo, które będzie w nowej linii. Przeanalizuj na kartce albo w debugerze jak to zachodzi dla dwóch pierwszych wersów inwokacji.
madaf007
Użytkownik
Użytkownik
Posty: 131
Rejestracja: 4 wrz 2008, o 17:01
Płeć: Mężczyzna
Lokalizacja: Wrocław
Podziękował: 33 razy

[c]nowy wiersz, główna funkcja, linux

Post autor: madaf007 »

Dzięki wielkie;] Masz u mnie zgrzewkę piwa:) Rozumiem całkowicie algorytm. Jeszcze "tylko" dodanie spacji i margines. Ciężka noc przede mną.

EDIT: Właśnie znalazłem tekst na którym bedzie sprawdzany ten program. Jest to słownik mający 230tys. słów i program na nim w ogóle nie działa... tak jakby robił i robił i nic sie nie dzieje.
Awatar użytkownika
Sokół
Użytkownik
Użytkownik
Posty: 451
Rejestracja: 17 wrz 2006, o 19:22
Płeć: Mężczyzna
Lokalizacja: Zielona Góra
Podziękował: 15 razy
Pomógł: 55 razy

[c]nowy wiersz, główna funkcja, linux

Post autor: Sokół »

Te 230k słów to spory kawałek pamięci, a u siebie masz tablicę na 1000 znaków (#define MAX 1000). W jaki sposób wczytujesz dane? Być może jest problem z zarządzaniem pamięcią, program wykrzacza się czy po prostu nic się nie dzieje? Spróbuj pododawać instrukcje w kodzie, które pozwolą zobaczyć gdzie tkwi błąd, tzn. czy program w ogóle przechodzi funkcję getline? Jak wygląda plik ze słownikiem? Pokaż też cały kod, po przeróbkach.

Może warto wczytywać plik w którąś z opisanych metod tutaj: ... lik%C3%B3w?
madaf007
Użytkownik
Użytkownik
Posty: 131
Rejestracja: 4 wrz 2008, o 17:01
Płeć: Mężczyzna
Lokalizacja: Wrocław
Podziękował: 33 razy

[c]nowy wiersz, główna funkcja, linux

Post autor: madaf007 »

aj. Kiedy starałem się dodać marginesy, sądziłem że właśnie przez getline mi nie działa i w main zrobiłem osobną funkcję, która pobierała te krótkie teksty, potem już zapomniałem o niej i korzystając z niej próbowałem uruchomić ten program na tym słowniku, przez co nie działało. Zmieniając z powrotem na funkcje getline działa. A już się przeraziłem;]

Nie wiem czemu robi mi tylko do literki i. Dalej program nie działa. Tak jakby tablica była za mała. Dałem na 1 000 000. Jak daje o jedno zero więcej to już mam naruszenie pamięci:
Oto mój kod:

Kod: Zaznacz cały

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

#define MAX 1000000

void usun(char zdanie[])
{
    int i;
    char znak = '\n';
    int dlugosc = strlen(zdanie);

    for(i=0;i<dlugosc-1;++i)
         if(zdanie[i]==znak)
         {
               zdanie[i]=' ';
         }
}

void newline(char zdanie[], int miejsce)
{
   int spacja=-1;
   int i=0;
   int dlugosc=strlen(zdanie);
              int j=0;

          for(i=0; i<dlugosc; ++i,++j)
     {
                   if(zdanie[i]==' ')
                   {
                       spacja=i;
                   }
                   if(j==miejsce)
                   {
                               zdanie[spacja]='\n';
                               j=i-spacja;
                   }
           }
}
void przesun(char zdanie[], int miejsce, char znak){
     int i; 
     int dlugosc = strlen(zdanie); 
     for(miejsce; dlugosc >= miejsce; dlugosc--){
                  i = dlugosc + 1; 
                  zdanie[i] = zdanie[dlugosc];
     }
     zdanie[miejsce] = znak;
}


void getline(char zdanie[], int lim)
{
   int c,i;

   for(i = 0;i<lim-1 && (c=getchar())!=EOF;i++)
      zdanie[i]=c;
      zdanie[i]='\0';
}

int main( int argc, char* argv[] )
{
    int i=0;
    int c;
    char zdanie[MAX];
    int miejsce = atoi(argv[1]);
    getline(zdanie,MAX);
    usun(zdanie);

    newline(zdanie,miejsce);
    printf("%s",zdanie);
    return 0;
}
funkcja przesuń dopiero będzie w użyciu w dodawaniu spacji, jeśli mi się uda coś wymyślić.

debugger coś wykrywa, ale nie umiem jeszcze w pełni z tego korzystać. Czas mnie nagli, w czwartek muszę to oddać, więc tylko siedzę nad tym prostym programem.


Valgrind się nazywa ten debugger, sprawdza wycieki pamięci, ale nic z tego nie rozumiem;]

No nic. Łudzę się, że prowadzący nie będzie sprawdzał całego wyniku, w końcu to 230 tys słów;] Zastanawiam się jak pobierać każdy wers i sprawdzać czy ma odpowiednia długość. Jeśli nie ma odpowiedniej długość to ma dodać spacje.
ODPOWIEDZ