C-Wörter zählen

Gast #3460206
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 :)
Gast #3460213
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
Gast #3460217
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.
Gast #3460221
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?
Gast #3460222
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.
Gast #3460223
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.
Gast #3460225
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!
Gast #3460234
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.
Gast #3460261
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
#3460322
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.
Gast #3460336
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
}
Gast #3460401
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
Persönliche Seite #3460416
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.
#3460475
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?
Gast #3460493
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()?
Persönliche Seite #3460509
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.
#3460529
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.
#3460550
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.
Gast #3460573
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.
#3460640
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)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren