Zaloguj się, aby obserwować  
Bartuc

Język C / C++ / C# / Java - pytania, problemy...

1979 postów w tym temacie

Dnia 04.01.2013 o 17:30, Dregorio napisał:

Mam zrobić coś takiego: Napisz program który liczbę z zakresu 1 .. 7000 wprowadzoną z
klawiatury wyświetli w postaci słownej.
Czyli trzeba zdefiniować nazwy od 0..9,10..19,20,30,40,50,60 itd? A potem by program
je łączył, np. widząc ''21'', pobiera ''dwadzieścia'' i ''jeden''.
Zastanawiam się tylko czy nie ma prostszej metody, bo to trochę pisania jest.


To jest bardzo mało pisania, i to bardzo prostego - zdefiniowanie 4 tablic po 10 elementów to pikuś. Łączenie jest już proste, jedynie trzeba uważać na to aby nie czytał zer. W sumie samo zdefiniowanie słownych wersji liczb zajęłoby ci tyle czasu co napisanie tego posta, więc nie ma co kombinować. :)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach
Dnia 04.01.2013 o 17:37, ziptofaf napisał:

/.../

To można zrobić dość prosto:

1 do 9 robimy ręcznie.
11 do 19 to tak naprawdę 1-9 + naście.
20 = dwa + dzieścia
30 = trzy + dzieścia
33 = trzy + dzieścia + trzy

A 50?
Tak naprawdę dla każdego poziomu mamy co najmniej 3-4 kombinacje przyrostków - kombinowanie w ten sposób będzie skutkowało jakimś programistycznym koszmarkiem...

Udostępnij ten post


Link to postu
Udostępnij na innych stronach
Dnia 04.01.2013 o 17:46, rob006 napisał:

Tak naprawdę dla każdego poziomu mamy co najmniej 3-4 kombinacje przyrostków - kombinowanie
w ten sposób będzie skutkowało jakimś programistycznym koszmarkiem...


A tak, mój błąd. Mózg mi najwyraźniej na moment wysiadł :D

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

/.../
Robię to na case, więc mam napisane:
#include <stdio.h>
int main()
{
int a;
scanf("%d", &a);
switch(a)
{
case 1:
printf("jeden");
break;
case 2:
printf("dwa");
break;
case 3:
printf("trzy");
break;
case 4:
printf("cztery");
break;
case 5:
printf("piec");
break;
case 6:
printf("szesc");
break;
case 7:
printf("siedem");
break;
case 8:
printf("osiem");
break;
case 9:
printf("dziewiec");
break;
case 10:
printf("dziesiec");
break;
case 11:
printf("jedynascie");
break;
case 12:
printf("dwanascie");
break;
case 13:
printf("trzynascie");
break;
case 14:
printf("czternascie");
break;
case 15:
printf("pietnascie");
break;
case 16:
printf("szesnacie");
break;
case 17:
printf("siedemnascie");
break;
case 18:
printf("osiemnascie");
break;
case 19:
printf("dziewietnascie");
break;
case 20:
printf("dwadziescia");
break;
case 30:
printf("trzydziesci");
break;
}
getchar();
getchar();
}
i teraz jak z tego zrobić 21 bez ''definiowania''? Bo się zgubiłem...

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

/.../

Jak widzę takie zapchane mainy to aż mi się nóż w kieszeni otwiera, podziel to sobie na jakieś procedury...

A co do twojego pytania - źle używasz case''a. W taki sposób to będziesz musiał autentycznie wykonać ich 7000... Spójrz na to w jaki sposób ja się za to zabrałem (kod masz post wyżej, w C++ niby ale podejrzewam że da się go łatwo zrozumieć):

if (liczba<=10){cout << jednosci(liczba) << endl;}
if (liczba>=11 && liczba <20){cout << nasci(liczba-10) << endl;}
if (liczba<100 && liczba>=20){cout << pokaz_dziesiatki(liczba) << endl;}
if (liczba<1000 && liczba>=100){cout << pokaz_setki(liczba) << endl;}
if (liczba<10000 && liczba>=1000){cout << pokaz_tysiace(liczba) << endl;}

