C-Programmieraufgabe

Hallo,
ich bräuchte dringend eure Hilfe.

Und zwar muss ich:
1.) einen Funktionskopf schreiben, der prüfen soll, ob eine Zeichenkette nur aus den Buchstaben a,A,c,C,g,G und t,T besteht.

2.) einen weiteren Funktionskopf angeben, der den Hamming-Abstand von zweich gleich langen Zeichenketten berechnen soll.
Ich habe zwar verstanden wie man anhand von binären Zahlen den Hamming-Abstand berechnet, jedoch habe ich keine Idee wie ich das als eine Funktion schreiben kann.

Und als wär ich damit nicht schon genung überfordert :smile:

soll ich dann aus den beiden Funktionsköpfen eine main-Funktion schreiben, die zwei Zeichenketten als Kommandozeilenparameter erhält. Die Funktion soll dann prüfen, ob die unter 1.) genannten Buchstaben vorkommen, sie anschließend auflisten und dann vergleichen, ob die Zeichenketten gleich lang sind. Falls ja, soll dann der sogenannte Hamming-Abstand berechnet oder eine Fehlermeldung ausgeben werden.

Also ich hoffe ihr könnt mir irgendwie weiterhelfen. Ich bin echt für jeden noch so kleinen Tipp dankbar.

Lieben Gruß,
Jessi

Hallo.
Hier sollen zwar keine Hausaufgaben erledigt werden aber sind wir mal nicht so:

#include 
#include 
#include 

int verify\_string(const char \*);
int hamming\_dist(const char \*, const char \*);

int main(int argc, char \*argv[])
{
 if(argc!=3) {
 printf("Usage: %s string string\n",argv[0]);
 system("pause");
 return 1;
 }
 char \*s1=argv[1];
 char \*s2=argv[2];
 if(verify\_string(s1)==0&&verify\_string(s1)==0) {
 printf("%s\n%s\n",s1,s2);
 if(strlen(s1)!=strlen(s2)) printf("Strings have different length\n");
 else printf("Hammingdistance: %d\n",hamming\_dist(s1,s2));
 }
 else printf("Strings do not only consist of the characters a, A, c, C, g, G, t, T\n");
 return 0;
}

int verify\_string(const char \*s)
{
 while(\*s!='\0') {
 switch(\*s) {
 case 'a': ;
 case 'A': ;
 case 'c': ;
 case 'C': ;
 case 'g': ;
 case 'G': ;
 case 't': ;
 case 'T': s++; break;
 default: return -1;
 }
 }
 return 0; 
}

int hamming\_dist(const char \*s1, const char \*s2)
{
 if(strlen(s1)!=strlen(s2)) {
 printf("Strings have different length");
 return -1;
 }
 int i, hd=0;
 while(\*s1!='\0') {
 if(\*s1!=\*s2) hd++;
 s1++;
 s2++;
 } 
 return hd;
}

Liebe Grüße.
Alex

Wow. Ich hatte nicht mit einer so schnellen und kompletten Lösung gerechnet. Wäre ja schon mit ein paar hilfreichen Tipps zufrieden gewesen. Trotzdem vielen lieben Dank.

Werd das gleich morgen in der Uni testen :smile:

Lieben Gruß,
Jessi

Hallo nochmal.

Also ich habe jetzt das Programm getestet. Wenn ich es kompiliere und ausführen lasse, kommt leider die Fehlermeldung: usage: a.out string string.
Kann mir eventuell jemand sagen was das bedeuten soll?

Danke.

Gruß, Jessi

Hallo Jessi,

Also ich habe jetzt das Programm getestet. Wenn ich es
kompiliere und ausführen lasse, kommt leider die
Fehlermeldung: usage: a.out string string.
Kann mir eventuell jemand sagen was das bedeuten soll?

Das ist ganz klar. Es bedeutet, daß Du den Quelltext
vom „softwareschmied“ einfach so ohne nachzudenken
kopiert und höchstwahrscheinlich nicht ein einziges
Mal überhaupt nur angesehen hast (oder angesehen und
nicht verstanden).

Weiterhin bedeutet es, daß Du mit den üblichen
Konventionen von Unix/Linux-Kommandozeilen-
programmen nicht vertraut bist.

Letztlich bedeutet es aber auch, daß Du mit den
Konventionen des von Dir verwendeten Compilers
nicht vertraut bist.

Hinsichtlich dieser Schwächen halte ich Deine
obige ernste Nachfrage nach der „Hamming-Distanz“
von Strings für entweder absurd oder Deiner Lern-
Situation völlig unangemessen.

Grüße

CMБ

Hallo.

Fehlermeldung: usage: a.out string string.
Kann mir eventuell jemand sagen was das bedeuten soll?

Du hast in deinem Ursprungsposting geschrieben, dass die beiden zu vergleichenden Zeichenketten als Komandozeilenparamter übergeben werden sollen.
Also startest du das Programm auf der Kommandozeile und hängst hinten die beiden Zeichenketten, getrennt durch ein Leerzeichen dran.
z.b: wenn das kompilierte Programm „a.out“ heisst startest du es als:
a.out atjgAAt atjgAAG
Liebe Grüße.
Alex
P.S.: Ich hab das Programm jetzt leicht abgeändert. Wenn nicht zwei Kommandozeilenparameter eingegeben wurden fragt es jetzt danach.

#include 
#include 
#include 

int verify\_string(const char \*);
int hamming\_dist(const char \*, const char \*);

int main(int argc, char \*argv[])
{
 char s1[100], s2[100];
 if(argc!=3) {
 printf("Erste Zeichenkette: (Maximal 100 Zeichen) ");
 gets(s1);
 printf("Zweite Zeichenkette: (Maximal 100 Zeichen) ");
 gets(s2);
 }
 else {
 strncpy(s1, argv[1], 100);
 strncpy(s2, argv[2], 100);
 printf("%s %s",s1,s2);
 }
 if(verify\_string(s1)==0&&verify\_string(s1)==0) {
 printf("%s\n%s\n",s1,s2);
 if(strlen(s1)!=strlen(s2)) printf("Strings have different length\n");
 else printf("Hammingdistance: %d\n",hamming\_dist(s1,s2));
 }
 else printf("Strings do not only consist of the characters a, A, c, C, g, G, t, T\n");
 system("pause");
 return 0;
}

int verify\_string(const char \*s)
{
 while(\*s!='\0') {
 switch(\*s) {
 case 'a': ;
 case 'A': ;
 case 'c': ;
 case 'C': ;
 case 'g': ;
 case 'G': ;
 case 't': ;
 case 'T': s++; break;
 default: return -1;
 }
 }
 return 0; 
}

int hamming\_dist(const char \*s1, const char \*s2)
{
 if(strlen(s1)!=strlen(s2)) {
 printf("Strings have different length");
 return -1;
 }
 int i, hd=0;
 while(\*s1!='\0') {
 if(\*s1!=\*s2) hd++;
 s1++;
 s2++;
 } 
 return hd;
}

@softwareschmied: vielen lieben dank für deine Hilfe :smile:

@Semjon Michailowitsch: Ja ich habe das Programm an dem Tag aus Zeitmangel nur kopiert und leider auch nicht verstanden. Ich wollte es auch nur einmal testen um es mir dann von einem Freund in Ruhe erklären lassen, denn leider habe ich überhaupt kein Verständnis fürs Programmieren.

Und ja ich bin auch nicht mit den Konventionen meines Compilers vertraut. Er wurde uns vorgeschrieben. Und wenn ich von meinem Tutor bei einer „Fehlermeldung 305“ auf Nachfrage zu hören bekomme, „Das weiß ich jetzt auch nicht. Da müsst ihr mal schauen“, dann denk ich mir was für eine großartige Hilfe.

Aber falls du meinen ersten Eintrag richtig gelesen hättest, hättest du bemerkt, dass ich gar keine fertige Lösung erwartet hatte, sondern vielmehr Ansätze die mir dabei hätten helfen können das alle zu verstehen. Denn hätte ich irgendetwas für mich verständliches in Büchern oder anderen Internetseiten gefunden, dann hätte ich doch hier nicht um Hilfe gebeten.

Gruß, Jessi

Hallo Jessi,

@Semjon Michailowitsch:

Aber falls du meinen ersten Eintrag richtig gelesen hättest,
hättest du bemerkt, dass ich gar keine fertige Lösung erwartet
hatte, sondern vielmehr Ansätze die mir dabei hätten helfen
können das alle zu verstehen. Denn hätte ich irgendetwas für
mich verständliches in Büchern oder anderen Internetseiten
gefunden, dann hätte ich doch hier nicht um Hilfe gebeten.

OK, so betrachtet war meine (offen und ehrlich gemeinte)
Antwort vielleicht etwas überzogen. Vielleicht kann ich,
im Sinne Deiner Anfrage, denn doch noch etwas hilfreiches
beitragen.

Zwar hat softwareschmied schon eine fertige Lösung angeboten,
diese ist aber imho nicht optimal auf das Problem zugeschnitten.

Deine Problemstellung sieht sehr nach DNA-Basen aus. Insofern
wären folgende Schritte zu machen:

  1. Stringlängen gleich/ungleich in etwa so:

    int l1 = strlen(argv[1]), l2 = strlen(argv[2]);

    if(l1 != l2) {
    … Fehler
    }

was der Konvention entspricht, daß die main()-Funktion
(der Eintrittspunkt des Programms in C) folgende Signatur
hat:

 int main(int argc, char \*argv[]) 

wobei argc die Anzahl der „Worte“ auf der Kommandozeile
und argv[] das Feld mit den Inhalten ist. Daher stehen
die Strings in argv[1] bzw. argv[2] (in argv[0] steht
der Programmname selbst => siehe softwareschmieds Lösung).

  1. Der nächste Schritt bestünde imho darin, die Strings
    in einen Puffer (sall) der Länge l1+l2 zu kopieren, um
    diese besser behandeln zu können:

    char *sall = malloc(l1 + l2 + 2);
    char *s1 = strcpy(sall, argv[1]);
    char *s2 = strcpy(sall+l1, argv[2]);

  2. Da es sich um DNA-Basen handelt, können wir alle
    in Großbuchstaben umwandeln, um leichter vergleichen
    zu können:

    char *p = sall;

    do *p &= ~0x20; while(*p++); /* make all chars lower case */

Die Umwandlung von Groß- zu Kleinbuchstaben bei ASCI besteht
im Ausblenden eines Bits in der Binärdarstellung (Bit 6).
Welches Bit das ist, siehst Du, wenn Du im Windows-
taschenrechner aus „wissenschaftliche Ansicht“ umstellst,
die Zahl 32 (20hex) eingibst und dann unter der Anzeige
auf (*)Bin klickst.

  1. Hast Du reine Großbuchstaben, besteht die Berechnung der
    Hamming-Distanz nur noch aus einem XOR der Buchstaben
    an den entsprechenden Stellen in den Strings. Liefert
    das XOR einen Wert, sind die Buchstaben unterschiedlich
    (hd = hd + 1), ansonsten bleibt sie gleich:

    const char *s = sall;
    const char *p = s + (l1+l2)/2;
    dist = 0;

    do dist += !!(*s++^*p++); while(*p)

Dieses !! vor der runden Klammer ist die doppelte Negation,
sie bedeutet: wenn (0), dann 0; wenn (nicht 0) dann 1
(ein übliches Idiom).

  1. Ach ja, bleibt nur noch die Feststellung, ob nur
    „erlaubte“ Buchstaben vorkommen. Um das genau dann
    zu Lösen, wenn die Menge der vorkommenden Buch-
    staben „überschaubar“ ist, benutzt man eine sog.
    lookup table (Nachschlagetabelle), in der
    man die Stellen für alle nicht erlaubten Buchstaben
    mit „1“ und die der erlaubten Buchstaben mit „0“
    belegt. Dann addiert man nur noch über alle Zeichen
    im String: summe = summe + lookup_table[charachter]
    Wenn die Summe 0 bleibt, warennur erlaubte Zeichen im
    String, ein unerlaubtes Zeichen führt zu „nicht 0“,
    also zu einem Fehler:

    const char* erlaubt = „AaTtCcGg“;
    const char* s = sall;
    int sum = 0;
    unsigned char lut[256];

    memset(lut, 1, sizeof(lut));
    do lut[*erlaubt] = 0; while(*erlaubt++);
    do sum += lut[*s]; while(*s++);
    // if sum !=0 dann => Fehler

Aus diesen Betrachtungen könnte man ein Programm entwerfen,
das auch DNA-Strings sehr großer Länge in kurzer Zeit
verarbeitet und das Resultat ausgibt.

Naja, hoffentlich habe ich nicht mehr Verwirrung
als Nutzen gestiftet :wink:

Grüße

CMБ

1 Like