# [c] Zählen der zeichen einer Zeichenkette



## Bismark (16. Januar 2011)

Hallo Lleute,
ich  bin gerade beim programmieren eines (Konsolen)Programms unter OpenSuse 10.1, bei dem ein Benutzer bis zu 150 zeichnen in ein char Array Eingeben kann, dabei existiert ein zweites Array von int, für die Anzahl der einzelnen zeichnen. Am ende sollen die alle Zeichen gezählt werden und (nur die eingegebenen) auf dem Bildschirm in einer Tabelle  ausgegeben werden. (Z.B. a =8; g = 9; k = 1).

Mein Problem ist, ich weiß nicht wie man ein Code schreibt, der eine art "Dynamische Tabelle" erstellt, der nur die eingegebenen zeichnen zählt und sie ausgibt noch wie man die zeichnen an sich zählen lässt. :-( 
Wobei bei Zeichenzählen könnte man doch eigentlich ein Sortieralgorithymus benutzen und anschließend die Felder miteinander vergleichen? 

Lg Bismark


----------



## sheel (17. Januar 2011)

Hi

Ich nehme an, du sprichst vom ASCII (bzw. irgendein Einbyte-Zeichensatz), kein Unicode etc?

Dann denkst du zu kompliziert 

Nimm ein int-Array, Größe 256.
In alle 256 0 reinschreiben.
Jetzt gehst du jeden eingegeben Buchstaben durch und zählst bei seinem Wert eins rauf (zB bei 'a' das 97. int)
Fertig.

Zum Ausgeben: Alle 256 ints durchgehen, den Index als Zeichen und den Inhalt als Anzahl nehmen.
Wenn du die nicht vorkommenden auslassen willst, gibst du eben nur die >0 aus.

Noch zu beachten: ASCII-Zeichen von 0 bis 31 in diesem Fall besser nicht direkt ausgeben, sondern irgendwas wie "Zeichen xx" hinschreiben.
Sonst bekommst du an unpassenden Stellen Zeilenumbrüche etc; sogar ein Ton ist dabei...

Und beim int-Array: Ich nehme an, dein String besteht aus signed chars.
Beim negativen Zeichen darfst du im int-Array nicht auf negative Indizes schreiben, sondern auf 128-255.
(index<0)?(256+index):index

Gruß


----------



## Trulleberg (17. Januar 2011)

```
#define MAXZEICHENZAHL 150

char eingabe[MAXZEICHENZAHL+1];
fgets( eingabe,sizeof eingabe,stdin );
if( strchr(eingabe,'\n') ) *strchr(eingabe,'\n')=0; else while( getchar()!='\n' );
printf("Es wurden %ld Zeichen eingegeben und zwar <%s>",strlen(eingabe),eingabe);
```
sollte wohl ein Ansatz zur Problemlösung sein.


----------



## Bismark (17. Januar 2011)

Hi,



sheel hat gesagt.:


> Hi
> 
> Ich nehme an, du sprichst vom ASCII (bzw. irgendein Einbyte-Zeichensatz), kein Unicode etc?
> 
> ...



Das Programm soll halt für die ASCII zeichen programmiert werden. Hab eine frage und zwar, es gibt ja zwei Arrays, einmal z.B. char Eingabe[151] und int Pruef[256]. Muss ich den Array Eingabe[] mit sich selbst vergleichen und bei Pruef[] hochzählen, woher wies ich denn z.B. bei welchem Array beim Pruef[] 'a' oder 'e' gezählt wird, vor allem bei der Ausgabe? Man muss es ja mehr oder weniger mit einer "Hilfvariable" durchführen. Wenn z.b. 't' eingegeben wird, nehme ich dann halt t als variable um den Index Hochzuzählen?

lg


----------



## sheel (17. Januar 2011)

Einem ASCII-Zeichen (zb 'a') ist einerseits der Buchstabe zugeordnet, andererseits auch die Nummer im Zeichensatz.
Bei zB a ist sie 97.

Und weil C/C++ so eine nette Sprache ist, kannst du es ohne weiteres in beiden Varianten verwenden, zB so:

```
pruef['a']=...;
```
Man muss nicht unbedingt eine Zahl als Index nehmen; hier wird dann eben 97 verwendet.

Setz zuerst alle 256 pruef-int auf 0, dann brauchst du nur noch sowas:

```
int i;
int len=strlen(Eingabe);

//Zuerst Nullsetzen
for(i=0;i<256;i++) pruef[i]=0;

//Jetzt den eigentlichen Code:
for(i=0;i<len;i++) pruef[ eingabe[i] ] ++;
```

Wirds so klarer?

Und um mienen Hinweis zu den negativen Zahlen noch zu beachten:
eingabe besteht eventuell aus signed chars, also -128 bis +127.
In pruef soll das aber von 0 bis 255 gehen, also muss negative Zahlen in 128-255 umrechnen

Also

```
for(i=0;i<len;i++) pruef[ (eingabe[i]<0)?(256+eingabe[i]):(eingabe[i]) ] ++;
```

Gruß


----------



## Bismark (17. Januar 2011)

Hi sheel,


sheel hat gesagt.:


> Einem ASCII-Zeichen (zb 'a') ist einerseits der Buchstabe zugeordnet, andererseits auch die Nummer im Zeichensatz.
> Bei zB a ist sie 97.
> 
> Und weil C/C++ so eine nette Sprache ist, kannst du es ohne weiteres in beiden Varianten verwenden, zB so:
> ...



danke, beim mir ist eine art "A-Ha" effekt eingetreten.  Ich bin immer davon ausgegangen, dass z.b. bei:


```
printf("%i", pruef[15]);
```

der 15. feld ausgegeben wird, sprich bei int wäre es ja nur eine Zahl.
Der Index des pruef[], wird doch mit erhöht, oder?


Lg Bismark


----------



## vfl_freak (17. Januar 2011)

Moin,



Bismark hat gesagt.:


> Ich bin immer davon ausgegangen, dass z.b. bei:
> 
> ```
> printf("%i", pruef[15]);
> ...



Nein, in Deinem Beispiel ist es bereits das 16. Feld, da ja der Index bei '0' beginnt !

Gruß
Klaus


----------



## Bismark (17. Januar 2011)

Hi,
mein fehler, stimmt. War nur so ein Denkfehler.


----------



## sheel (17. Januar 2011)

In dem Fall ist es aber egal; du musst nicht -1 oder so rechnen.

Die 256 int von prüf haben die Indizes 0-255; und die möglichen Werte von einem eingabe-char sind auch0-255.
Passt perfekt zusammen.


----------



## deepthroat (18. Januar 2011)

Hi.





sheel hat gesagt.:


> Die 256 int von prüf haben die Indizes 0-255; und die möglichen Werte von einem eingabe-char sind auch0-255.
> Passt perfekt zusammen.


Nur falls char nicht vorzeichenbehaftet ist. Du solltest char besser nach (unsigned char) casten wenn du es als Index für das Array verwendest.

Gruß


----------



## Bismark (18. Januar 2011)

Hi,
hab noch eine Frage. :-(
Wenn von diesen Arrays jeweils Zeiger erstellt und die Felder in einer Funktion hoch zählt wird, muss man ja in Prinzip folgendermaßen (als Beispiel) machen:

Hauptprogramm

```
int reset(*eingabe);
int zaehlen(*eingabe, *pruef );

int main()
{
Definition
   char Einagbe[151] ;       //für die Eingabe
   int  Uebrpruefen[255];  //zählen der zeichen
   
   //Zeiger
   char *eingabe = Eingabe;
   int  *pruef = Uebrpruefen;


     //Zeichenkette einlesen
      reset(*pruef );

      /Zählen des Zeichenanzahls
      zaehlen(*eingabe, *pruef );

   return 0;
}
```

Funktion zum zurücksetzen

```
int Reset(*pruef)
{
	//Schleife für das Nullsetzen
      for(i = 0; i < 256; i++)
	{
		*(pruef + i) = 0;
	}

return *pruef;
}
```



Wenn man jedoch den Zeichenanzahl über einen Zeiger in einer Funktion zählen lässt, muss man es folgendermaßen machen lassen? bzw. wie wird es eigentlich gemacht?

Funktion zum Zählen

```
zaehlen(*eingabe, *pruef );
{
      //Zeichenanzahl Zählen
      for(i=0;i<len;i++)
      {
	     *(pruef*(eingabe + i));
      }

    return *(pruef*(eingabe  + i));
}
```

Lg Bismark


----------



## sheel (19. Januar 2011)

Hi

1) zum ersten Codeteil: Lässt sich das kompilieren ?!

In den ersten zwei Zeilen musst du bei den Parametern schon angeben, ob sie int/char/etc... sind.

Im main, erste Zeile: Bei "Definition" fehlt wohl // vorne, oder?

Eingabe und Ueberpruefen haben Rechtschreibfehler (falls wen stört...)

Wichtiger: Warum ist Ueberpruefen nicht 256 lang, nur 255?
Es gibt 256 verschiedene char-Werte (entweder 0 bis 255 oder -128 bis +127).
Aber auch wenns nur bis 256 geht, musst du hier die Anzahl nehmen und auch die 0 mitzählen.
=256

Die zwei Zeiger in den nächsten Zeilen sind überflüssig.
Du kannst die ursprünglichen Variablen auch als Zeiger verwenden, sind ja auch nichts anderes.

Bei den Funktonsaufrufen daruner: Alle * weg!
Du willst ja die Zeiger auf die kompletten Arrays übergeben, nicht den Wert des ersten Arrayelements.

2) Zu Reset: Zeile 1: Dasselbe wie oben schon erwähnt, Typ des Parameters mitangeben.

Zeile in der Schleife: Warum so kompliziert? pruef[ i ] würde es auch tun.

Das return: Warum gibst du den ersten von 256 Nullern zurück? Wenn man im main einen Nuller braucht, kann man auch einfach 0 schreiben und ist nicht auf den Returnwert angewiesen .
Nimm als Rückgabetp void und lass das return komplett weg, das braucht keiner.

3) Zu zaehlen: Erste Zeile: Parametertypen, außerdem Rückgabetyp her und Strichpunkt weg.

Bei der Schleife: Wo kommt len auf einmal her?

In der Schleife und Returnwert: Ohoh. Du addierst die Adresse von eingabe und i.
Das Ergebnis multiplizierst (, Multiplizieren von Pointern?!) du mit der Adresse von pruef.
Das Ergebnis nimmst du wieder als Adresse und willst den Wert, wo sie hinzeigt.
Wenn du das alles hast, was machst du dann mit dem Wert? Nichts.
...Da ist Verbesserungsbedarf

Gruß


----------



## Bismark (20. Januar 2011)

Hi,
hab bei den meisten sachen nicht aufgepasst beim posten.
Mein problem ist halt ob man mit Zeigern - trottz dessen, dass Array auch zeiger sind - auf Arrays Zeigen kann und die Zeiger auf Arrays, z.B. folgendermaßen bearbeiten kann:


```
pruef[1] = 0;
```

Da ich paar mal im Internet mehrmals folgendes gelesen hatte:


```
for(i = 0; i < 256; i++)
   {
      *(pruef + i) = 0;
   }
```

Wie gesatgt, meine frage ist halt, beim zählen der Zeichenanzahl, ob man auch folgendermaßen beim zeiger machen kann:


```
*(pruef*(eingabe + i))
```


@ Arrays sind wie zeiger:
Hab gelesen, dass Arrays eine Adresse einer Adresse sind und Arrays/Felder der Name einer adresse sind


Lg Bismark


----------



## sheel (20. Januar 2011)

Arrays sollen Adressen von Adressen sein? Nur wenn du ein int-Array hast und als Werte Adressen nimmst.
Generell ist ein Array eine Ansammlung von Variablen mit dem gleichen Typ, diese liegen im Speicher genau hintereinander (ohne andere Sachen oder Leerräume dazwischen).
Die Variable im Programm hat die Adresse des ersten Elements.


```
*(pruef + i) = 0;
```
ist das Gleiche wie

```
pruef[i] = 0;
```

Beispiel: Angenommen, man hat ein char-Array c und die Adresse in der Variable ist 100
Das char-Array hat 3 chars, sind daher auf den Adressen 100, 101 und 102.
*(c + 1) ergibt jetzt was?
c+1 ist 100+1 ist 101, und *101 zeigt auf den cahr mit der Adresse 101
c[1] ist auch der char mit Adresse 101
c[0] ist auch der char wäre auf Adresse 100 und c[2] auf 102

Und dazu:

```
*(pruef*(eingabe + i))
```
hab ich mich ja eigentlich schon geäußert...
*xyz nimmt den Wert von xyz als Adresse und greift auf diese Adresse zu.
abc*xyz ist aber eine mathematische Multiplikation und hat mit Pointern nichts zu tun!
Du multiplizierst hier Speicheradressen, das ist in den seltensten Fällen sinnvoll...


----------



## Bismark (20. Januar 2011)

Ich meinte Zeiger sind Adressen von Adressen :-(
Felder sind Namen von Adressen :-(

Lg Bismark


----------



## sheel (20. Januar 2011)

Auch Pointer müssen keine Adressen von Adressen sein.
Pointer sind int mit einer Adresse als Wert.
Die Adresse kann von einem float sein, von einem double, einem Objekt einer Klasse, einem int...
Kann natürlich auch die Adresse von einem int sein, das wieder eine Adresse hat; muss aber nicht so sein.

Ein Pointer hat wie jedes normale int auch einen Variablennamen. Das hat überhaupt nichts mit Feldern zu tun.


----------

