cpointer-to-memberpointer-to-array

Pointers to Pointers to Avoid Duplicate Code?


I am new to learning about C, so as an exercise I attempted to create a text-based card game where each person/CPU places down a random card at the top of their deck, and the person with the higher card will take the card and add it to their deck. During a tie, both cards would be discarded. When a person reaches zero cards, in this game they will lose. It is basically a simplified version of the war card game.

I came across a problem soon after I started developing. Here is the code I had until I ran across my error:

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

enum suit {
    heart = 0,
    spade = 1,
    club = 2,
    diamond = 3
};

struct card {
    enum suit current_card_suit;
    int card_num;
    int is_red_card;
};

int cardDeckSize = 0;

int numOpponentCardsLeft;
int numPlayerCardsLeft;

void deal_cards_to_player (struct card * pPlayerCards, int cardDeckSize);
void deal_cards_to_cpu (struct card * pCpuCards, int cardDeckSize);

int get_random_number_above_zero(int max);
void waitFor(unsigned int seconds);

void flush_input() {
    int ch;
    while ((ch = getchar()) != '\n' && ch != EOF)
    continue;
}

int main (int argc, char **argv) {
    //Get Random number sequence for later
    srand(time(NULL));

    int random_suit;
    char userInput[10];
    //Get deck size for war game
    int invalidSize = 1;

    while (invalidSize == 1) {
        printf("\nEnter the amount of cards you would like to be dealed to each player for the war game (between 0 and 100)\n");

        fgets(userInput, 9, stdin);

        if(sscanf(userInput, "%i", &cardDeckSize) != 1) {
            printf("\nPlease enter an integer. You will have to enter the number twice because you did not follow directions.\n");
            flush_input();
            continue;
        }
        if(cardDeckSize > 0 && cardDeckSize < 101) {
            invalidSize = 0;
            break;
        } else {
            printf("\nPlease type a number between 0 and 100. You will have to enter the number twice because you did not follow directions.\n");
            flush_input();
            continue;
        }
    }
    printf("\nPress enter once more to proceed...");
    flush_input();

    //Create arrays to hold the cards of the player and CPU
    struct card *pPlayerCards;
    struct card *pCpuCards;

    pPlayerCards = (struct card *) malloc (cardDeckSize * sizeof(struct card));
    pCpuCards = (struct card *) malloc (cardDeckSize * sizeof(struct card));

    //You will see duplication in the two functions called below, but I could not figure out how to remove it; it works for now
    deal_cards_to_player(pPlayerCards, cardDeckSize);
    deal_cards_to_cpu(pCpuCards, cardDeckSize);

    printf("\nWow! My hand is SO tired of dealing all those cards.  Let's play!\n\n");

    struct card **pCurrentSideCards;
    //"parse" the properties of each card...and right after show the game round results to the player
    /* I will have to change "i < cardDeckSize" eventually becuase the size of the deck will not necessarily determine
     the # of rounds; I'll get through one round first before worrying about this */
    for(int i = 0; i < cardDeckSize; i++) { //Loop through each round

        //Countdown for the player
        printf("3, ");
        waitFor(1);
        printf("2, ");
        waitFor(1);
        printf("1, ");
        waitFor(1);
        printf("GO, GO, GO!!!");
        waitFor(1);

        char playerCardSuit[6];
        char cpuCardSuit[6];

        char playerStringCardNum[5];
        char cpuStringCardNum[5];

        char playerCardColor[5];
        char cpuCardColor[5];

        //Determine card terms set for each player
        for (int i = 0; i < 2; i++) {
            /* To eliminate duplication, based on the current iteration I tried to
            create a pointer that points to a pointer to the array of card structures
            for each player */
            if(i == 0) {
                //Start with "parsing" the player cards, then the CPU cards
                pCurrentSideCards = &pPlayerCards;
            } else {
                pCurrentSideCards = &pCpuCards;
            }

            char cardSuit[6];

            //EXPLANATION:
            /* Accessing the card properties: I first tried to dereference the pointer
            to find a pointer to the card deck structure array.  Then I accessed
            the correct card member in the array with "+i".  I finally tried
            to access the value with the "->" symbol, which dereferences again
 before accessing the member
            */
            switch ( ((*pCurrentSideCards)+i)->current_card_suit) {
                case heart:
                strcpy(cardSuit, "hearts");
                break;
                case spade:
                strcpy(cardSuit, "spades");
                break;
                case club:
                strcpy(cardSuit, "clubs");
                break;
                case diamond:
                strcpy(cardSuit, "diamonds");
                break;
                default:
                printf("\nThere was a fatal error determining the card suit of some dealt out cards.\n");
            }
            if(i == 0) { //If i = 0 we are working with the player cards, otherwise we are working with the CPU cards
                strcpy(playerCardSuit, cardSuit);
            } else {
                strcpy(cpuCardSuit, cardSuit);
            }

            char stringCardNum[5];


            switch ( ((*pCurrentSideCards)+i) ->card_num) {
                case 1:
                strcpy(stringCardNum, "ace");
                break;
                case 11:
                strcpy(stringCardNum, "jack");
                break;
                case 12:
                strcpy(stringCardNum, "queen");
                break;
                case 13:
                strcpy(stringCardNum, "king");
                break;

                default: {
                    int cardAsNumber = ((*pCurrentSideCards)+i) -> card_num;
                    char cardAsString[5];
                    sprintf(cardAsString, "%i", cardAsNumber);
                    strcpy(stringCardNum,cardAsString);
                }
            }
            if(i == 0) {
                strcpy(playerStringCardNum, stringCardNum);
            } else {
                strcpy(cpuStringCardNum, stringCardNum);
            }

            char cardColor[5];


            switch ( ((*pCurrentSideCards)+i )->is_red_card) {
                case 0:
                strcpy(cardColor, "black");
                break;
                case 1:
                strcpy(cardColor, "red");
            }

            if(i == 0) {
                strcpy(playerCardColor, cardColor);
            } else {
                strcpy(cpuCardColor, cardColor);
            }
        }
            //The error comes right here before printing out the results somewhere
            printf("                     RESULTS!!! (DUN DUN, DUN)");
            printf("\n       Card Color        Card Number         Card Suit");
            printf("\n YOU: A %s                 %s          of      %s     ", playerCardColor, playerStringCardNum, playerCardSuit);
            printf("\n CPU:  A %s                 %s          of      %s    " , cpuCardColor, cpuStringCardNum, cpuCardSuit);
    }

    free(pPlayerCards);
    return 0;
}
void deal_cards_to_cpu(struct card *pCpuCards, int cardsToDeal) {
    printf("\nPlease Wait...We are giving your opponent a good hand\n");
    waitFor(1);
    int numbersDealedSinceResponse = 0;
    float randNumsNeeded = 3 * cardsToDeal; //3 values to assign per card in the deck
    float totalNumsDealed = 0.0;

    for (int i = 0; i < cardsToDeal; i++) {
        //Get suit for card
        int suitNum = get_random_number_above_zero(4);
        //Get card number
        int cardNum = get_random_number_above_zero(13);
        //Tell if the card is red
        int isRed = (get_random_number_above_zero(2)) - 1;

        //Find the current card and assign the correct values
        (pCpuCards+i)->current_card_suit = suitNum;
        (pCpuCards+i)->card_num = cardNum;
        (pCpuCards+i)->is_red_card = isRed;
        printf("\n\nFor debugging purposes only, here are the CPU cards generated");
        printf("\nSuit Num: %i", suitNum);
        printf("\nCardNum: %i", cardNum);
        printf("\nIs it red: %i\n", isRed);
        if(numbersDealedSinceResponse > 6) {
            //delay and then change seed; see comment in deal_cards_to_player() for explanation
            waitFor(1);
            srand(time(NULL));
        }
        if(numbersDealedSinceResponse == 12) {
            //After 12 cards, give the user feedback on our progress by % done
            float percent_done = 100 * (totalNumsDealed / randNumsNeeded);;
            int percent_rounded = (int) percent_done;
            printf("Please Wait...We are giving your opponent a good hand (%i%%)\n", percent_rounded);
            numbersDealedSinceResponse = 0;
            totalNumsDealed += 12;
        }
        numbersDealedSinceResponse+=3;
    }
}
void deal_cards_to_player(struct card *pPlayerCard, int cardsToDeal) {
    printf("\nPlease Wait...We are dealing out your cards\n");
    waitFor(1);
    int numbersDealedSinceResponse = 0;
    float randNumsNeeded = 3 * cardsToDeal; //You need three random values shown in the struct for each card
    float totalNumsDealed = 0.0;

    for (int i = 0; i < cardsToDeal; i++) {
        //Get suit for card
        int suitNum = get_random_number_above_zero(4);
        //Get card number
        int cardNum = get_random_number_above_zero(13);
        //Tell if the card is red
        int isRed = (get_random_number_above_zero(2)) - 1;
        //Assign the values after getting the current card in the array
        (pPlayerCard+i)->current_card_suit = suitNum;
        (pPlayerCard+i)->card_num = cardNum;
        (pPlayerCard+i)->is_red_card = isRed;
        printf("\n\nFor debugging purposes only, here are the player cards generated:");
        printf("\nSuit Num: %i", suitNum);
        printf("\nCardNum: %i", cardNum);
        printf("\nIs it red: %i", isRed);
        if(numbersDealedSinceResponse > 6) {


        /* In order for the random numbers to stay unique and not be
        generated in a pattern, wait for one second and then call srand(time(NULL));
to change the seed again based on time every 6 numbers */
                waitFor(1);
                srand(time(NULL));
            }
            if(numbersDealedSinceResponse == 12) {
                //Every 12 numbers provide a response showing the percent completed
                float percent_done = 100 * (totalNumsDealed / randNumsNeeded);;
                int percent_rounded = (int) percent_done;
                printf("Please Wait...We are dealing out your cards (%i%%)\n", percent_rounded);
                numbersDealedSinceResponse = 0;
                totalNumsDealed += 12;
            }
            numbersDealedSinceResponse+=3;
    }
}