I te ify można ewentualnie sobie pozamieniać na case''y:
case 1 = ponizej 10
case 2 = od 11 do 19
case 3 = od 20 do 99
i tak dalej. A wewnątrz case''a tylko wywoływać odpowiednie wyświetlanie sekwencji znaków. A nie robić case pod KAŻDĄ liczbę z osobna.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach
Dnia 04.01.2013 o 19:40, Dregorio napisał:

/.../
Nie mogę tego programu zrobić na tablicach, więc nie wiem jak mam się zabrać. najłatwiej
było dla mnie wypisywać wszystko.


Co masz na myśli przez "nie mogę"? Podaj więc pełne polecenie jakie dał ci wykładowca to można będzie zasugerować coś lepszego...

Bo na upartego to możesz to nawet na pętli rekurencyjnej robić która by za każdym razem wywoływała się z mniejszą wartością (czyli np. 1232 najpierw jako 1232, potem 232, potem 32, potem 2 i tak aż do czasu gdy nie dojdzie do 0), w trakcie tylko sprawdzać długość tej liczby i zależnie od tego dopisywać do standardowego wyjścia kolejne człony... I wtedy rzeczywiście da się jakoś upychać case''y. Dla przykładu case dla tysięcy - od 1 do 7. Potem case''y dla setek, dziesiątek i wreszcie jedności. Wykonalne? I owszem. Proste? Też... ale głupie, toż to celowe przedłużanie kodu xD

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

/.../
Mam zrobić to w C z wykorzystaniem switch. Napisz program który liczbę z zakresu 1 .. 7000 wprowadzoną z klawiatury wyświetli w postaci słownej.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach
Dnia 04.01.2013 o 20:42, Dregorio napisał:

/.../
Mam zrobić to w C z wykorzystaniem switch. Napisz program który liczbę z zakresu 1 ..
7000 wprowadzoną z klawiatury wyświetli w postaci słownej.


To zrób to na switchach, ale za pomocą metod, tak jak w przykładzie ziptofafa.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Z nieznanych mi powodów pisanie programów operujących na tekście to zawsze dla mnie prioblem :/
W każdym razie chciałbym napisać program w C, który wczytuje od użytkownika/dowolnego źródła zdanie (string) składające się z 3 słów oddzielonych spacją, i każde zapisuje w innej zmiennej. Wydaje mi się, że będzie to w postaci

//wczytuj scanfem
//if spacja...

no własnie, co przechowywało by ostatni znak jeśli wczutuje string, jak sprawdzić aktualnie wczytywany char i jednoczesnie jeśli to nie spacja wczytywać dalej... jak zapisać to bez tych spacji (jeśli spacja to od następnego znaku do następnej zmiennej...)

to w zasadzie 3 linijki kodu (tak myślę), tylko jakie?

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

/.../
Aż 3 linijki kodu? o_O Co ty tak długiego chcesz tworzyć?

char s1[15];
char s2[15];
char s3[15];
scanf ("%s %s %s", s1, s2, s3);
printf("%s", s3);

Proszę. Wpisz 3 słowa, oddziel je spacjami. I działa. Na co komu 3 linijki, tylko scanfa dobrze użyć XD

Udostępnij ten post


Link to postu
Udostępnij na innych stronach
Dnia 16.01.2013 o 12:38, ziptofaf napisał:

Proszę. Wpisz 3 słowa, oddziel je spacjami. I działa. Na co komu 3 linijki,
tylko scanfa dobrze użyć XD


Dzięki za pomoc. Faktycznie dużo prościej i czytelniej.
Czy gdyby oddzielającym symbolem była np. litera C byłoby to tak samo proste? Choć to już poza tematem :P

Udostępnij ten post


Link to postu
Udostępnij na innych stronach
Dnia 16.01.2013 o 12:53, Boguslav4 napisał:

Dzięki za pomoc. Faktycznie dużo prościej i czytelniej.
Czy gdyby oddzielającym symbolem była np. litera C byłoby to tak samo proste? Choć to
już poza tematem :P


