Forum: PC-Programmierung C-Wörter zählen


von Muco (Gast)


Lesenswert?

Hey,
ich hätte kurz eine Frage:

Das Programm soll die anzahl der Wörter zählen, was es auch tut, jedoch 
wenn das erste Zeichen schon ein Enter ist wird in dem Fall auch das 
Enter bei fgets als ein Wort gezählt:
1
# include <conio.h>
2
# include <stdio.h>
3
4
int wordcount(char s[]);
5
6
int main()
7
{
8
  char satz[99], anzahl=0;
9
10
  fgets(satz, 99, stdin);
11
12
  anzahl=wordcount(satz);
13
14
  printf("Wortanzahl: %d", anzahl);
15
16
  getch();
17
  return 0;
18
}
19
20
int wordcount(char s[]) 
21
{
22
  int i, count=0;
23
24
  for(i=0; s[i]!=0; i++)
25
  {
26
    
27
    if(s[i]==' ')
28
    {
29
      
30
      count++;
31
      
32
    }
33
  }
34
  
35
  return count+1;
36
}
Wenn ich nicht count+1 zurückgebe wird halt ein Wort weniger ausgegeben, 
da das Enter nicht als Wort gezählt wird.

Könnte mir jemand helfen? Danke :)

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Muco schrieb:
> Könnte mir jemand helfen? Danke :)

dein Programm zählt keine Wörter sondern Leerzeichen.

Was ist wenn 2 Leerzeichen hintereinander kommen?

Da wirst du wohl etwas mehr code schreiben müssen.

von Muco (Gast)


Lesenswert?

Ich weiß, dass mein Programm Leerzeile zählt, aber trotzdem werden 
dadurch gleichzeitig auch Wörter gezählt deswegen habe ich halt "Wörter 
gezählt" gesagt. Aber sorry falls dich das gestört hat.
Kannst du mir auch meine Frage beantworten? Wäre sehr nett.. Danke

von Muco (Gast)


Lesenswert?

*Leerzeichen

von Muco (Gast)


Lesenswert?

Aber ich hab schon verstanden was du meinst mit zwei Leerzeichen.. Aber 
das kommt dann vielleicht als nächster Schritt :)

von Peter II (Gast)


Lesenswert?

Muco schrieb:
> Ich weiß, dass mein Programm Leerzeile zählt, aber trotzdem werden
> dadurch gleichzeitig auch Wörter gezählt deswegen habe ich halt "Wörter
> gezählt" gesagt.

nein ebend nicht, wie du selber siehst.


Bei dir wird jede Leerzeile und jedes zusätzliche Leerzeichen als Wort 
gezählt und das ist falsch.

von Muco (Gast)


Lesenswert?

Ja du hast schon recht aber zuerst wollte ich mal verstehen wie ich das 
mit dem Zählen von Leerzeichen hin bekomme.

Wenn ich nicht count+1 zurückgebe wird halt ein Zeichen weniger 
ausgegeben.
Wie könnte ich das lösen?

von Rene H. (Gast)


Lesenswert?

Muco schrieb:
> Ja du hast schon recht aber zuerst wollte ich mal verstehen wie
> ich das
> mit dem Zählen von Leerzeichen hin bekomme.
>
> Wenn ich nicht count+1 zurückgebe wird halt ein Zeichen weniger
> ausgegeben.
> Wie könnte ich das lösen?

Schau Dir mal strtok() an.

Grüsse,
R.

von Peter II (Gast)


Lesenswert?

Muco schrieb:
> Wie könnte ich das lösen?

versuche es mal mit
1
int wordcount(char s[])
2
{
3
  int i, count=0;
4
5
  for(i=0; s[i]!=0; i++)
6
  {
7
    if(s[i]==' ')
8
    {
9
      count++;
10
    }
11
  }
12
13
  if ( i > 0 ) {
14
     count++;
15
  }
16
17
  return;
18
}

aber richtig wird es damit noch lange nicht.

von HertzFrequenz (Gast)


Lesenswert?

@ Muco

Das mit den Leerzeichen ist irgendwie ja eine nette Idee. Hat nur ein 
paar Nachteile, sprich: es funktionert nicht. Was z.B. wenn nicht ein 
Leerzeichen, Worte trennt, sondern ein Tabulator? Etcpp.

