funkcja pobierająca dokładnie n znaków

funkcja pobierająca dokładnie n znaków
CR
  • Rejestracja:prawie 9 lat
  • Ostatnio:około 6 lat
  • Postów:28
0

Witam,
Próbuje zrobić zadanie, w którym mam do napisania funkcję pobierającą z klawiatury najbliższe n znaków, włącznie z odstępami, tabulatorami i znakami nowej linii.
Problem polega na tym, że nie wiem jak zrobić, aby program po wpisaniu maksymalnej ilości znaków zaprzestał ich pobierania bez przechodzenia do nowej linii (jeśli wklepana została maksymalna ilość znaków).

Czy powinienem użyć w takim wypadku gets() / fgets() operując na łańcuchach?

Poniżej moja funkcja.

Kopiuj
#include <stdio.h>
#include <ctype.h>
#define MAX 10
int main()
{
	char ch;
	int n;
	
	while (n != MAX + 1){
		if (ch = getchar() || isspace(ch))
			n++;
	}
	return 0;

} 
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:3 dni
  • Lokalizacja:Szczecin
2

Skąd to isspace? Nie ma nic o tym w warunkach zadania.

Po prostu n razy wykonaj getchar


CR
  • Rejestracja:prawie 9 lat
  • Ostatnio:około 6 lat
  • Postów:28
0

Chyba nie bardzo rozumiem jak powtórzyć getchar n razy.
Czy mam użyć np. pętli for, czy do while? Niezależnie czego używałem, zawsze musiałem zaakceptować wprowadzony wiersz enterem, przy czym mogło to być 10 znaków ale również 20.

Nie chcę, aby funkcja pozwalała na wklepywanie znaków po załóżmy dziesiątej spacji/literze/enterze itp. (dlatego też dodałem isspace(ch), bo chodzi również o znaki niedrukowane)

0
crystalsky napisał(a):

Chyba nie bardzo rozumiem jak powtórzyć getchar n razy.
Czy mam użyć np. pętli for, czy do while? Niezależnie czego używałem, zawsze musiałem zaakceptować wprowadzony wiersz enterem, przy czym mogło to być 10 znaków ale również 20.

Nie chcę, aby funkcja pozwalała na wklepywanie znaków po załóżmy dziesiątej spacji/literze/enterze itp. (dlatego też dodałem isspace(ch), bo chodzi również o znaki niedrukowane)

To chyba będzie ci potrzebna biblioteka ncurses.h jak chcesz się bawić w zaawansowane sterowanie terminalem

mlyszczek
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad 8 lat
  • Lokalizacja:Wrocław
  • Postów:167
1

if (ch = getchar() || isspace(ch)) ten warunek nie ma zbyt wiele sensu. getchar odczytuje ze standardowego wejścia jeden znak (również białe znak) i zwraca go w postaci unsigned char. (ch = getchar()) zwróci kod ascii, więc będzie prawdą ZAWSZE, bo nie da się (w normalny sposób bez kombinowania z remapem) z klawiatury wprowadzić '\0' aby warunek też zwrócił 0. Teraz isspace(ch) zwróci 1 gdy ch == 0x20, a nie ma takiej potrzeby bo już getchar zwróci w tym przypadku 1.

Tak naprawdę funkcja isspace zostanie wykonana tylko w przypadku, gdy ch == '\0' (inaczej getchar zwraca prawdę i program od razu skacze do bloku if bez sprawdzania drugiego warunku), a gdy ch == '\0' to nie ma już sensu sprawdzać isspace bo wiemy ze 100% pewnością, że zwróci on 0.

Wniosek, isspace można wypieprzyć bo kompletnie, ale to kompletnie nic sensownego nie robi.