Z pomocą scanf? Niekoniecznie.
http://www.cplusplus.com/reference/cstdio/scanf/
"Whitespace character: the function will read and ignore any whitespace characters encountered before the next non-whitespace character (whitespace characters include spaces, newline and tab characters -- see isspace)." I tylko te 3 znaki będą tak traktowane. Jakbyś chciał literkę C i wykorzystać scanf tak żeby to działało to tak czy siak musiałbyś w jakiś sposób to C zamienić na znak spacji. Scanf niestety nie za bardzo powala swoją dokumentacją więc nawet nie wiem czy da się na nim wymusić traktowanie czegoś jako znak przerwy poza tym co on tam ma domyślnie. Na upartego to pewnie tak, przestawić tryb konsoli na jakiś dziwaczny żeby ci traktował konkretną kombinację znaków jako whitespace ale wydaje mi się to nieprawdopodobną bzdurą. Zresztą sam nie jestem pewny jak to zrobić, trzeba by jakoś locale pozmieniać na taki własnoręcznie utworzony... pewnie najszybciej jakąś wstawką assemblerową i się dobrać do adresów klawiszy czy nawet sterowników klawiatury... ale już bez jaj, my tu mamy zrobić prosty program a nie modyfikować to jak system operacyjny traktuje nam wciskane klawisze xD

Więc prościej (choć wymaga to ździebko dłuższego maina) to możesz napisać sobie funkcję dziel która będzie jako jeden z argumentów przyjmowała dany znak, jako drugi adres twojego stringa a jako trzeci jego długość a potem sprawdzała czy należy go sobie zamienić znak po znaku (a jeśli tak to modyfikować oryginał, dlatego potrzebny nam wskaźnik a nie po prostu kopia). Do napisania w jakieś 3 minuty. Np. w ten sposób:

void dziel(char whitespace, char *zdanko, int length)
{
int a=0;
for (;a<=length; a++)
{
if (zdanko[a]==whitespace){zdanko[a]='' '';}
}
}

To już mamy naszą funkcję.
Teraz main:

int main()
{
char zdanie[20];
scanf("%s", zdanie);
char white=''C''; // czy jakikolwiek inny. Możesz go nawet z klawiatury czytać.
dziel(white, zdanie, 20);

char s1[15];
char s2[15];
char s3[15];
sscanf (zdanie, "%s%s%s", s1, s2, s3);

printf("%s", s3);

printf("Press enter to continue ...");
getchar();
Sleep(1000);
return 0;

}

Musiałem za drugim razem zastosować sscanf zamiast scanf bo danych tym razem nie bierzemy prosto z klawiatury a z już istniejącego stringa który został wczytany wcześniej.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Dnia 16.01.2013 o 12:38, ziptofaf napisał:

Proszę. Wpisz 3 słowa, oddziel je spacjami. I działa. Na co komu 3 linijki,
tylko scanfa dobrze użyć XD


Hm... A gdybym próbował wczytywać to linia po lini z pliku?
Powiedźmy n linijkowego po 3 słowa. W danym momencie wypróbowuje różne kombinacje warunków.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach
Dnia 16.01.2013 o 18:12, Boguslav4 napisał:

Hm... A gdybym próbował wczytywać to linia po lini z pliku?
Powiedźmy n linijkowego po 3 słowa. W danym momencie wypróbowuje różne kombinacje warunków.


Nie pamiętam za bardzo jak to działało w C ale w C++ to byłoby tak:

