Problem in C mit einem Programm zum Zeichen zählen



  • Hey Jungs ich soll eine Aufgabe für die Uni machen.
    Es sollen Zeichen gezählt werden.
    Der Benutzer soll einen beliebigen Text eingeben dürfen, von dem nur
    die ersten 150 Zeichen verwendet werden sollen. Anschließend werden
    die verschiedenen Zeichen des Textes (auch deutsche Umlaute, Ziffern,
    Leerzeichen, Sonderzeichen, usw.; also wirklich alle Zeichen) gezählt
    und die Anzahl in dem Array gespeichert. Groß- und Kleinschreibung soll
    dabei nicht unterschieden werden. Am Ende wird die Anzahl der
    einzelnen Zeichen tabellarisch ausgegeben (nur die Zeichen, die auch im
    Text vorkommen!), und zwar so, dass die gesamte Tabelle auf einer
    Bildschirmseite zu sehen ist. D.h. es muss eine mehrspaltige Tabelle
    verwendet werden. Dabei soll jeweils erst das Zeichen –
    bei ASCII-Werten unter 32 ein Leerzeichen –, dahinter in Klammern der
    hexadezimale ASCII-Wert des Zeichens und dann die Anzahl der
    gezählten Zeichen ausgegeben werden. Beachten Sie auch, dass Sie die
    Tabelle in der letzten Zeile bis zum rechten Rand ausgeben, auch wenn
    es keine weiteren Einträge mehr gibt!

    Ich bin zur Zeit soweit gekommen

    #include <string.h>
    #include <stdio.h>
    char intToChar(int);
    void Einlesen(char *treffer,int *anzTreffer);
    void printTable(char *treffer, int *anzTreffer);
    int main()
    {
     char treffer[256]; int anzTreffer[256];
     Einlesen(treffer, anzTreffer);
     printTable(*treffer,*anzTreffer);
    
     return 0;
    }
    
    char intToChar(int i)
    {
       char c;
       if (i<256)
       {
          c=(char)i;
          return c;
       }
       return '\n';
    }
    
    void Einlesen(char *treffer,int *anzTreffer)
    {
     char kette[151];
     int i;
     int j;
     int c;
     printf("Bitte Zeichenkette (max.150) eingeben: ");
     scanf("%150s", kette);
     for (i = 15; i <= 256; i++)
     {
        c=intToChar(i);
        for (j = 1;j <=strlen(kette);j++)
        {
           if(c==kette[j])
           {
               anzTreffer[i]++;
               treffer[i]=c;
           }
        }
     }
    }
    
    void printTable(char *treffer, int *anzTreffer)
    {
      int i;
      for (i=15; i <=256; i++)
      {
        if(anzTreffer!=0)
        printf("%c %i | %c %i | %c %i | %c %i \n", treffer[i], anzTreffer[i], treffer[i+1], anzTreffer[i+1], treffer[i+2], anzTreffer[i+2], treffer[i+3], anzTreffer[i+4]);
      }
    }
    

    Jedoch bekomme ich keine Ausgabe.

    Könnt ihr mir helfen?

    Lg





  • nee ist nicht wirklich hilfreich fande ich.

    Hat jemand hier eine Idee was ich verändern muss?

    Lg



  • hast du beide threads schon gelesen? vollständig? da wird genau das gemacht was du machen mußt?
    🙄



  • öhhm ich würde sagen nein 😉 da die beiden mit Prozenten arbeiten und ich aus deren quelltexten nicht so wirklich schlau werde.

    Wäre schön wenn man lieber auf meinen Quelltext eingeht anstatt andere Quelltexte zu zeigen.



  • also spannend wirds für dich hier

    //zaehlt wie oft ein zeichen vorkommt
    void countChars(int count[],char *str){
        while(*str)
          count[(unsigned char)*str++]++;
    }
    //a-z wird zu den A-Z zeichen addiert
    void mergeUpperAndLowerChars(int count[]){
        int i;
        for(i='a';i<='z';i++){
            if(count[i]){
                count[i+('A'-'a')]+=count[i];
                count[i] = 0;
            }
        }
    } 
    
    //das gibts dir wieder aus
    void plotCountCharsBuffer(int count[],int length){
        int l = 0xFF+1;
        float buffer = 100/((float)length);
        while(--l){
            if(count[l]>0){
                printf("%c:\t%d\t%f %%\n",(char)l,count[l],buffer*((float)count[l]));
            }
        }
    }
    

    gefunden im 2.link (19:49:53 12.01.2010) ist nicht exact was du brauchst aber doch schon recht nah dran...

    lg lolo



  • also ich denke nur das wäre für mich interessant.

    //das gibts dir wieder aus
    void plotCountCharsBuffer(int count[],int length){
        int l = 0xFF+1;
        float buffer = 100/((float)length);
        while(--l){
            if(count[l]>0){
                printf("%c:\t%d\t%f %%\n",(char)l,count[l],buffer*((float)count[l]));
            }
        }
    

    Weil Zeichen zählen etc habe ich ja schon.

    Nur was es mit dem buffer auf sich hat, versteh ich nicht.
    Ich würde es einfach so machen die Ausgabe das man eine Schleife macht wo er alle zeichen durchzählt und bei jedem Buchstaben(Asci Wert) die Treffer Anzahl größer =1 ist soll er ausgeben.

    Das wird ja hier nicht gemacht 😞



  • stell dir mal vor du hast einen string mit deinen 150+x zeichen, ein zeichen dieses strings ist ein char und hat 8 bit und diese 8 bit gehen von o-0xFF +- ein bischen, ok, also was ist die einfachste lösung?

    wir verwenden ein array mit 0xFF+1 int werten z.b.

    int myArray[0xFF+1];
    

    jetzt fragst du dich warum na ganz einfach wir verwenden einen buchstaben als index und der inhalt ist die anzahl, hoffe das ist soweit klar?

    myArray['h']++;
    myArray['a']++;
    myArray['l']++;
    myArray['l']++;
    myArray['o']++;
    

    und jetzt mal langsam mit einem string

    char str[] = "asdasddasd";
    myArray[str[0]]++;//a
    myArray[str[1]]++;//s
    myArray[str[2]]++;//d
    

    das machen wir in einer schleife die schaut dann so aus

    void countChars(int count[],char *str){
        while(*str)
          count[(unsigned char)*str++]++;
    }
    
    evtl. mal bischen anders
    
                        +--unser Array[0xFF+1]
                        |
                        |             +--unser String
                        v             v
    void countChars(int count[],char *str){
        int count = 0;
        while(str[count]){
            count[(unsigned char)str[count]] = count[(unsigned char)str[count]] + 1;
            count = count + 1;
        }
    }
    

    das ist doch viel einfacher als

    for (i = 15; i <= 256; i++)
     {
        c=intToChar(i);
        for (j = 1;j <=strlen(kette);j++)
        {
           if(c==kette[j])
           {
               anzTreffer[i]++;
               treffer[i]=c;
           }
        }
     }
    

    oder? so sollten wir mal anfangen bevor wir uns um die ausgabe kümmern 😉



  • Wenn du das so machen willst kannst du das ja nicht ein beliebigen Text eingeben
    wenn du die Index im int myArry selbst bestimmst.

    und außerdem zählt er dir doch bei der while sache nur ein zeichen. Das muss man doch mit einer Schleife lösen.

    Ob das was du machst einfach er ist weiß ich nicht, weil ich versteh das nicht 🙂 dafür aber das was ich gemacht habe^^

    Lg



  • schade eigentlich und ich hab mir so viel mühe beim erklären gegeben 😞



  • TeamNoX schrieb:

    Jedoch bekomme ich keine Ausgabe.

    dann ist 'anzTreffer' höchstwahrscheinlich 0, d.h. deine einlesefunktion ist wohl verbuggt.
    🙂



  • na ja, verbugt ist schon ganz richtig 🙂
    klar ist, dass man das wesentlich "schöner" u. letztendlich auch kürzer bzw. weniger fehlerträchtig machen könnte.
    Trotzdem war der Grundgedanke ok, sodaß ich mir den code mal angeschaut habe ( lerne grad selbst mal wieder etwas c aus spass an der freud 😉

    vorab erstmal, die Lösung ist immer noch nicht korrekt i.S. der Aufgabenstellung aber es gibt schon mal eine halbwegs korrekte Ausgabe, hier erstmal eine "verbesserte" Version:

    #include <string.h>
    #include <stdio.h>
    char intToChar(int);
    void Einlesen(char *treffer,int *anzTreffer);
    void printTable(char *treffer, int *anzTreffer);
    int main(){
     char treffer[256]; int anzTreffer[256];
    	for (int i=0;i<256;i++){
    		treffer[i]=' ';
    		anzTreffer[i]=0;
    	}
     Einlesen(treffer, anzTreffer);
     printTable(treffer,anzTreffer);
     return 0;
    }
    
    char intToChar(int i){
       char c;
       if (i<256)   {
          c=(char)i;
          return c;
       }
       return '\n';
    }
    
    void Einlesen(char *treffer,int *anzTreffer){
     char kette[151];
     int i;
     int j;
     int c;
     printf("Bitte Zeichenkette (max.150) eingeben: ");
     fgets(kette ,151,stdin);
     for (i = 15; i < 256; i++) {
        c=intToChar(i);
        for (j = 0;j <strlen(kette);j++)    {
           if(c==kette[j])       {
               anzTreffer[i]++;
               treffer[i]=c;
           }
        }
     }
    }
    
    void printTable(char *treffer, int *anzTreffer){
      int i;
      for (i=15; i <=256-4; i+=4)  {
        //if(anzTreffer!=0)
        printf("%c %i | %c %i | %c %i | %c %i \n", treffer[i], anzTreffer[i], treffer[i+1], anzTreffer[i+1], treffer[i+2], anzTreffer[i+2], treffer[i+3], anzTreffer[i+3]);
      }
    }
    

    die gefundenen "Macken" bisher:
    - bei mir hat schon der Compiler gestreikt, weil der Aufruf der Methode printTable nicht mit den korrekten Parametern erfolgte.
    - wenn man Arrays benutzt, sollte man sie sicherheitshalber als erstes initialisieren
    - die Ausgabefunktion gibt 4 Felder auf einmal aus, deshalb i+=4 im Scheifenrumpf, auch die Abbruchbedingung muss entspr. angepasst werden
    - scanf liest nur bis zum ersten whitespace ( z.b. leerzeichen) ein, deshalb hab ich fgets benutzt ( es sollen ja alle character gezaehlt werden, also auch spaces )
    - der erste char der eingabe ist kette[0] nicht kette[1]

    was noch offen ist: es sollen groß-/kleinbuchstaben äquivalent sein/gezaehlt werden
    - die zeichen <= 13 sollen zwar als space dargestellt, aber vermutlich trotzdem gezaehlt werden
    - das zeichen selbst soll im hexcode ausgegeben werden

    ansonsten ist die Funktion zum umwandeln von int-> char relativ überflüssig, das muesste mit einem simplen Cast von int auf unsigned char auch funktionieren.

    greetz,
    olli



  • kermitaner schrieb:

    was noch offen ist: es sollen groß-/kleinbuchstaben äquivalent sein/gezaehlt werden

    nimmst du 'toupper()' oder 'tolower()' um alles gross oder klein zu machen.

    kermitaner schrieb:

    - die zeichen <= 13 sollen zwar als space dargestellt, aber vermutlich trotzdem gezaehlt werden

    naja, if (zeichen <=13) zeichen = ' ';

    kermitaner schrieb:

    - das zeichen selbst soll im hexcode ausgegeben werden

    das geht mit printf und '%x', z.b.: printf ("%02x", zeichen);
    🙂



  • Hey,

    genau solche Antworten wollte ich die sich auf meinen Quellcode beziehen.
    Weil ich denke Programmieren ist ein Stück Weit "Kunst" jeder macht es anders.

    Das mit der Hex Ausgabe funktioniert nicht so wirklich.

    void printTable(char *treffer, int *anzTreffer)
    {
    int i;
    for (i=15; i <=256-4; i+=4)
    {
    if(anzTreffer!=0)
    printf("%c %i | %c %i | %c %i | %c %i \n", treffer[i], anzTreffer[i], treffer[i+1], anzTreffer[i+1], treffer[i+2], anzTreffer[i+2], treffer[i+3], anzTreffer[i+3]);
    }
    }
    Da müsste man ja noch ein Parameter übergeben oder? Oder wie kann ich das realisieren.

    Und zu der Groß und Kleinschreibung.
    Muss ich die Fuktion selber schreiben?
    Ich brauch ja eig nur eine und zwar die GroßzuKlein Buchstabe.

    Hier ist nochmal die Aufgabe Detailiert:
    http://public.beuth-hochschule.de/~kempfer/2009ws2010/ueb10/ueb10.pdf
    edit: unten im Link ist ein Beispiel wie es aussehen soll.

    achso und was noch fehlt ist das nur die zeichen angezeigt werden die auch nur vorhanden sind 😃 vielen Dank nochmal für die Hilfe

    Lg



  • TeamNoX schrieb:

    Das mit der Hex Ausgabe funktioniert nicht so wirklich.

    void printTable(char *treffer, int *anzTreffer)
    {
    int i;
    for (i=15; i <=256-4; i+=4)
    {
    if(anzTreffer!=0)
    printf("%c %i | %c %i | %c %i | %c %i \n", treffer[i], anzTreffer[i], treffer[i+1], anzTreffer[i+1], treffer[i+2], anzTreffer[i+2], treffer[i+3], anzTreffer[i+3]);
    }
    }

    ersetze er mal diese ganzen %c gegen %02x.

    TeamNoX schrieb:

    Und zu der Groß und Kleinschreibung.
    Muss ich die Fuktion selber schreiben?

    nee, die gibts schon fertig: http://www.cplusplus.com/reference/clibrary/cctype/tolower/
    🙂



  • na ja, weils anscheinend pressiert ( Abgabe spätestens 22.1 😉
    hier mal die ausgabe

    void printTable(char *treffer, int *anzTreffer){
      int i,spalte=0;
    	char c2;
    	printf("|-------------------------------------------------------|\n|");
      for (i=0; i <=255; i++)  {
        if(anzTreffer[i]>0){
    		c2=(treffer[i]>' ')?treffer[i]:' ';
        	printf(" %c (0x%02X): %d |",c2,i,anzTreffer[i]); 
    		spalte++;
    		if(spalte>=4){
    			printf("\n|");
    			spalte=0;
    		}
    
    	}
      }
    	//rest der letzten zeile ausgeben, falls noetig
    if (spalte>0){ 
      	for (i=spalte;i<4;i++){
    		printf("             |");
    	}
    	printf("\n");
    
    }
    	printf("|-------------------------------------------------------|\n");
     }
    

    kleiner tipp noch, in der windows dos box kann man mit "Alt"+ziffern (3 stellig) ueber numblock den asci code direkt eingeben, so kann man pruefen, ob auch das zeichen #255 korrekt erkannt u. gezaehlt wird.
    wenn nix eingegeben wird, wird aber noch ein "|" zuviel ausgegeben, das könnte man auch noch wegoptimieren, oder man zaehlt den zeilenumbruch "\n" generell mit 😉



  • ^^also die formatierung von dem code ist ja wohl gruselig. rück den mal vernünftig ein, öffnende { in die nächste zeile und so. so mag das ja keiner lesen. *fg*
    🙂



  • Naja ich denke jedem seins 🙂

    Gibt ja keinen offiziellen Standart oder?

    Was macht denn die Zeile.
    Die versteh ich nicht so ganz.

    c2=(treffer[i]>' ')?treffer[i]:' ';
    

    Des weitern habe ich die Funktion tolower eingesetzt hier in der Einlesen Funktion.

    void Einlesen(char *treffer,int *anzTreffer)
    {
       char kette[151];
       int i;
       int j;
       int c;
       printf("Bitte Zeichenkette (max.150) eingeben: ");
       fgets(kette ,151,stdin);
       for (i = 15; i < 256; i++)
       {
          c=intToChar(i);
           while (kette[i])
           {
              c=kette[i];
              putchar (tolower(c));
              i++;
           }
    
          for (j = 0;j <strlen(kette);j++)
          {
              if(c==kette[j])
              {
                 anzTreffer[i]++;
                 treffer[i]=c;
              }
          }
        }
    }
    

    Aber er macht mir die nicht groß. Die Funktion muss doch das Arry kette durchgehen und jeden eingegeben Buchstaben klein umwandeln oder?
    Oder wo muss ich sie einsetzen?

    Lg



  • TeamNoX schrieb:

    Naja ich denke jedem seins 🙂

    Gibt ja keinen offiziellen stan**** oder?

    nein aber es gibt definitive nogo's 😉



  • du meinst mit den { direkt hinter der anweisung?
    also

    if (a>b) {
    

    ?

    Weil sonst fällt mir nichts an der Formatierung von kermitaner.
    Macht auch 3 Leerzeichen immer usw.

    Lg


Anmelden zum Antworten