Segmentation Fault beim Listen-Iterator



  • #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct ListNode ListNode;
    
    struct ListNode {
    	void *data;
    	ListNode *next;
    };
    
    ListNode* listAddFirst(ListNode *, void *);
    void listDeleteAll(ListNode *);
    ListNode *listIterate(ListNode *head);
    
    int main(void) {
    	ListNode* head = NULL;
    	head = listAddFirst(head, (void *) "John");
    	head = listAddFirst(head, (void *) "Jane");
    	listIterate(head);
    	listIterate(head);
    	listIterate(head);
    	printf("%s\n", (const char *) listIterate(head)->data);
    	listDeleteAll(head);
    	return EXIT_SUCCESS;
    }
    
    ListNode* listAddFirst(ListNode *head, void *data) {
    	if (!head) {
    		ListNode *n = NULL;
    		n = malloc(sizeof(ListNode));
    		if (!n) {
    			perror("Error: cannot allocate heap memory\n");
    			exit(EXIT_FAILURE);		
    		}
    		n->data = data;
    		n->next = NULL;
    		return n;
    	} else {
    		ListNode *n = NULL;
    		n = malloc(sizeof(ListNode));
    		if (!n) {
    			perror("Error: cannot allocate heap memory\n");
    			exit(EXIT_FAILURE);		
    		}
    		n->data = data;
    		n->next = head;
    		return n;
    	}
    }
    
    void listDeleteAll(ListNode *head) {
    	if (!head) {
    		return;	
    	} else {
    		ListNode *tmp = head;
    		head = head->next;
    		free(tmp);
    		listDeleteAll(head);
    	}
    }
    
    ListNode *listIterate(ListNode *head) {
    	if (head) {
    		if (head->next) {		
    			static ListNode *tmp = NULL;
    			if (!tmp) {
    				tmp = head;
    			}
    			tmp = tmp->next;
    			return tmp;
    		} else {
    			return NULL;		
    		}
    	}
    	return NULL;
    }
    

    Passiert immer bei ungeraden listIterator()-Aufrufen. Eine lokale static-Variable hat ja den alten Wert von NULL nicht mehr nach der Initialisierung.
    Also müsste es bei jedem Aufruf klappen.



  • Kann es sein, dass du bei printf den nullzeiger dereferenzierst? Benutz doch mal den debugger.



  • Program received signal SIGSEGV, Segmentation fault.
    0x00000000004006b0 in main () at main.c:22
    22          printf("%s\n", (const char *) listIterate(head)->data);
    (gdb) b listIterate
    Breakpoint 1 at 0x4007cd: file main.c, line 63.
    (gdb) next
    
    Program terminated with signal SIGSEGV, Segmentation fault.
    The program no longer exists.
    


  • sag ich doch. also du schreibst 2 elemente in die liste, iterierst aber dreimal, das heißt ListIterate liefert nachher NULL zurück (weil tmp->next == NULL) und das dereferenzierst du dann in printf, weshalb das programm abbricht.



  • #ifdef DEBUG
    ListNode *listIterate(ListNode *head) {
        static ListNode *tmp = NULL;
        if (tmp == NULL) {
            tmp = head;
            return tmp;
        }
        /* tmp != NULL */
        if (tmp->next != NULL) {
            tmp = tmp->next;
            return tmp;
        }
        /* tmp->next == NULL */
        tmp = head;
        return tmp;
    }
    #endif
    

    Hab' nicht geblickt, warum es einen NULL-Pointer ergab. Habe es mir nochmal verbildlicht mit MS Paint und dann bin ich zu diesem Code gekommen. Jetzt klappt's! Zwar blicke ich immer noch nicht wie's zum NULL-Pointer kam beim vorherigen Programm, aber ist jetzt eh egal.



  • du hast in zeile 72 festgelegt, dass die funktion NULL zurückgeben soll, wenn du am ende der liste angekommen bist, was eben auf lange sicht passieren wird, da du nur 2 elemente angelegt hast, aber 3 mal iterierst.

    faktisch liefert ListIterate in Zeile 19 das Element mit "John" zurück und in Zeile 20 und 21 schon NULL und das dereferenzierst du dann in printf.

    mach dir mal die mühe, entsprechende ausgaben einzubauen, was wann zurück gegeben wird und welcher programmzweig gerade aufgerufen wird und du kannst das auch ohne debugger super nachvollziehen. oder du benutzt eben visual studio mit komfortablerer grafischer oberfläche. 😉


Anmelden zum Antworten