int get_random_number_above_zero(int max_num) {
    int randomNumber;
    randomNumber = (rand() % max_num) + 1;
    return randomNumber;
}

void waitFor(unsigned int seconds) {
    unsigned int stopTime = time(0) + seconds;
    while (time(0) < stopTime); //it will wait until the calculated stop time
}

(I apologize for the code dump; I wanted to make sure it was possible to reproduce the problem)

The Problem in the Code

I have tested the code that assigns random card properties to each deck of cards, and have found the values assigned to be ok. I attempted to avoid creating duplicate code by basically looping two times when determining the card strings, and I tried to create a pointer to the pointer to the structure of cards. Here is a test run example of what happens:

Enter the amount of cards you would like to be sealed to each player
for the war game (between 0 and 100)

    50

    Press enter once more to proceed...

    Please Wait...We are dealing out your cards


    For debugging purposes only, here are the player cards generated:
    Suit Num: 2
    CardNum: 3
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 12
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 2
    CardNum: 11
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 11
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 1
    CardNum: 13
    Is it red: 1
    Please Wait...We are dealing out your cards (0%)


    For debugging purposes only, here are the player cards generated:
    Suit Num: 4
    CardNum: 4
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 2
    CardNum: 13
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 2
    CardNum: 2
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 8
    Is it red: 1
    Please Wait...We are dealing out your cards (8%)


    For debugging purposes only, here are the player cards generated:
    Suit Num: 2
    CardNum: 12
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 12
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 1
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 1
    CardNum: 3
    Is it red: 0
    Please Wait...We are dealing out your cards (16%)


    For debugging purposes only, here are the player cards generated:
    Suit Num: 4
    CardNum: 7
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 4
    CardNum: 8
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 10
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 1
    Is it red: 0
    Please Wait...We are dealing out your cards (24%)


    For debugging purposes only, here are the player cards generated:
    Suit Num: 2
    CardNum: 5
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 4
    CardNum: 4
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 9
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 1
    CardNum: 9
    Is it red: 1
    Please Wait...We are dealing out your cards (32%)


    For debugging purposes only, here are the player cards generated:
    Suit Num: 4
    CardNum: 13
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 1
    CardNum: 13
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 5
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 4
    Is it red: 1
    Please Wait...We are dealing out your cards (40%)


    For debugging purposes only, here are the player cards generated:
    Suit Num: 2
    CardNum: 8
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 2
    CardNum: 9
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 1
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 1
    CardNum: 12
    Is it red: 0
    Please Wait...We are dealing out your cards (48%)


    For debugging purposes only, here are the player cards generated:
    Suit Num: 4
    CardNum: 3
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 5
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 13
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 10
    Is it red: 0
    Please Wait...We are dealing out your cards (56%)


    For debugging purposes only, here are the player cards generated:
    Suit Num: 2
    CardNum: 1
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 4
    CardNum: 1
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 9
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 1
    CardNum: 5
    Is it red: 1
    Please Wait...We are dealing out your cards (64%)


    For debugging purposes only, here are the player cards generated:
    Suit Num: 4
    CardNum: 9
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 1
    CardNum: 10
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 5
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 13
    Is it red: 1
    Please Wait...We are dealing out your cards (72%)


    For debugging purposes only, here are the player cards generated:
    Suit Num: 2
    CardNum: 4
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 2
    CardNum: 6
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 4
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 1
    CardNum: 8
    Is it red: 0
    Please Wait...We are dealing out your cards (80%)


    For debugging purposes only, here are the player cards generated:
    Suit Num: 4
    CardNum: 12
    Is it red: 0

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 2
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 13
    Is it red: 1

    For debugging purposes only, here are the player cards generated:
    Suit Num: 3
    CardNum: 6
    Is it red: 0
    Please Wait...We are dealing out your cards (88%)


    For debugging purposes only, here are the player cards generated:
    Suit Num: 2
    CardNum: 10
    Is it red: 1
    Please Wait...We are giving your opponent a good hand


    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 11
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 3
    CardNum: 9
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 1
    CardNum: 12
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 13
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 5
    Is it red: 1
    Please Wait...We are giving your opponent a good hand (0%)


    For debugging purposes only, here are the CPU cards generated
    Suit Num: 3
    CardNum: 9
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 3
    CardNum: 13
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 11
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 2
    CardNum: 13
    Is it red: 0
    Please Wait...We are giving your opponent a good hand (8%)


    For debugging purposes only, here are the CPU cards generated
    Suit Num: 1
    CardNum: 4
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 9
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 10
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 11
    Is it red: 0
    Please Wait...We are giving your opponent a good hand (16%)


    For debugging purposes only, here are the CPU cards generated
    Suit Num: 3
    CardNum: 2
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 1
    CardNum: 5
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 6
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 2
    CardNum: 6
    Is it red: 0
    Please Wait...We are giving your opponent a good hand (24%)


    For debugging purposes only, here are the CPU cards generated
    Suit Num: 1
    CardNum: 10
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 2
    CardNum: 1
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 5
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 1
    Is it red: 1
    Please Wait...We are giving your opponent a good hand (32%)


    For debugging purposes only, here are the CPU cards generated
    Suit Num: 3
    CardNum: 5
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 3
    CardNum: 10
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 1
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 2
    CardNum: 9
    Is it red: 1
    Please Wait...We are giving your opponent a good hand (40%)


    For debugging purposes only, here are the CPU cards generated
    Suit Num: 1
    CardNum: 13
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 6
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 10
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 7
    Is it red: 0
    Please Wait...We are giving your opponent a good hand (48%)


    For debugging purposes only, here are the CPU cards generated
    Suit Num: 3
    CardNum: 11
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 1
    CardNum: 2
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 9
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 2
    CardNum: 2
    Is it red: 0
    Please Wait...We are giving your opponent a good hand (56%)


    For debugging purposes only, here are the CPU cards generated
    Suit Num: 1
    CardNum: 6
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 2
    CardNum: 11
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 5
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 10
    Is it red: 1
    Please Wait...We are giving your opponent a good hand (64%)


    For debugging purposes only, here are the CPU cards generated
    Suit Num: 3
    CardNum: 1
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 3
    CardNum: 7
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 1
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 2
    CardNum: 5
    Is it red: 1
    Please Wait...We are giving your opponent a good hand (72%)


    For debugging purposes only, here are the CPU cards generated
    Suit Num: 1
    CardNum: 12
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 3
    CardNum: 3
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 13
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 3
    Is it red: 0
    Please Wait...We are giving your opponent a good hand (80%)


    For debugging purposes only, here are the CPU cards generated
    Suit Num: 3
    CardNum: 7
    Is it red: 0

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 4
    CardNum: 12
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 1
    CardNum: 9
    Is it red: 1

    For debugging purposes only, here are the CPU cards generated
    Suit Num: 2
    CardNum: 11
    Is it red: 0
    Please Wait...We are giving your opponent a good hand (88%)


    For debugging purposes only, here are the CPU cards generated
    Suit Num: 1
    CardNum: 2
    Is it red: 1

    Wow! My hand is SO tired of dealing all those cards.  Let's play!

        3, 2, 1, GO, GO, GO!!!

