Thread: Static vs. Dynamic Allocation for a rolling dice function

  1. #1
    Registered User
    Join Date
    Mar 2022
    Posts
    3

    Static vs. Dynamic Allocation for a rolling dice function

    C beginner here, so bear with me.

    I have a function that does a yahtzee roll:

    Code:
    #include <stdlib.h>
    #define DIE_SIDES 6
    #define MAX_DICE_PER_ROLL 5
    
    
    typedef struct Roll {
        int   dice[MAX_DICE_PER_ROLL];
        int   num_dice;
    } Roll;
    
    
    /**
     * Roll n dice. If less than 6 die are
     * rolled, zeros out the remaining slots.
     */
    Roll* roll_dice(int num_dice) {
        static Roll roll;
        roll.num_dice = num_dice;
        for (int i = 0; i < MAX_DICE_PER_ROLL; i++) {
            if (i < num_dice) {
                // roll_die is declared else where and returns a
                // random number between 1-6.
                roll.dice[i] = roll_die();
            } else {
                // Zero out dice that are not rolled.
                roll.dice[i] = 0;
            }
        }
        return &roll;
    }
    A few questions about the code I've written:

    1. I am returning a pointer to Roll, as I understand this is best practice instead of returning the actual struct instance. Mostly this is because it allows the struct to add properties and other code that's using this will still compile. In my case it's really a matter of style/convention. True or false?

    2. Since I return a reference to the roll, I must either declare the roll static or allocate on the heap so that the reference returned refers to a memory location that is still valid past the enclosing function's execution lifetime. Both declaring this static and dynamically allocating on the heap seem to serve the same purpose here, so what's the difference exactly and what is most appropriate for this function? My guess is that if I have many rolls, static allocation is wasteful because the memory allocated for each roll lives as long as the program does, whereas dynamic allocation of that roll allows me to localize the memory usage and it can be reclaimed by the caller...is that right?

    3. Would it be better to have a dynamically allocated array of dice in the struct vs. padding it with zeros to represent n dice out of 5 that weren't rolled?

    Thanks for your patience.
    Last edited by acohen; 03-30-2022 at 01:52 PM.

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,378
    How about:
    Code:
    void roll_dice(Roll *roll) {
        for (int i = 0; i < MAX_DICE_PER_ROLL; i++) {
            if (i < roll->num_dice) {
                // roll_die is declared else where and returns a
                // random number between 1-6.
                roll->dice[i] = roll_die();
            } else {
                // Zero out dice that are not rolled.
                roll->dice[i] = 0;
            }
        }
    }
     
    int main() {
        Roll roll;
        roll.num_dice = 5;
        roll_dice(&roll);
        ...
    }
    A long time ago being crazy meant something. - Charles Manson

  3. #3
    Registered User
    Join Date
    Feb 2022
    Location
    Canada, PEI
    Posts
    64
    I have a simple rule(reminder) when I start considering dynamic allocation: Never use dynamic allocation unless you absolutely have to.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,121
    > My guess is that if I have many rolls, static allocation is wasteful because the memory allocated for each roll lives as long as the program does
    Well this is where it breaks down, there is ever only one copy of your roll.

    This for example will give you surprises.
    Code:
    Roll *player1 = roll_dice(4);
    Roll *player2 = roll_dice(3);
    What you thought you had in player1 will now be the same as player2.

    You can rescue the situation by copying the pointer.
    Code:
    Roll player1 = *roll_dice(4);
    Roll player2 = *roll_dice(3);
    Or do as john.c suggests in post #2

    > 3. Would it be better to have a dynamically allocated array of dice in the struct vs. padding it with zeros to represent n dice out of 5 that weren't rolled?
    Given the low upper limit, it's fine as it is.

    In fact, dynamic allocation would likely waste more memory in this case.
    Each allocated block has several words of overhead used by the allocator to track what's used and what's free.


    You don't need to pad with zeros, as you already have a count of the number of dice rolls within the struct.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Mar 2022
    Posts
    3
    Well this is where it breaks down, there is ever only one copy of your roll.
    this is because of the static allocation, right? Because the static allocation means there's one copy of the data during the entire lifetime of the program?

    Is John's solution, where the function returns void and the roll is a pointer outside the function more idiomatic C? It's funny coming from a non-C, an OO and/or a functional background it's weird to call functions that return void yet mutate values. I understand this is how it's often done in languages like Go/C/C++ and it's for a reason, but it is hard to get used to.
    Last edited by acohen; 03-31-2022 at 01:59 AM.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,121
    > this is because of the static allocation, right? Because the static allocation means there's one copy of the data during the entire lifetime of the program?
    Yes and yes.

    > Is John's solution, where the function returns void and the roll is a pointer outside the function more idiomatic C?
    Pretty much wherever you need to modify a struct.

    Is it any less weird in C++, just because 'this' is effectively hidden from you.
    Code:
    typedef struct Roll {
        int   dice[MAX_DICE_PER_ROLL];
        int   num_dice;
    } Roll;
    void roll_dice(Roll *roll, int num_dice) {
        roll->num_dice = num_dice;
        for( int i = 0 ; i < roll->num_dice ; i++ ) {
            roll->dice[i] = roll_die();
        }
    }
      
    int main() {
        Roll roll;
        roll_dice(&roll,5);
    }
    vs
    Code:
    class Roll {
        int   m_dice[MAX_DICE_PER_ROLL];
        int   m_num_dice;
    public:
        void roll_dice(int num_dice);
    };
    
    void Roll::roll_dice(int num_dice) {
        m_num_dice = num_dice;
        for( int i = 0 ; i < m_num_dice ; i++ ) {
            m_dice[i] = roll_die();
        }
    }
      
    int main() {
        Roll roll;
        roll.roll_dice(5);
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Dec 2017
    Posts
    1,378
    Alternatively, you could just return the struct. With optimizations this will be turned into something similar to passing in a pointer to the struct (i.e., a pointer to the caller's struct will be passed in "under the hood").
    Code:
    Roll roll_dice(int num_dice) {
        Roll roll;
        roll.num_dice = num_dice;
        for (int i = 0; i < MAX_DICE_PER_ROLL; i++)
            roll.dice[i] = i < num_dice ? rand() % DIE_SIDES + 1 : 0;
        return roll;
    }
     
    int main() {
        Roll roll = roll_dice(5);
        ...
    }
    A long time ago being crazy meant something. - Charles Manson

  8. #8
    Registered User
    Join Date
    Mar 2022
    Posts
    3
    Is it any less weird in C++, just because 'this' is effectively hidden from you.
    I don't write C++, so I can't say. But yes I see that much is hidden from you when you write languages that are written on top of C.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. rolling a two dice
    By amirul m nasir in forum C Programming
    Replies: 4
    Last Post: 09-10-2011, 05:59 PM
  2. dice rolling in c
    By ceddsoboss in forum C Programming
    Replies: 3
    Last Post: 11-06-2010, 02:44 PM
  3. Dice Rolling Program help
    By courtesan in forum C Programming
    Replies: 3
    Last Post: 08-17-2005, 03:14 PM
  4. Rolling Dice
    By pianorain in forum A Brief History of Cprogramming.com
    Replies: 12
    Last Post: 03-22-2005, 07:07 AM
  5. rolling dice problem
    By egomaster69 in forum C Programming
    Replies: 7
    Last Post: 10-19-2004, 06:14 PM

Tags for this Thread