Anfängerfrage zu: Strings verketten



  • Hi,

    Dies ist mein erster Post hier und ich sag erstmal:

    printf("Hallo zusammen\n");
    

    Bevor ich gleich mit Fragen löchere,möchte ich mich schon vorab bei allen bedanken die sich die Mühe machen diesen Post zu lesen (und evtl. auch zu antworten).

    Ich habe mit C angefangen. Diese Beichte haben bestimmt schon viele Anfänger hier abgelegt. Vielleicht mal ein Satz dazu warum überhaupt. (Ich denke im ersten Posting kann man sich mal die Zeit dafür nehmen).

    Ich habe begonnen mich mit Microcontrolern zu beschäftigen, da habe ich schnell gemerkt, dass C recht hilfreich sein kann wenn man dem MC Assemblerdialekt nicht ausgeliefert sein will.

    Also hab ich mir "Pelles C" installiert, ein bischen im Wiki book über C gerumgestöbert und losgelegt. Ein paar Tutorials habe ich auch schon gelesen.

    Nach etwa zwei Tagen hab ich es dann sogar geschafft ein paar einfache numerische Programme zu schreiben. (Faktorisierung, Primzahlsuche, Collatz Folge, etc...). Das hat auch soweit ganz gut geklappt.

    Sonst programmiere ich meistens Delphi und (arbeitsbedingt) Visual Basic.
    Naja gut, in der Mittelstufe (also in jungen Jahren) auch GWBasic.

    Daher lief dass auch ganz gut. Der Syntax ist etwas "rustikal" (für Pascal verwöhnte Hände 😉 ) aber noch lange kein Nebel dunkler Verwirrung zu der C immer gerne erklärt wird.

    Dann habe ich mich an strings gewagt. Und hier wird es nun etwas schwierig für mich.

    Ich versuche mit "strings" (die es ja harnicht gibt) zu arbeiten und sage mir dabei immer gebetsmühlenartig selbt: "Strings gibt es nicht. Es gibt nur Arrays. Strings gibt es nicht."
    Und in Pascal kann man, so man denn will, ja uch einen string wie ein eindimensionales array behandeln.

    Ich poste nun mal ein kleines Program bei dem ich die ganze Sache aber nicht mehr verstehe. Ich führe dann aus welche GEdanken ich mir dabei gemacht habe. (Vielleicht ist mein Ansatz ja schon um die Ecke herum verkehrt gedacht.)

    #include <stdio.h>
    #include <stdarg.h>
    #include <string.h>
    
    int SumReturn(int x,...)
    {
      int result;
      va_list liste;
    
      result = 0;
      va_start(liste,x);
    
      for (int i=0;i<x;i++)
        {
    	  result += va_arg(liste,int);
    	}  
    
      va_end(liste);
    return result;
    }
    
    char* TextReturn(int n,...)
    {
      char *result;
      char *source;
      va_list list;
    
      va_start(list,n);
       result = va_arg(list,char *);
       source = va_arg(list,char *);
       //*strcat(result,source); 
      va_end(list);
    return result;
    }
    
    int main(void)
    {
      int number;
      char *text;
    
      number = SumReturn(5,1,2,3,4,5);
      text = TextReturn(3,"Hallo ","Welt ","!!!");
      printf("\n  Summe: %d\n\n",number);
      printf("\n  Text: %s\n\n",text);
    return 0;
    }
    

    Worauf das hier hinauslaufen soll is ein Aneinanderstricken der Stringliste.

    Mein Problem ist nun genau die "strcat" Funktion.
    Die C Dokumentation sagt:

    char * strcat(char * restrict dst, const char * restrict src);
    

    Das verstehe ich so:
    Die Funktion liefert einen Zeiger auf ein character.
    Die Funktion erwartet Zeiger auf character.

    Ich dachte genau das liefer ich mit den vaiablen "source" und "result", da:

    char *result;
      char *source;
    

    Aber leider schmiert das Program sofort ab.

    Ich hab dnn ein wenig rumgespielt und es mal mit statischem Text und in der Grösse definierten char arrays probiert, und das funktioniert einwandfrei.

    Also könnte es am "restrict" liegen, dachte ich. "Restrict" klingt ja schonmal sehr einschränkend. Da alle Tutorials strcat nur mit eben statischem Text gezeigt haben hat mir das nicht weitergeholfen. Auf "restrict" wurde da nie eingegangen.
    Also fix gegoogelt, dass hier gefunden:

    http://developers.sun.com/solaris/articles/cc_restrict.html

    ... und nur Bahnhof verstanden (und dass liegt nicht daran weil der Text auf englisch ist 😉 )

    Wenn mir da bitte jemand etwas Erleuchting brächte, wäre das super.

    Schlussendlich habe ich dochnoch ein Beispiel für das Stringstricken gefunden, aber das macht nicht ganz das was ich vorhatte:

    void strxcat(int n_strings, ...)
    {
       va_list zeiger;
       char *quelle, *ziel, *p;
       int counter=0;
    
       va_start(zeiger,n_strings);
    
       /*Nun auf den Zielstring*/
       ziel = va_arg(zeiger,char *);
       p = ziel;
       /*Am Ende vom Zielstring*/
       ziel+=strlen(ziel);
    
       if( (ziel-p) > MAX)
          {
             printf("!!!Max. Anzahl Zeichen Überschritten!!!\n");
             return;
          }
    
       while(--n_strings > 0)
          {
             /*Quelle einlesen*/
             quelle=va_arg(zeiger, char *);
             /*Jetzt Zeichen für Zeichen an ziel*/
             while(*quelle)
                {
                   *ziel++ = *quelle++;
                   if( (ziel-p) > MAX)
                      {
                         printf("!Max. Zeichen ueberschritten!\n");
                         exit(0);
                      }
                }
          }
       *ziel = '\0';
    }
    

    Zum eine wird hier der String nicht zurückgegeben (void) und zum anderen verstehe ich die Kopieraktion nicht so ganz.

    Konkret:

    while(*quelle)
    

    Für mich heisst das hier aber so etwas "Solange Zeiger auf die Quelle wahr".
    Da die quelle ja schon ein Zeiger ist, ist das also dann ein Zeiger auf den Zeiger auf die Zeichenkette der wahr sein muss? Oder ws hat der Stern hier zu suchen?

    Habe die Vermutung das ich das mit den Zeigern noch nicht so ganz geschnallt habe. 😕

    Ich hoffe ich gehe euch mit meinem ersten Posting nicht schon auf Denselbigen. 😃

    Cheers,
    Catweasel



  • Wenn du per

    char *s;
    

    einen Zeiger deklarierst, zeigt dieser zunächst nirgendwohin. Ihn zu dereferenzieren erzeugt undefiniertes Verhalten (d.h., der Standard definiert nicht, was eine Implementation in so einem Fall zu tun hat). So etwas sollte man vermeiden. Bevor du ihn benutzen kannst, musst du ihn initialisieren; in diesem Fall musst du ihn auf einen Speicherbereich zeigen lassen, der ausreichend groß ist, um den String zu fassen.

    Im Falle von strcat wird der Speicherbereich, an den etwas angehängt werden soll, als erster Parameter übergeben. Beispiel:

    char a[256] = "Hallo";
    strcat(a, ", Welt!");
    
    puts(a);
    

    wird "Hallo, Welt!" ausgeben. Es ist wichtig, sicherzustellen, dass in a genug Platz ist, um den kombinierten String aufzunehmen.

    Die restrict-Schlüsselwörter in

    char * strcat(char * restrict dst, const char * restrict src);
    

    versprechen dem Compiler, dass dst und src nie gleich sind (und nicht in den gleichen String zeigen). Genauer: Der restrict-Qualifier verspricht, dass innerhalb des Gültigkeitsbereichs des betreffenden Zeigers alle Zugriffe auf das Objekt, auf das der Zeiger zeigt, durch diesen Zeiger geschehen. Du kannst Kopien des Zeigers ziehen, aber wenn bei Eintritt in seinen Geltungsbereich ein anderer Zeiger das selbe Objekt referenziert, ist das Verhalten undefiniert.

    Dadurch kann ein optimierender Compiler schnelleren Code erstellen.

    while(*quelle) {
      /* ... */
    }
    

    heißt: Tu etwas so lange, wie das, worauf quelle zeigt, wahr ist. "Wahr" heißt hier "ungleich null", und da per Konvention Strings in C mit einem Null-Byte enden, heißt es hier "bis zum Ende des Strings".


Anmelden zum Antworten