Pointer Zuweisung und SIGSEGV Problem



  • Hi,
    Ich habe ein Problem mit einer Uebergabe eines void Pointers an eine Funktion.
    Die Idee ist einen Pointer auf einen Pointer eines Elements zu uebergeben fuer jeweils "first" und "last". Pointer auf Pointer, weil ja die gerufene Funktion Speicher allokiert und deren Adressen veraendert.

    Das Problem ist, der Code kompiliert auf meinem Debian per gcc, allerdings nicht unter Cygwin per "cygwin-gcc". Ich bekomme Signal 11 / SIGSEGV fuer

    *last = tmp;
    

    Das Problem scheint wohl zu sein, dass der Code auf meiner Linux Maschine nur zufaellig fehlerfrei laeuft und ich evtl eine Eigenschaft benutze, die nicht garantiert ist. Nur was ist das Problem?!

    Nja, mir ist klar, dass ich hier eigentlich einen Pointer habe, den ich letztlich gewaltsam ueber Umwege ueber eine void* Geschichte, auf einen Pointer-auf-Pointer caste. Aber void** macht imho nicht wirklich Sinn und schliesslich brauche ich ja einen Pointer auf das was ich veraendern will (was ja schon ein Pointer ist), also etwas mit "**", oder doch nicht? Woran liegt das?

    Der Code:

    // function call
    int main(){
      element* first = NULL;
      element* last = first;
    
      // alloc
      puts("alloc");
      alloclist( (void*) &first, (void*) &last);
      printf("\n");
    //...
    }
    
    /*
      function: allocate elements for a list
    //*/
    void alloclist(void* start, void* end)
    {
      element **first = (element**) start;
      element **last = (element**) last;
      element *tmp = NULL;
    
      unsigned int idx=0;
      for(idx = 0; idx < LIST_SIZE; ++idx){ 
        if(NULL == (tmp = malloc(sizeof(*tmp)))){
          perror("malloc failed!");
          exit(EXIT_FAILURE);
        }
    
        // limit to values up to 100
        tmp->value = (random() % 100);
        if(0 == idx){
          tmp->prev = NULL;
          tmp->next = NULL;
          *first = tmp;
        }else{
          tmp->prev = *last;
          tmp->next = NULL;
          (*last)->next = tmp;
        }
        *last = tmp; // SIGSEGV !?
        tmp = NULL;
      }
      tmp = NULL;
    }
    


  • void * ist nicht gleich void **.

    int main()
    {
        element* first = 0;
        element* last = first;
    
        // alloc
        puts("alloc");
        alloclist(&first, &last);
        printf("\n");
    }
    
    /*
      function: allocate elements for a list
    //*/
    void alloclist(element** start, element** end)
    {
        element **first = (element**)start;
        element **last = (element**) last;
        element *tmp = 0;
    
        unsigned int idx=0;
        for(idx = 0; idx < LIST_SIZE; ++idx)
        {
            tmp = malloc(sizeof(*tmp));
            if (!tmp)
            {
                perror("malloc failed!");
                // hier könnte ein speicherleck entstehen, wenn malloc
                // schon erfolgeich speicher angefordert hat, aber in späteren
                // durchläufen 0 zurückgibt
                exit(EXIT_FAILURE);
            }
    
            // limit to values up to 100
            tmp->value = (random() % 100);
            if(idx == 0)
            {
                tmp->prev = 0;
                tmp->next = 0;
                *first = tmp;
            }
            else
            {
                tmp->prev = *last;
                tmp->next = 0;
                (*last)->next = tmp;
            }
            *last = tmp;
            tmp = 0;
        }
        tmp = 0;
        // unnötig, funktion ist eh zuende
    }
    

    ich würde es so machen

    int main()
    {
        element *first, *last;
        alloc(&first, &last, 100);
        // hier wieder freigeben
    }
    bool alloc(element **first, element **last, unsigned size)
    {
        element *Anker = malloc(sizeof(element));
        Anker->value = random() % 100;
        Anker->last = 0;
        Anker->next = 0;
        if (!Anker)
        {
            // Fehler!
            return false;
        }
        *last = Anker;
        for (unsigned i = 0; i < size; ++i)
        {
            element *temp = malloc(sizeof(element));
            if (!temp)
            {
                // rückwärts alles wieder löschen
                return false;
            }
            temp->value = random() % 100;
            temp->last = 0;
            temp->next = Anker;
            Anker->last = temp;
            Anker = temp;
        }
        *first = Anker;
        return true;
    }
    


  • Hi,
    Danke fuer den Hinweis - im eigentlichen Prg lasse ich einen Zaehler mitlaufen der die allokierten Elemente zaehlt und gegen den dann in einer "freelist()" Funktion gefreet wird. Der Unterschied ist, dass ich einfach statt "exit()" zu rufen auch einen return mache - gefreet wird immer nur das was auch da ist.

    Die Sache mit dem Anker ist einfach nur ein anderer Ansatz - aber nicht die Loesung. Die Loesung ist viel banaler, nachdem ich nun schon fast den Glauben in die Zeigerarithmetik verloren hab, hab ich per GDB herausgefunden, dass die Zuweisung auf *first funktioniert, aber die auf *last nicht.

    Dann hab ich meine Brille aufgesetzt:

    element **last = (element**) last;
    

    Nja, diese zugegebenermassen sinnfreie Zeile sollte eigentlich folgendermassen heissen, dann klappts auch mit der Zuweisung weiter unten:

    element **last = (element**) end;
    

    Danke trotzdem, bin wenigstens nich der einzigste der's nich erkannt hat! 🤡


Anmelden zum Antworten