Falsche Ausgabe



  • #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <alloc.h>
    
    #define NUMERIC   1      /* Numerisch sortieren */
    #define DECR      2      /* Absteigend sortieren */
    #define FOLD      4      /* Groß- und Kleinbuchstaben gleich */
    #define LINES     100    /* Maximale Anzahl zu sortieren */
    #define MAXLEN    100
    #define ALLOCSIZE 10000
    
    int chrcmp(char *s, char *t);
    int numcmp(char *, char *);
    int readlines(char *lineptr[], int maxlines);
    void qsort(char *v[], int left, int right, int (*comp)(void *, void *));
    void writelines(char *lineptr[], int nlines, int decr);
    
    char *alloc(int n);
    void swap (void *v[], int i, int j);
    
    int main(int argc, char* argv[])
    {
      char *lineptr[LINES];
      int nlines;
      int c, rc = 0;
      static char option = 0;
    
      while(--argc > 0 && (*++argv)[0] == '-')
        while(c = *++argv[0])
          switch(c)
          {
          case 'f':
            option |= FOLD;
            break;
          case 'n':
            option |= NUMERIC;
            break;
          case 'r':
            option |= DECR;
            break;
          default:
            printf("sort: illegal option %c\n", c);
            argc = 1;
            rc = -1;
            break;
          }
          if (argc)
            printf("Usage: Sort -nr \n");
          else
            if((nlines = readlines(lineptr, LINES)) > 0)
            {
              if (option & NUMERIC)
                qsort((void **)lineptr, 0, nlines-1, (int (*)(void *, void *))strcmp);
              else if (option & FOLD)
                qsort((void **)lineptr, 0, nlines-1, (int (*)(void *, void *))strcmp);
              writelines(lineptr, nlines, option & DECR);
            }
            else
            {
              printf("Input too big to sort\n");
              rc = -1;
            }
            return rc;
    }
    
    int readlines(char *lineptr[], int maxlines)
    {
      int len, nlines;
      char *p, line[MAXLEN];
    
      nlines = 0;
      len = 0;
      while((len = getline(line, MAXLEN)) > 0)
        if(nlines >= maxlines || (p = alloc(len)) == NULL)
          return -1;
        else
        {
          len = strlen(line);
          line[len-1] = '\0'; /* Zeilentrenner entfernen */
          strcpy(p, line);
          lineptr[nlines++] = p;
        }
        return nlines;
    }
    
    /* writelines: Zeilen ausgeben */
    void writelines(char *lineptr[], int nlines, int decr)
    {
      int i;
    
      if (decr)
        for (i = nlines-1; i >= 0; i--)
          printf("%s\n", lineptr[i]);
        else
          for (i = 0; i < nlines; i++)
            printf("%s\n", lineptr[i]);
    }
    
    /* alloc: Liefert Zeiger auf Platz für n Zeichen */
    char *alloc(int n)
    {
      static char allocbuf[ALLOCSIZE];
      static char *allocp = allocbuf;
      if (allocbuf + ALLOCSIZE - allocp >= n)   /* passt */
      {
        allocp += n;
        return allocp + n; /* alter Zeiger */
      }
      else
        return 0;
    }
    
    /* getline: eine Zahl lesen, Länge liefern */
    int getline(char *line, int max)
    {
      int c, i;
      c = 0;
      for (i = 0; i < max-1 && (c = getchar()) != EOF && c != '\n'; ++i)
        line[i] = c;
      if (c == '\n')
      {
        line[i] = c;
        ++i;
      }
      line[i] = '\0';
      return i;
    }
    
    int chrcmp(char *s, char *t)
    {
      for ( ; tolower(*s) == tolower(*t); s++, t++)
        if(*s == '\0')
          return 0;
        return tolower(*s) - tolower(*t);
    }
    
    /* qsort: Sortiere v[left]...v[right] in aufsteigender Reihenfolge */
    void qsort(char *v[], int left, int right, int (*comp)(void *, void *))
    {
      int i, last;
      void swap(void *v[], int, int);
      if (left >= right)
        return;
      swap(v, left, (left + right)/2);
      last = left;
      for (i = left+1; i <= right; i++)
        if ((*comp)(v[i], v[left]) < 0)
          swap(v, ++last, i);
      swap(v, left, last);
      qsort(v, left, last-1, comp);
      qsort(v, last+1, right, comp);
    }
    
    void swap (void *v[], int i, int j)
    {
      void *temp;
    
      temp = v[i];
      v[i] = v[j];
      v[j] = temp;
    }
    

    Das Programm erlaubt, die Eingabe von beliebig vielen Zeilen, die dann sortiert wieder ausgegeben werden. Das Problem, dass ich jetzt habe ist, dass wenn ich eine Eingabe mache z. B.:
    1. Zeile: a
    2. Zeile: b
    3. Zeile: c
    4. Zeile: Computer
    5. Zeile: r
    6. Zeile: Hallo

    Dann sollte es ja sortiert wieder ausgegeben werden, aber dies passiert nicht, sondern es geschieht folgender Fehler. Bei dem obigen Beispiel sind zwei Zeilen dabei, die länger sind. Der Fehler tritt bei diesen beiden Zeilen auf, denn die 4. Zeile ist in der "Ausgabe: Compualo".

    Wie kann dieser Fehler passieren ?



  • Schmeiß mal deinen Debugger an und find es raus. Achte mal darauf ob du auch genügend Speicher reservierst.



  • Also es muss in diesem Bereich sein, da hier die Werte übertragen werden auf den Pointer:

    while((len = getline(line, MAXLEN)) > 0)
        if(nlines >= maxlines || (p = alloc(len)) == NULL)
          return -1;
        else
        {
          len = strlen(line);
          line[len-1] = '\0'; /* Zeilentrenner entfernen */
          strcpy(p, line);
          lineptr[nlines++] = p;
        }
        return nlines;
    

    Der Fehler tritt auf, wenn die zweite längere Zeile eingelesen und der Speicher dafür allokiert wird:

    if(nlines >= maxlines || (p = alloc(len)) == NULL)
    

    Interessant dabei ist auch, dass dieser Fehler erst auftritt, wenn die zweite Eingabe eine bestimmte Länge hat.



  • Lass dir im Debugger die Werte der Variablen ausgeben, vielleicht kommst du dann drauf.



  • Ich hab da eine Idee.... nämlich bei der Schleife

    while((len = getline(line, MAXLEN)) > 0)
        if(nlines >= maxlines || (p = alloc(len)) == NULL)
          return -1;
        else
        {
          len = strlen(line);
          line[len-1] = '\0'; /* Zeilentrenner entfernen */
          strcpy(p, line);
          lineptr[nlines++] = p;
    

    allokiert er immer wieder den Speicher neu... wenn nun die zweite Eingabe kürzer ist, als die Erste, dann wird natürlich an einer früheren Stelle im Speicher angefangen wieder einzusetzen, wodurch die Ausgabe verfälscht wird.



  • Jetzt weiß ich woran es liegt. Dein lineptr stimmt nicht mit deiner Allokierung zusammen. Mach folgendes mit lineptr:

    ...
    char **lineptr;
    ...
    //Das sollte gleich am Anfang gemacht werden
    *lineptr = malloc(LINES * sizeof(char *));
    ...
    

    Und am Schluss deines Programms solltest du mit free() alles wieder freigeben, was du allokiert hast.



  • Wenn ich das in die main-Funktion einbaue, dann bekomme ich einen Speicheradressenfehler und zwar gleich am Anfang.

    int main(int argc, char* argv[])
    {
      char **lineptr = 0;
      int nlines;
      int c, ialloc, rc = 0;
      static char option = 0;
    
      *lineptr = malloc(LINES * sizeof(char *));
      while(--argc > 0 && (*++argv)[0] == '-')
    

    Ich habs hier gleich am Anfang eingebaut, so wie du gesagt hast 😉 - Vielleicht liegt der Fehler des Programms ganz woanders begraben 😕



  • Nein, aber ich hab einen Stern zuviel gemacht. Der Stern vor lineptr beim Allokieren gehört natürlich weg. Aja und den Parameter bei readlines() wirst du auch anpassen müssen.



  • int main(int argc, char* argv[])
    {
      char *lineptr;
      int nlines;
      int c, rc = 0;
      static char option = 0;
    
      lineptr = malloc(LINES * sizeof(char *));
      while(--argc > 0 && (*++argv)[0] == '-')
    

    Ich hab es jetzt so eingefügt, aber dennoch die falsche Ausgabe. Daran kann es also nicht liegen 😕



  • Wundert mich nicht. Ich hab doch gesagt, dass nur der Stern vor lineptr beim Allokieren falsch ist. Bei der Definition von lineptr gehören immer noch 2 * hin.


Anmelden zum Antworten