Hab Nachsicht mit uns, die wir hier teilweise erst seit 30 Jahren im 
Fach sind. Wir neigen zu inakzeptabler Genauigkeit. :-)

Aber zu Übungszwecken wäre es doch ganz nett wenn Du mal eine positive 
Definition von Wörtern erstellst und das Programm dazu. Das freut auch 
Deinen Lehrer. Bestimmt!

von PittyJ (Gast)


Lesenswert?

Gibt es doch alles schon.
Unter Unix ist standardmäßig ein Utility mit dem Namen wc für WordCount 
dabei. Einfach mit wc dateiname aufrufen.
Und die Sourcen gibt es z.B. unter
http://www.gnu.org/software/cflow/manual/html_node/Source-of-wc-command.html

von NurEinGast (Gast)


Lesenswert?

Wie gesagt - Du zählst keine Worte. Aber das weißt Du ja selbst.

> Wenn ich nicht count+1 zurückgebe wird halt ein Wort weniger ausgegeben,
> da das Enter nicht als Wort gezählt wird.

Wenn Du "ENTER" mitzählen willst,

   if( (s[i]==' ') || (s[i]=='\r') || (s[i]=='\n') )

Hier würde aber bei einem Windows System CR und LF getrennt gezählt, Du 
bekommst nun ein "count" zu viel.

   if( (s[i]==' ') || (s[i]=='\n'))

Hier würde "nur" NewLine erkannt. Wenn Deine Eingabe nur mit 
Carriage-Return endet, dann würdest Du das nicht nichtig zaehlen.

Tabs und andere Sonderzeichen würdest Du immer noch nicht erkennen.


   if (!isprint(s[i]))  könnte man auch mal anschauen.

All das zählt aber - wie Du weißt - nicht die Wörter, sondern die 
Leer/Sonderzeichen.

von Muco (Gast)


Lesenswert?

Danke an alle also das mit : if( (s[i]==' ') || (s[i]=='\n')) hat eh 
geklappt.

Dass da jetzt nicht Wörter sondern Zeichen gezählt werden ist mir auch 
klar aber danke an alle. Mir geht es eigentlich daweil darum , dass ich 
mit Strings besser umgehen kann und versuche eigentlich den Unterschied 
zwischen der Eingabe mit scanf und mit fgets zu verstehen.

Ich hätte evtl. noch eine Frage:

Wenn ich einen String deklariere mit 100 Zeichen: char s[100] dann sind 
ja eigentlich 99 Zeichen für mich zur Eingabe reserviert und das letzte 
Zeichen ist ein '\0' stimmt das?
Was ist aber bei fgets da muss doch auch ein Enter mit reserviert werden 
und ich müsste sozusagen 2 Zeichen mehr reservieren oder?

Danke nochmal

von Kaj (Gast)


Lesenswert?

HertzFrequenz schrieb:
> Hab Nachsicht mit uns, die wir hier teilweise erst seit 30 Jahren im
> Fach sind. Wir neigen zu inakzeptabler Genauigkeit. :-)
Gefaellt mir :D

von Dirk B. (dirkb2)


Lesenswert?

Muco schrieb:
> Was ist aber bei fgets da muss doch auch ein Enter mit reserviert werden
> und ich müsste sozusagen 2 Zeichen mehr reservieren oder?

Ja. Nein. Vielleicht.

fgets weiß, das es die '\0' ablegen muss und berücksichtigt das auch.
Mit dem '\n' von der Entertaste kannst du überprüfen, ob die ganze Zeile 
eingelesen wurde.
Wenn kein '\n' im Array enthalten ist, hat fgets aus Platzmangel das 
einlesen unterbrochen. Es stehen also noch Zeichen von der Zeile im 
Eingabestrom.

Bei scanf gibst du die maximal Anzahl an Zeichen an, die scanf einlesen 
darf.
Zudem läßt scanf Zeichen, die nicht zum Formatspecifier passen, im 
Eingabestrom stehen.

von Dirk B. (dirkb2)


Lesenswert?

