Ryan
Ryan

Reputation: 85

How can I add items into a struct without creating variables

I am using a struct to store a string and an integer like so:

struct movement {
    char *direction;
    int steps;
};

I can add items into the struct by doing this

struct movement m1= { "right",20 };
struct movement m2= { "left" ,10 };

The end result I am trying to achieve is to collect user inputs (e.g. "right 20"), and store it in the struct. How can I store an unknown number of user inputs into the struct without the use of variables (m1, m2 etc) since I will not know how many items there will be at the end.

Upvotes: 1

Views: 788

Answers (3)

RoadRunner
RoadRunner

Reputation: 26315

Use a linked list. It is a recursive data structure which would be great for what you want.

Here is some example code I wrote a while ago that might help:

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

/* basic linked list structure */
typedef struct node node_t;

struct node {
    char *direction;
    int steps;
    node_t *next;
};

/* pointers to the head and tail of the list */
typedef struct {
    node_t *head;
    node_t *foot;
} list_t;

list_t *initialize_list(void);
list_t *insert_nodes(list_t *list, char *direction, int steps);
void free_list(list_t *list);
node_t *generate_node(void);
void print_list(list_t *list);
void exit_if_null(void *ptr, const char *msg);

int
main(int argc, char const *argv[]) {
    list_t *list;

    /* empty list created */
    list = initialize_list();

    /* inserting information one a time */
    list = insert_nodes(list, "right", 20);
    list = insert_nodes(list, "left", 10);

    print_list(list);

    /* freeing list at the end */
    free_list(list);
    list = NULL;

    return 0;
}

/* function to insert information into a node */
list_t
*insert_nodes(list_t *list, char *direction, int steps) {

    /* called generate_node() to create a new node */
    node_t *new;
    new = generate_node();

    /* puts steps information into node */
    new->steps = steps;

    /* allocates space for direction string */
    /* this is needed because *direction is a pointer */
    new->direction = malloc(strlen(direction)+1);

    /* copies direction info into node */
    strcpy(new->direction, direction);

    /* inserting information at the tail of the list */
    new->next = NULL;

    if (list->foot == NULL) {
        /* first insertion into list */
        list->head = list->foot = new;
    } else {
        list->foot->next = new;
        list->foot = new;
    }

    /* returns modified list */
    return list;
}

.* function which generates new nodes */
node_t
*generate_node(void) {
    node_t *newnode;

    /* create space for new node */
    newnode = malloc(sizeof(*newnode));
    exit_if_null(newnode, "Allocation");

    /* initialize node info to nothing */
    newnode->direction = NULL;
    newnode->steps = 0;

    return newnode;
}

/* creates the empty linked list */
list_t 
*initialize_list(void) {
    list_t *list;

    create space for list */
    list = malloc(sizeof(*list));
    exit_if_null(list, "Allocation");

    /* set pointers to NULL */
    /* We don't want them pointing at anything yet */
    list->head = list->foot = NULL;

    return list;
}

/* function which prints entire list */
void
print_list(list_t *list) {

    /* start at the head of the list */
    node_t *curr = list->head;

    while (curr) {
        printf("%s %d\n", curr->direction, curr->steps);

        /* steps through the list */
        curr = curr->next;
    }
}

/* function which frees nodes */
void
free_list(list_t *list) {
    node_t *curr, *prev;

    /* start at beginning of list */
    curr = list->head;

    /* frees nodes one at a time */
    while(curr) {
        prev = curr;
        curr = curr->next;
        free(prev);
    }

    /* frees entire list */
    free(list);
}

/* function which checks malloc(), and whether enough space was allocated */
void
exit_if_null(void *ptr, const char *msg) {
    if (!ptr) {
        printf("Unexpected null pointer: %s\n", msg);
        exit(EXIT_FAILURE);
    }
}

Upvotes: 2

unwind
unwind

Reputation: 399949

It doesn't sound as if you really want to "store values into the struct", instead you want to store a sequence of independent struct instances; one for each user input.

The three most basic ways of doing this are:

  • An array, whose size you select at compile-time. It shouldn't be too hard to make it "large enough" for reasonable input
  • An array whose size you set (and then grow) at run-time
  • A linked list of structure instances

Which one to prefer depends on which you think is simplest. If at all possible, a static appeoach is always simplest. You can easily have something like

struct movement movements[10000];

at the global level, this will only cost perhaps 120 KB on a 64-bit system. Note though that this doesn't include memory for the direction strings; if those are always chosen from "right" and "left" (and perhaps "up"/"down" too) you could represent it as an enum instead:

enum direction { DIRECTION_LEFT = 0, DIRECTION_RIGHT, DIRECTION_UP, DIRECTION_DOWN };

This will make the structure "self-contained" and (on 64-bit systems) smaller since the enumeration will be smaller than a pointer.

Dynamically growing an array using realloc() isn't too hard, you could look that up easily as its often used.

Upvotes: 4

thepace
thepace

Reputation: 2221

Use a LinkedList to store an indefinite number of movements. For each movement, create a node in the linked list and update the next pointer.

struct node {
  struct movement m;
  node* next;
}

Upvotes: -1

Related Questions