#include <fstream>
#include <vector>
using namespace std;
int main(){
fstream F("nazwapliku");
vector<string> tablica_zdan(1);
int a=0;
while (F)
{
tablica_zdan.push_back("");
getline(F, tablica_zdan[a]);
a++;
}
I tym sposobem powinno nam wczytać wszystkie linie w danym pliku, każda linia będzie w osobnym elemencie wektora (taka ulepszona tablica). Teraz tylko każdą potraktować naszą poprzednio napisaną funkcją "dziel" i ewentualnie podzielić to sobie na jeszcze więcej tablic mających tylko 1 słowo każde. I voilla, zadanie zakończone.

W C z kolei będzie trudniej. Sporo zależy od tego czy chcesz przechowywać wszystkie słowa czy też ma to być robione na bieżąco - 3 słowa, wyrzucić je na standardowe wyjście czy coś innego z nimi zrobić i potem idziemy do kolejnej linijki i proces resetuje się od nowa. Wtedy kod który zaproponowałem post wcześniej działa jak trzeba, tylko wrzucić to wszystko w jeszcze dużą pętle while która by sprawdzała czy w linijce są normalne słowa czy EOF. W tym drugim przypadku robić break.

Jednak jeśli chcemy te dane przechowywać to będzie nieco trudniej bo C nie ma za bardzo tablic które mogą dowolnie zwiększać swoje rozmiary. I co prawda da się je sobie napisać (albo przynajmniej coś co spełni ich rolę) ale trzeba się bawić ze wskaźnikami czego ja bardzo nie lubię osobiście, wręcz nie znoszę. Do tego mi się kod z C miesza z C++ a akurat w tym aspekcie te języki są diametralnie różne.

Ale spróbujemy. Po pierwsze, napiszemy sobie jakąś ładną strukturkę która będzie przechowywać nam zdania (próbuję uprościć kod w ten sposób bo mi zaczną wychodzić dwu czy trójwymiarowe tablice a to jest co najmniej nieczytelne). Na przykład taka:

typedef struct
{
char linia[30];
}linia;
Wstawiamy to sobie nad mainem.

Z kolei w mainie dodamy takie coś:
linia *tablica_linii;
tablica_linii = (linia*)malloc(rozmiar * sizeof(linia));
Gdzie rozmiarem jest oczywiście zmienna oznaczająca ilość linii.
Poniżej tego robimy coś w rodzaju:
for (j=0; j<rozmiar; j++)
{
scanf("%s", &tablica_linii[j].linia_tekstu);
dziel(white, tablica_linii[j].linia_tekstu, 20);
}

Ewentualnie używamy fscanf ale zakładam że po prostu przekierowałeś standardowe wejście na plik zamiast klawiatury a nie tworzyłeś cały interfejs obsługi pliku (co niby nie zajmuje dużo linijek ale można robić tak a można też przez przekierowanie, kwestia gustu).
I tym oto sposobem mamy wszystkie linijki już podzielone. Teraz tylko zrobić kolejną strukturę, znowu powyżej maina.

typedef struct
{
char slowo1[12];
char slowo2[12];
char slowo3[12];
}slowa;

Następnie znowu powtórzyć zabawę z mallociem ale tym razem dla tablicy o typie slowa a nie linia. Odpowiednio użyć sscanf tak żeby korzystało z &tablica_linii[j].linia_tekstu jako wejscia i &tu_wstaw_nazwe_tablicy_slow[j].slowo1, &tu_wstaw_nazwe_tablicy_slow[j].slowo2, &tu_wstaw_nazwe_tablicy_slow[j].slowo3 jako wyjścia (nie różni się to od tego co pokazywałem w poprzednich postach). I voilla.

Tak z 50-60 linii kodu będzie łącznie :D W sumie da się to zrobić w znacznie mniejszej ich ilości ale jak już pisałem - ja nie lubię wskaźników. Jasne że mógłbym wszystko zrobić na jednej dwuwymiarowej tablicy char, i to potem sobie poprzenosić do takiej osobnej ze słowami ale może i byłoby to szybsze ale niekoniecznie dla mnie prostsze do odczytania.

A tak, i na koniec jeszcze wypadałoby zwolnić pamięć którą zarezerwowaliśmy mallociem komendą free.
Czyli np. free(linia);

Udostępnij ten post


Link to postu
Udostępnij na innych stronach
Dnia 16.01.2013 o 20:28, ziptofaf napisał:

> Hm... A gdybym próbował wczytywać to linia po lini z pliku?
> Powiedźmy n linijkowego po 3 słowa. W danym momencie wypróbowuje różne kombinacje
warunków.

Dnia 16.01.2013 o 20:28, ziptofaf napisał:

A tak, i na koniec jeszcze wypadałoby zwolnić pamięć którą zarezerwowaliśmy mallociem
komendą free.
Czyli np. free(linia);


/.../
W swoim naiwnym mysleniu próbowałem utworzyć tablicę[j][k], gdzie i to kolejny wiersz, j to kolejne słowo, a k to liczba znaków nań przeznaczona... Choć oczywiście taka konstrukcja nie działała.

A gdyby to uprościć? Pobierać z pliku tekst i jeśli spełnia założenie użytkownika (np. linia 100) to ją wypisać.
Zadziwia mnie ogrom pracy, jaki zostął tutaj wykonany dla zadania- które miało być łatwe, a urosło trochę ponad miarę :P

Udostępnij ten post


Link to postu
Udostępnij na innych stronach
Dnia 16.01.2013 o 20:37, Boguslav4 napisał:

W swoim naiwnym mysleniu próbowałem utworzyć tablicę[z][j][k], gdzie z to kolejny wiersz,
j to kolejne słowo, a k to liczba znaków nań przeznaczona... Choć oczywiście taka konstrukcja
nie działała.


Ależ to by mogło zadziałać z tym że wątpię żebyś w ogóle wiedział co właśnie utworzyłeś i jakie są ograniczenia.
Weźmy takie coś:
int szescian[3][3][4];

To jest trójwymiarowa tablica.
Jednowymiarowa wygląda tak:
int a[3];
1 2 3
Proste.
Dwuwymiarowa:
int a[3][3];
1 2 3
1 2 3
1 2 3

3 kolumny po 3 miejsca każdy.

Teraz trójwymiarowa:
int a[3][3][3]
http://www.mielk.pl/pl/pics/13_01_tablice.jpg
Wygląda to mniej więcej tak.
3 na wysokość, 3 na szerokość, 3 na głębokość. Już się robi ciężko z ogarnięciem ile to w ogóle ma elementów, prawda? W tym przypadku 3x3x3 ma ich oczywiście 27.
Czasem choć BARDZO rzadko widuje się też więcej niż 3 wymiary. 4 wymiarowa tablica to już jednak hipersześcian i człowiekowi bardzo ciężko zrozumieć indeksowanie tego. Już 3 są problematyczne.
To w gruncie rzeczy byłoby aż NADTO miejsca żeby zmieścić te linijki i wszystko inne co chcesz ale jednocześnie jest powodem dla którego nawet o tym nie pomyślałem. Kod robi się po prostu nieludzko nieczytelny. Zwłaszcza że pewnie jeszcze byś chciał żeby ta tablica miała różny rozmiar zależnie od ilości linijek w pliku i trzeba by to i tak robić dynamicznie. Powodzenia przy niemyleniu się.
Dlatego samemu postawiłem na struktury. Łatwiej mi zrozumieć coś co się nazywa struktura1 i ma trzy elementy:
słowo1
słowo2
słowo3
Z których każdy jest tablicą char o rozmiarze np. 15. I tylko musiałem dla nich utworzyć dynamiczny indeks. Ale jest to mimo wszystko wtedy tylko 1 wymiarowa tablica a nie jakieś programistyczne potwory.

Dnia 16.01.2013 o 20:37, Boguslav4 napisał:

A gdyby to uprościć? Pobierać z pliku tekst i jeśli spełnia założenie użytkownika (np.
linia 100) to ją wypisać.

Wczytujesz linijka po linijce i po prostu szukasz w każdej z nich określonego ciągu znaków nie zapisując tych danych w pamięci do późniejszego użytku? To wtedy to łatwe.
W C++ masz do tego string.find(""), w C mamy http://www.cplusplus.com/reference/cstring/strstr/

Dnia 16.01.2013 o 20:37, Boguslav4 napisał:

Zadziwia mnie ogrom pracy, jaki został tutaj wykonany dla zadania- które miało być łatwe,
a urosło trochę ponad miarę :P

Czy ja wiem czy ogrom...? Zależy od twojej wiedzy w temacie. Mi napisanie tej wersji z wczytywaniem linijek, dynamicznymi rozmiarami i strukturami zajęło z 20 minut a musiałem sobie przypomnieć jak działał malloc i jak wyglądały struktury w C. Gdybym robił to w C++ którego znam lepiej to pewnie byłoby z 5 i mógłbym skrócić kod o 2/3 ^_^

Udostępnij ten post


Link to postu
Udostępnij na innych stronach
Dnia 16.01.2013 o 21:02, ziptofaf napisał:

> W swoim naiwnym mysleniu próbowałem utworzyć tablicę[z][j][k], gdzie z to kolejny
wiersz,


Wiem, jak bardzo wielka to tablica, lecz na obecnym poziomie nie znam innego sposobu przedstawienia danych.

Jeśli chodzi o ogrom- nie tylko wiedzy, ale i tekstu i kodu :)
(gdy przeciętnie odpowiedzi na forum to jednolinijkowce, szkoda że nie haiku :P)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Utwórz konto lub zaloguj się, aby skomentować

Musisz być użytkownikiem, aby dodać komentarz

Utwórz konto

Zarejestruj nowe konto na forum. To jest łatwe!


Zarejestruj nowe konto

Zaloguj się

Masz już konto? Zaloguj się.


Zaloguj się
Zaloguj się, aby obserwować