HertzFrequenz schrieb:
> Hab Nachsicht mit uns, die wir hier teilweise erst seit 30 Jahren im
> Fach sind. Wir neigen zu inakzeptabler Genauigkeit. :-)

Das mag daran liegen, dass der Computer nicht das macht was man will, 
sondern das, was man ihm sagt.

von chris (Gast)


Lesenswert?

eigentlich sollte es so sein:
1
int wordcount(char *s)
2
{
3
  int i, count=0;
4
  if(s)
5
  while(*s) {
6
  while(*s&&!isalpha(*s)) s++; // ueberspringe alles was kein Wort ist 
7
  if(isalnum(*s)) count++;     // zähle 
8
  while(*s&&isalnum(*s)) s++;  // ueberspringe wörter
9
  }
10
  return count;
11
}

: Bearbeitet durch User
von Kaj (Gast)


Lesenswert?

Dirk B. schrieb:
> Bei scanf gibst du die maximal Anzahl an Zeichen an, die scanf einlesen
> darf.

Also nach meinen Wissensstand gibt man da nichts an, von wegen wie viele 
Zeichen. So weit ich weiss, liest scanf bis zum ersten White-Space. 
Korrigiert mich, falls ich irre.

Gruesse

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Kaj schrieb:
> So weit ich weiss, liest scanf bis zum ersten White-Space.

Das tut es, und deswegen gehört scanf auch auf die schwarze Liste 
der unbedingt verbotenen Funktionen.

fscanf ist hier eindeutig zu bevorzugen. Als Dateihandle ist stdin 
zu verwenden, und der Drops ist gelutscht.

-- Nachträgliche Anmerkung:

Hier habe ich Unfug geschrieben. Leider ist das nicht so, die 
Weihnachtsfeiertage haben mich irgendwie benebelt.

: Bearbeitet durch User
von Dirk B. (dirkb2)


Lesenswert?

Kaj schrieb:
> Also nach meinen Wissensstand gibt man da nichts an, von wegen wie viele
> Zeichen. So weit ich weiss, liest scanf bis zum ersten White-Space.
> Korrigiert mich, falls ich irre.

Du beziehst dich auf %s.
Was ist mit %9s ?

Maximal 9 Zeichen oder bis zum Whitespace. Je nachdem was früher 
eintritt.

Rufus Τ. Firefly schrieb:
> fscanf ist hier eindeutig zu bevorzugen. Als Dateihandle ist stdin
> zu verwenden, und der Drops ist gelutscht.

Wo hat fscanf andere Formatspecifiere?
Bzw. wie verhält sich das anders als scanf?

von Rolf Magnus (Gast)


Lesenswert?

Dirk B. schrieb:
> Rufus Τ. Firefly schrieb:
>> fscanf ist hier eindeutig zu bevorzugen. Als Dateihandle ist stdin
>> zu verwenden, und der Drops ist gelutscht.
>
> Wo hat fscanf andere Formatspecifiere?
> Bzw. wie verhält sich das anders als scanf?

Das würde mich auch interessieren. Evtl. verwechselt mit gets()/fgets()?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Rolf Magnus schrieb:
> Das würde mich auch interessieren. Evtl. verwechselt mit gets()/fgets()?

Mist.

Ja, Asche auf mein Haupt, die Weihnachtstage und der ganze Brimborium 
sind eindeutig nicht gut überstanden.


-------------


Um dem ganzen einen Sinn zu geben:

Eine halbwegs sichere Kombination gibt es nur, wenn die eigentliche 
Einleseoperation und das Parsen des eingelesenen Strings getrennt 
gehandhabt wird.

Um sicherzustellen, daß nicht zu viel eingegeben wird, ist in einen 
ausreichend dimensionierten Zeichenpuffer einzulesen (Danke für den von 
Rolf Magnus völlig zurecht angebrachten Hinweis auf gets/fgets) - und 
zwar mit fgets, weil da eine Puffergröße angegeben werden kann.

Der so einlesene String kann nun mit sscanf weiter zerlegt werden 
(wenn man nicht strok benutzen möchte), und wie von Dirk angemerkt, 
sollte hier statt %s der Formatspezifizierer mit Längenangabe verwendet 
werden, also z.B. %9s.