edytowany 2x, ostatnio: mlyszczek
Zobacz pozostały 1 komentarz
mlyszczek
Ale to nie spełni oczekiwań autora, bo autor chce aby można było wpisać 10 znaków, a ten warunek pozwoli na wpisanie 10 wyrazów.
MarekR22
@mwl4 czy ty wiesz, że to co napisałeś, nie zadziała zgodnie z twoim oczekiwaniem, bo przecinek tak nie działa jak ci się wydaje?
kq
A to dlaczego? Ten kod jest analogiczny do if((ch = getchar()), isspace(ch)). Jeśli tam nie ma UB z kolejnością dostępu (sequence points / sequenced after/before) to wydaje się być ok - nawet jeśli zapis nietypowy.
mwl4
No właśnie. Ja doskonale wiem co oznacza przecinek w takim zapisie ;)
kq
Może if(isspace(ch = getchar()) by było czytelniejsze?
MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:2 minuty
2

stawiam na to, że autor chce bezpośredniego dostępu do klawiatury, a tymczasem nie zdaje sobie sprawy, że tak naprawdę korzysta ze standardowego wejścia skojarzonego z plikiem emulowanym przez klawiaturę.
Ergo dopóki user nie naciśnie enter nie będzie miał interakcji z programem, bo po prostu taka jest natura konsoli (pliku klawiatury).

Prawie na pewno musi wykroczyć poza standardowe biblioteki, by osiągnąć zamierzony cel.
Pod Windows może skorzystać z conio.h, albo lepiej z ncurses, które dostępne jest na wszystkie platformy, ale jest z nim nieco więcej rzeczy do zrobienia.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: MarekR22
mlyszczek
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad 8 lat
  • Lokalizacja:Wrocław
  • Postów:167
0

@MarekR22 Problem nie leży tak naprawdę po stronie funkcji getchar a po stronie terminala. getchar bierze jeden znak ze strumienia, a w konsoli strumień jest domyślnie buforowany i flushowany dopiero po znaku nowej linii. Aby mieć natychmiastową reakcję przy getchar, w Linuksie trzeba przestawić terminal aby nie buforował znaków. Można to zrobić za na przykład tak system("/bin/stty raw"); Nie wiem jak to można zrobić na Windowsie.

#errata, trochę się zamotałem, nigdzie nie napisałeś, ze problem jest po stronie getchar, a że taka jest natura termina. Ale to wciąż można zmienić prosto bez ncurses.

edytowany 3x, ostatnio: mlyszczek
CR
  • Rejestracja:prawie 9 lat
  • Ostatnio:około 6 lat
  • Postów:28
0

Dziękuję wszystkim za odpowiedzi.
Może po prostu ja źle rozumiem zadanie, bo wątpię, aby ta funkcja miała być aż tak skomplikowana, bo mimo wszystko są to wciąż początki.
W drugim wariancie tego zadania funkcja ma kończyć działanie właśnie po wprowadzeniu n znaków, spacji, tabulatora lub znaku nowej linii, ale wciąż jestem zależny od przesłania wprowadzonego wiersza enterem, więc i tak automatycznie funkcja by kończyła swoją pracę, ponieważ enter został użyty (a co ze spacją i tabulatorem?).

Kopiuj
#include <stdio.h>
#define MAX 10
int main()

{
	char ch;
	int n;
	
	for (n = 0; n < MAX + 1; n++){
		ch = getchar();
		if (ch == '\t' || ch == ' ' || ch == '\0')
			break;
	}
	return 0;
		
} 
edytowany 1x, ostatnio: crystalsky
Zobacz pozostałe 9 komentarzy
KA
@mlyszczek: Jak odbierasz znaczki z klawiatury to masz gwarancje. Ale jeśli masz otwarty deskryptor dajmy na to modemu, to możesz mieć i kodowanie 9-cio bitowe i dodatkowe kody sterujące, a wtedy zrzutowanie na char-a grozi śmiercią :)
mlyszczek
A jak chcesz do getc, które przyjmuje FILE * (otrzymywane przez fopen) przekazać deskryptor do urządzenia szeregowego, które przyjmuje int otrzymywane z open;)
KA
A to urządzenia nie da się otworzyć za pomocą fopen() :)? A potem użyć getw, żeby mieć pewność, że wczytujesz wsio ;)? Oczywiści wspomnianego int-a to ja mogę dostać także z otwartego obiektu typu FILE. Chociażby przez fileno(3).
mlyszczek
Właśnie sprawdziłem u siebie i faktycznie za pomocą fopen otworzyłem uarta! Nigdy by mi to przez myśl nie przyszło, że tak można. Zwracam honor w takim razie i kajam się nisko. I dzięki za ciekawostkę:)
KA
De facto fopen(3) i open(2) różnią się przede wszystkim tym, że fopen(3) zgodnie z tym, co wskazuje numerek 3 jest częścią standardu C, a open(2) - jest biblioteką systemową i definiuje to POSIX / SUS / cokolwiek o co się teraz ludzie ciągną po sądach. Ale jedno i drugie otwiera pliki, więc jak masz tylko uarta wystawionego jako plik to jednym i drugim raczej go otworzysz ;)
datdata
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 7 lat
  • Postów:957
1

Upewnij się czy na pewno musisz robić to, o czym piszesz. Jeśli to zadanie podczas początkowej nauki podstaw, zapewne rozwiązanie, które "wczyta" dowolną ilość znaków, a zapisze tylko n może być wystarczające, a Ty za bardzo kombinujesz :)


"A human being should be able to change a diaper, plan an invasion, butcher a hog, conn a ship, design a building, write a sonnet, balance accounts, build a wall, set a bone, comfort the dying, take orders, give orders, cooperate, act alone, solve equations, analyze a new problem, pitch manure, program a computer, cook a tasty meal, fight efficiently, die gallantly. Specialization is for insects." Robert Heinlein.

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.