[PROGRAM STOPS UNEXPECTEDLY BEFORE PRINTING OUT RESULTS]

Abort trap: 6

Leading me to believe I am accessing memory I do not own when I tried to convert the randomly generated numbers into words. I think my problem happens when I try to create my pointer that points to the pointer to the array of the card structure and decide here:

struct card **pCurrentSideCards

And when I decide based on the for loop iteration:

 if(i == 0) {
    pCurrentSideCards = &pPlayerCards;
 } else {
    pCurrentSideCards = &pCpuCards;
 }

Finally, when I try to access the values with the switch statements

 switch ( ((*pCurrentSideCards)+i)->current_card_suit)

Is there a problem with this approach to try to remove the duplicate code? Is this where the error in my code is?


Solution

  • You have a number of mistakes.

    The following source corrects some of them. However a fundamental defect is that you need to create a deck of 52 cards and then randomly select from the deck without replacement. You are instead doing random generation of individual cards which can result in duplicated cards.

    One change was to make this actually compile as a C program rather C++. I got compiler errors due to the variable definitions scattered through the code but then I am using an older compiler.

    This corrects a number of problems with your original source in the original question. I hope this helps you.

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <string.h>
    
    enum suit {
        heart = 0,
        spade = 1,
        club = 2,
        diamond = 3
    };
    
    char *suitNames[] = {   // must correspond to the enum suit {} above.
            "hearts",       // position 0 or heart
            "spades",       // position 1 or spade
            "clubs",        // position 2 or club
            "diamonds"      // position 3 or diamond
    };
    
    struct card {
        enum suit current_card_suit;
        int card_num;
        int is_red_card;
    };
    
    int cardDeckSize = 0;
    
    int numOpponentCardsLeft;
    int numPlayerCardsLeft;
    
    void deal_cards_to_player (struct card * pPlayerCards, int cardDeckSize);
    void deal_cards_to_cpu (struct card * pCpuCards, int cardDeckSize);
    
    int get_random_number_above_zero(int max);
    void waitFor(unsigned int seconds);
    
    void flush_input() {
        int ch;
        while ((ch = getchar()) != '\n' && ch != EOF)
        continue;
    }
    
    int main (int argc, char **argv) {
    
        int random_suit;
        char userInput[10];
        //Get deck size for war game
        int invalidSize = 1;
        int i, j;
    
        //Create arrays to hold the cards of the player and CPU
        struct card *pPlayerCards;
        struct card *pCpuCards;
        struct card *pCurrentSideCards;
    
        //Get Random number sequence for later
        srand(time(NULL));
        while (invalidSize == 1) {
            printf("\nEnter the amount of cards you would like to be dealed to each player for the war game (between 0 and 100)\n");
    
            fgets(userInput, 9, stdin);
    
            if(sscanf(userInput, "%i", &cardDeckSize) != 1) {
                printf("\nPlease enter an integer. You will have to enter the number twice because you did not follow directions.\n");
                flush_input();
                continue;
            }
            if(cardDeckSize > 0 && cardDeckSize < 101) {
                invalidSize = 0;
                break;
            } else {
                printf("\nPlease type a number between 0 and 100. You will have to enter the number twice because you did not follow directions.\n");
                flush_input();
                continue;
            }
        }
        printf("\nPress enter once more to proceed...");
        flush_input();
    
        pPlayerCards = malloc (cardDeckSize * sizeof(struct card));
        pCpuCards = malloc (cardDeckSize * sizeof(struct card));
    
        //You will see duplication in the two functions called below, but I could not figure out how to remove it; it works for now
        deal_cards_to_player(pPlayerCards, cardDeckSize);
        deal_cards_to_player(pCpuCards, cardDeckSize);
    //    deal_cards_to_cpu(pCpuCards, cardDeckSize);
    
        printf("\nWow! My hand is SO tired of dealing all those cards.  Let's play!\n\n");
    
        //"parse" the properties of each card...and right after show the game round results to the player
        /* I will have to change "i < cardDeckSize" eventually becuase the size of the deck will not necessarily determine
         the # of rounds; I'll get through one round first before worrying about this */
        for(i = 0; i < cardDeckSize; i++) { //Loop through each round
    
            char playerCardSuit[12] = {0};
            char cpuCardSuit[12] = {0};
    
            char playerStringCardNum[12] = {0};
            char cpuStringCardNum[12] = {0};
    
            char playerCardColor[12] = {0};
            char cpuCardColor[12] = {0};
            char stringCardNum[12] = {0};
    
            //Countdown for the player
            printf("\n3, ");
            waitFor(1);
            printf("2, ");
            waitFor(1);
            printf("1, ");
            waitFor(1);
            printf("GO, GO, GO!!!\n");
            waitFor(1);
    
            //Determine card terms set for each player
            for (j = 0; j < 2; j++) {
                char cardSuit[12] = {0};
                char cardColor[12] = {0};
    
                /* To eliminate duplication, based on the current iteration I tried to
                create a pointer that points to a pointer to the array of card structures
                for each player. we need to index through the hand to each card dealt */
                if(j == 0) {
                    //Start with "parsing" the player cards, then the CPU cards
                    pCurrentSideCards = pPlayerCards + i;
                } else {
                    pCurrentSideCards = pCpuCards + i;
                }
    
                //EXPLANATION:
                /* Accessing the card properties: I first tried to dereference the pointer
                to find a pointer to the card deck structure array.  Then I accessed
                the correct card member in the array with "+i".  I finally tried
                to access the value with the "->" symbol, which dereferences again
     before accessing the member
                */
                if ( pCurrentSideCards->current_card_suit <= diamond) {
                    strcpy (cardSuit, suitNames[pCurrentSideCards->current_card_suit]);
                } else {
                   printf("\nThere was a fatal error determining the card suit of some dealt out cards.\n");
                }
                if(j == 0) { //If i = 0 we are working with the player cards, otherwise we are working with the CPU cards
                    strcpy(playerCardSuit, cardSuit);
                } else {
                    strcpy(cpuCardSuit, cardSuit);
                }
    
                switch (pCurrentSideCards->card_num) {
                    case 1:
                        strcpy(stringCardNum, "ace");
                        break;
    
                    case 11:
                        strcpy(stringCardNum, "jack");
                        break;
    
                    case 12:
                        strcpy(stringCardNum, "queen");
                        break;
    
                    case 13:
                        strcpy(stringCardNum, "king");
                        break;
    
                    default: {
                        int cardAsNumber = pCurrentSideCards->card_num;
                        char cardAsString[12] = {0};
                        sprintf(cardAsString, "%i", cardAsNumber);
                        strcpy(stringCardNum,cardAsString);
                    }
                }
                if(j == 0) {
                    strcpy(playerStringCardNum, stringCardNum);
                } else {
                    strcpy(cpuStringCardNum, stringCardNum);
                }
    
                switch (pCurrentSideCards->is_red_card) {
                    case 0:
                        strcpy(cardColor, "black");
                        break;
                    case 1:
                        strcpy(cardColor, "red");
                        break;
                }
    
                if(j == 0) {
                    strcpy(playerCardColor, cardColor);
                } else {
                    strcpy(cpuCardColor, cardColor);
                }
            }
    
            printf("\n               RESULTS!!! (DUN DUN, DUN)");
            printf("\n         Card Color        Card Number         Card Suit");
            printf("\n YOU:  A   %-8.8s             %-8.8s     of      %s     ", playerCardColor, playerStringCardNum, playerCardSuit);
            printf("\n CPU:  A   %-8.8s             %-8.8s     of      %s    " , cpuCardColor, cpuStringCardNum, cpuCardSuit);
        }
    
        free(pPlayerCards);
        return 0;
    }
    
    void deal_cards_to_player(struct card *pPlayerCard, int cardsToDeal) {
        int numbersDealedSinceResponse = 0;
        float randNumsNeeded = 3 * cardsToDeal; //You need three random values shown in the struct for each card
        float totalNumsDealed = 0.0;
        int i;
    
        printf("\nPlease Wait...We are dealing out your cards\n");
        waitFor(1);
        for (i = 0; i < cardsToDeal; i++) {
            //Get suit for card as a value from 0 to 3.
            int suitNum = get_random_number_above_zero(4) - 1;
            //Get card number
            int cardNum = get_random_number_above_zero(13);
            //Tell if the card is red based on the suit number
            // red if hearts or diamonds.
            int isRed = (suitNum == 0 || suitNum == 3);
            //Assign the values after getting the current card in the array
            (pPlayerCard+i)->current_card_suit = suitNum;
            (pPlayerCard+i)->card_num = cardNum;
            (pPlayerCard+i)->is_red_card = isRed;
            printf("\n\nFor debugging purposes only, here are the player cards generated:");
            printf("\nSuit Num: %i", suitNum);
            printf("\nCardNum: %i", cardNum);
            printf("\nIs it red: %i", isRed);
            if(numbersDealedSinceResponse > 6) {
                /* In order for the random numbers to stay unique and not be
                generated in a pattern, wait for one second and then call srand(time(NULL));
                to change the seed again based on time every 6 numbers */
                waitFor(1);
            }
            if(numbersDealedSinceResponse == 12) {
                    //Every 12 numbers provide a response showing the percent completed
                    float percent_done = 100 * (totalNumsDealed / randNumsNeeded);
                    int percent_rounded = (int) percent_done;
                    printf("Please Wait...We are dealing out your cards (%i%%)\n", percent_rounded);
                    numbersDealedSinceResponse = 0;
                    totalNumsDealed += 12;
            }
            numbersDealedSinceResponse+=3;
        }
    }
    
    int get_random_number_above_zero(int max_num) {
        int randomNumber;
        randomNumber = (rand() % max_num) + 1;
        return randomNumber;
    }
    
    void waitFor(unsigned int seconds) {
        unsigned int stopTime = time(0) + seconds;
        while (time(0) < stopTime); //it will wait until the calculated stop time
    }