Ärgerlicherweise verhält sich %*s bei scanf & Co. anders als bei 
printf & Co., so daß die maximale Stringlänge als numerische Konstante 
im Formatstring anzugeben ist, und nicht als Argument übergeben werden 
kann.


So, ich hoffe, die durch die Weihnachtsdröhnung verursachten 
Verwirrungen meinerseits jetzt ein bisschen kompensiert zu haben.

: Bearbeitet durch User
von Dirk B. (dirkb2)


Lesenswert?

Wenn man schon fgets benutzt, dann weiß man auch, wie groß der Text für 
%s bei sscanf maximal sein kann. Dann kann man den Puffer auch groß 
genug anlegen.

scanf bzw fscanf hat den Charme, dass man keinen Puffer braucht sondern 
die Daten (Zahlen) direkt einlesen kann. Auch der *-Modifiere ist dabei 
hilfreich.

Es kommt dabei auch darauf an, was man einlesen möchte.

Und  wer überprüft bei fgets schon, ob er die komplette Ziele gelesen 
hat.

von Karl H. (kbuchegg)


Lesenswert?

Dirk B. schrieb:
> Wenn man schon fgets benutzt, dann weiß man auch, wie groß der Text für
> %s bei sscanf maximal sein kann. Dann kann man den Puffer auch groß
> genug anlegen.
>
> scanf bzw fscanf hat den Charme

scanf bzw. fscanf haben den 'Charme', dass sich damit eine unter allen 
Umständen fehlerfreie Einleseprocedure als recht schwierig herausstellt. 
Mit den Erweiterungen im Formatstring hat sich zwar einiges gebessert, 
nichts desto trotz ist wohl die Kombination aus fgets + sscanf, bzw. 
eigene Parse-Funktionen anstatt sscanf, die vernünftigste Lösung.

von TomA. (Gast)


Lesenswert?

Hallo Leute,

vor vielen Jahren gab es schon Tools die kostenlos zu haben waren und 
vermutlich noch sind (falls es sie überhaupt noch gibt).
Da gab es "YACC", welches dabei half eigene Compiler zu bauen. YACC 
hatte einen Scanner und Parser um die Schlüsselworte im Quelltext zu 
finden, dazu musste er den Text Wortweise abklappern. Soweit ich mich 
erinnere konnte man ihn über eine Tabelle die Zeichen geben, welche ein 
Wort begrenzen.

Das Gute daran, YACC lag im Quelltext vor - so kann man nachschauen wie 
die das mit der Worterkennung gemacht haben, oder den entsprechenden 
Code selbst verwenden. Und es war einfacher C-Code :-)

Ich hoffe es hilft ein wenig.

von Karl H. (kbuchegg)


Lesenswert?

TomA. schrieb:
> Hallo Leute,
>
> vor vielen Jahren gab es schon Tools die kostenlos zu haben waren


Ich bin mir recht sicher, dass es sich hier einfach nur um ein 
Übungsbeispiel handelt und nicht um einen realen Einsatz.

von Dirk B. (dirkb2)


Lesenswert?

PittyJ schrieb:
> Gibt es doch alles schon.
> Unter Unix ist standardmäßig ein Utility mit dem Namen wc für WordCount
> dabei. Einfach mit wc  dateiname aufrufen.
> Und die Sourcen gibt es z.B. unter
> http://www.gnu.org/software/cflow/manual/html_node/Source-of-wc-command.html

von None (Gast)


Lesenswert?

Schau Dir dieses einmal an:
http://www.roseindia.net/c-tutorials/c-string-tokenizer.shtml

Dann bekommst Du mit Sicherheit die passenden Ideen.

von Dirk B. (dirkb2)


Lesenswert?

None schrieb:
> Dann bekommst Du mit Sicherheit die passenden Ideen.

Da steht aber nicht, wie man strtok programmiert.

Zudem ist es auch gar nicht nötig zeilenweise zu lesen.
Man kann nach jedem Zeichen entscheiden ob es zu einem Wort oder 
Leerraum gehört.

Wichtig ist nur die Definition für Wort ( nur Buchstaben, auch Zahlen, 
alles was ein darstellbasres Zeichen ist)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.