Home > Mobile >  Return a pointer from a function, then free the pointer
Return a pointer from a function, then free the pointer

Time:12-01

Im trying to process multiple names from the command line argv[] and then add or remove said names if they were prefaced by a ' ' or '-'. IE bill ted -ted would add bill and ted then remove ted. I can add names to this list no problem but my removeNode() function call results in a segmentation fault. In my main() when I go to process names to be removed I set char * name to be equal to the return pointer of removeNode(), which should be the string from the node being freed. What would the correct way to return this pointer be so I can remove the name I reference from the command line? Ive also included my insert function.

int insert(struct node ** head, char * name) {
    struct node * newNode = (struct node * ) malloc(sizeof(struct node));
    newNode -> data = name;
    newNode -> next = NULL;
    struct node * current = * head;
    if ( * head == NULL) {
        * head = newNode;
        return 1;
    }
    while (current -> next != NULL) {
        current = current -> next;
    }
    current -> next = newNode;
    return 1;
}

char * removeNode(struct node ** head, char * name) {
    struct node * current = * head;
    struct node * previous;

    if (current == NULL) {
        return "error0";
    }

    if (strcmp(current -> data, name) == 0) {
        char * data = current -> data;
        * head = current -> next;
        free(current);
        printf("Removed %s \n", name);
        return data;
    }
    while (current != NULL) {
        previous = current;
        current = current -> next;
        if (strcmp(current -> data, name) == 0) {
            char * data = current -> data;
            previous -> next = current -> next;
            free(current);
            printf("Removed %s \n", name);
            return data;
        }
    }
    return "error0";
}

int main(int argc, char * argv[]) {
    printf("Author : Torin Costales \n");
    struct node * head = NULL;
    for (int x = 1; x < argc; x  ) {
        if (argv[x][0] == ' ') {
            char * name = malloc((strlen(argv[x]   1)   1));
            if (name == NULL) return EXIT_FAILURE;
            strcpy(name, argv[x]);
            printf("adding %s \n", name);
            insert( & head, name);
            printf("List: ");
            printList( & head);
        } else if (argv[x][0] == '-') {
            printf("removing %s \n", argv[x]   1);
            char * name = removeNode( & head, argv[x]   1);
            free(name);
            printList( & head);

        }
    }
}

CodePudding user response:

The problem leading the to fault is that you were using

strcpy(name, argv[x]);

where you should have been using

strcpy(name, argv[x]   1);

This caused a string produced by "error0" to be returned when trying to remove ted since the list contained bill and ted.


Fixed and cleaned up:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct node {
   char        *data;
   struct node *next;
} node;

void printList(struct node *node) {  // Don't need a pointer to a pointer.
    printf("List:");
    for (; node; node = node->next)
        printf(" %s", node->data);
        
    printf("\n");
}

// Returns 0 on success.
// Returns -1 and sets errno on error.
int append(struct node **node_pp, char *name) {  // Better name
   while (*node_pp)
      node_pp = &( (*node_pp)->next );

    struct node *newNode = malloc(sizeof(struct node));
    if (!newNode)
        return -1;

    newNode->data = name;
    newNode->next = NULL;

    *node_pp = newNode;
    return 0;
}

// Returns NULL if not found.
char *removeNode(struct node **node_pp, const char *name) {  // Added `const`
    for (; *node_pp; next_p = &( (*node_pp)->next )) {
        if (strcmp((*node_pp) -> data, name) == 0) {
            struct node * oldNode = *next_p;
            *node_pp = oldNode->next;

            char *data = oldNode->data;
            free(oldNode);
            return data;
        }
    }

    return NULL;  // NULL is a far better value to return on error.
}

int main(int argc, char * argv[]) {
    struct node *head = NULL;
    for (int x = 1; x < argc; x  ) {
        if (argv[x][0] == ' ') {
            char *name = strdup(argv[x]   1);  // Simpler
            if (name == NULL) {
                perror("Can't allocate memory");  // Error message is good
                exit(EXIT_FAILURE);
            }

            printf("Appending %s.\n", name);
            if (append(&head, name) < 0) {
                perror("Can't append node to list");
                exit(EXIT_FAILURE);
            }
        } else if (argv[x][0] == '-') {
            const char *name_to_find = argv[x]   1;
            printf("Removing %s.\n", name_to_find);
            char *name = removeNode(&head, name_to_find);
            if (name) { // Do check if it was found!
               free(name);
            } else {
                printf("%s not found\n", name_to_find);
            }
        }

        printList(head);
        printf("\n");
    }
}

Output for foo bar -baz -foo:

Appending foo.
List: foo

Appending bar.
List: foo bar

Removing baz.
baz not found
List: foo bar

Removing foo.
List: bar
  • Related