-1

I am writing a go-fish program in C, but I have come across a segmentation fault error with a print statement. I don't even have to print something, just the print statement being there causes an error.

`
int getIndex(int* cards, int start, int x){
  printf("");
  for(int i = start; i < 26; i++){
    if(cards[i]==x){
      return i;
    }
  }
  return -1;
}`

Additionally, when I delete the print statement, the function always returns 0. I have attached a link to my complete code, as I think there is a chance that the error does not stem from this function but rather somewhere else and it just shows up here.

https://replit.com/@LukeSell20/Go-Fish-in-C#main.c

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

void shuffle(int cards[]);
void swapCards(int *cardOne, int *cardTwo);
void delay(int seconds);
void printArray(int arr[]);
int howMany(int cards[], int card);
int getIndex(int *cards, int start, int x);
void moveCards(int **cards1, int **cards2, int card, int x);

int
main(void)
{
    int order[] = { 1, 2, 3, 4, 5, 6, 7, 8,
        9, 10, 11, 12, 13, 14, 15,
        16, 17, 18, 19, 20, 21, 22,
        23, 24, 25, 26, 27, 28, 29,
        30, 31, 32, 33, 34, 35, 36,
        37, 38, 39, 40, 41, 42, 43,
        44, 45, 46, 47, 48, 49, 50,
        51, 52
    };

    shuffle(order);
    printf("Dealing cards...\n");
    delay(1);
    int playerHand[26];
    int computerHand[26];

    for (int i = 0; i < 26; i++) {
        playerHand[i] = -1;
        computerHand[i] = -1;
    }
    for (int i = 0; i < 7; i++) {
        playerHand[i] = order[i];
        computerHand[i] = order[i + 7];
    }

    int counter = 15;
    int bookCount = 0;
    int playerScore = 0;
    int computerScore = 0;
    // just an int array to keep track of any important indexes throughout
    // the program
    int index[3];

    do {
        printf("\nThese are your cards:\n\n");
        // delay(2);
        for (int m = 0; m < sizeof(playerHand) / sizeof(playerHand[0]); m++) {
            switch (playerHand[m] % 13) {
            case -1:
                continue;
                break;
            case 0:
                printf("Ace\n");
                break;
            case 1:
                printf("Two\n");
                break;
            case 2:
                printf("Three\n");
                break;
            case 3:
                printf("Four\n");
                break;
            case 4:
                printf("Five\n");
                break;
            case 5:
                printf("Six\n");
                break;
            case 6:
                printf("Seven\n");
                break;
            case 7:
                printf("Eight\n");
                break;
            case 8:
                printf("Nine\n");
                break;
            case 9:
                printf("Ten\n");
                break;
            case 10:
                printf("Jack\n");
                break;
            case 11:
                printf("Queen\n");
                break;
            case 12:
                printf("King\n");
                break;
            }
            // delay(1);
        }
        printf("\nComputer Hand:\n\n");
        for (int m = 0; m < sizeof(computerHand) / sizeof(computerHand[0]);
            m++) {
            switch (computerHand[m] % 13) {
            case -1:
                continue;
                break;
            case 0:
                printf("Ace\n");
                break;
            case 1:
                printf("Two\n");
                break;
            case 2:
                printf("Three\n");
                break;
            case 3:
                printf("Four\n");
                break;
            case 4:
                printf("Five\n");
                break;
            case 5:
                printf("Six\n");
                break;
            case 6:
                printf("Seven\n");
                break;
            case 7:
                printf("Eight\n");
                break;
            case 8:
                printf("Nine\n");
                break;
            case 9:
                printf("Ten\n");
                break;
            case 10:
                printf("Jack\n");
                break;
            case 11:
                printf("Queen\n");
                break;
            case 12:
                printf("King\n");
                break;
            }
            // delay(1);
        }
        char userMove[30];

        printf("\nPress enter to continue: ");
        scanf("%c", userMove);
        int fish;

        do {
            printf("\nWhat card do you want from your opponent?: ");
            scanf("%s", userMove);

            if (strcmp(userMove, "ace") == 0) {
                fish = howMany(computerHand, 0);
                printf("Your opponent had %d %s!",
                    fish, fish == 1 ? "ace" : "aces");
                int *array1 = playerHand;
                int *array2 = computerHand;

                moveCards(&array1, &array2, 0, fish);
            }
            else if (strcmp(userMove, "two") == 0) {
                fish = howMany(computerHand, 1);
                printf("Your opponent had %d %s!",
                    fish, fish == 1 ? "two" : "twos");
            }
            else if (strcmp(userMove, "three") == 0) {
                fish = howMany(computerHand, 2);
                printf("Your opponent had %d %s!",
                    fish, fish == 1 ? "three" : "threes");
            }
            else if (strcmp(userMove, "four") == 0) {
                fish = howMany(computerHand, 3);
                printf("Your opponent had %d %s!",
                    fish, fish == 1 ? "four" : "fours");
            }
            else if (strcmp(userMove, "five") == 0) {
                fish = howMany(computerHand, 4);
                printf("Your opponent had %d %s!",
                    fish, fish == 1 ? "five" : "fives");
            }
            else if (strcmp(userMove, "six") == 0) {
                fish = howMany(computerHand, 5);
                printf("Your opponent had %d %s!",
                    fish, fish == 1 ? "six" : "sixes");
            }
            else if (strcmp(userMove, "seven") == 0) {
                fish = howMany(computerHand, 6);
                printf("Your opponent had %d %s!",
                    fish, fish == 1 ? "seven" : "sevens");
            }
            else if (strcmp(userMove, "eight") == 0) {
                fish = howMany(computerHand, 7);
                printf("Your opponent had %d %s!",
                    fish, fish == 1 ? "eight" : "eights");
            }
            else if (strcmp(userMove, "nine") == 0) {
                fish = howMany(computerHand, 8);
                printf("Your opponent had %d %s!",
                    fish, fish == 1 ? "nine" : "nines");
            }
            else if (strcmp(userMove, "ten") == 0) {
                fish = howMany(computerHand, 9);
                printf("Your opponent had %d %s!",
                    fish, fish == 1 ? "ten" : "tens");
            }
            else if (strcmp(userMove, "jack") == 0) {
                fish = howMany(computerHand, 10);
                printf("Your opponent had %d %s!",
                    fish, fish == 1 ? "jack" : "jacks");
            }
            else if (strcmp(userMove, "queen") == 0) {
                fish = howMany(computerHand, 11);
                printf("Your opponent had %d %s!",
                    fish, fish == 1 ? "queen" : "queens");
            }
            else if (strcmp(userMove, "king") == 0) {
                fish = howMany(computerHand, 12);
                printf("Your opponent had %d %s!",
                    fish, fish == 1 ? "king" : "kings");
            }
            else {
                printf("Make sure you enter a valid card in all lowercase(ex: two)");
                fish = -1;
            }
            delay(1);
        } while (fish == -1);

        for (int k = 0; k < sizeof(playerHand) / sizeof(playerHand[0]); k++) {
            if (playerHand[k] == -1) {
                continue;
            }
            int index1 = 0;
            int index2 = 0;
            int index3 = 0;
            int cardCount = 1;

            for (int n = k + 1; n < sizeof(playerHand) / sizeof(playerHand[0]); n++) {
                if (playerHand[k] % 13 == playerHand[n] % 13) {
                    cardCount++;
                    if (index1 == 0)
                        index1 = n;
                    else if (index2 == 0)
                        index2 = n;
                    else
                        index3 = n;
                }
            }

            if (cardCount == 4) {
                bookCount++;
                playerHand[k] = -1;
                playerHand[index[0]] = -1;
                playerHand[index[1]] = -1;
                playerHand[index[2]] = -1;
                printf("\nBook found!");
            }
        }
    } while (bookCount < 13);

    // seven cards to each player
    // rest to the middle
    // asks for card
    // if they don't have it, go fish
    // if they get the card they asked for from the pile, they still get to
    // go next four cards is a book
    // once all books have been gotten, player with most books wins
    return 0;
}

void
swapCards(int *cardOne, int *cardTwo)
{
    int temp = *cardOne;

    *cardOne = *cardTwo;
    *cardTwo = temp;
}

void
shuffle(int cards[])
{
    srand(time(0));
    for (int i = 0; i < 52; i++) {
        int r = i + (rand() % (52 - i));

        swapCards(&cards[i], &cards[r]);
    }
}

void
delay(int halfseconds)
{
    long pause;
    clock_t now,
     then;

    pause = halfseconds * 0.5 * CLOCKS_PER_SEC;
    now = then = clock();
    while ((now - then) < pause)
        now = clock();
}

void
printArray(int *arr)
{
    for (int i = 0; i < sizeof(*arr); i++) {
        printf("%d\n", arr[i]);
    }
}

int
howMany(int *cards, int card)
{
    int cardCount = 0;

    for (int i = 0; i < 26; i++) {
        cardCount += card == cards[i] % 13 ? 1 : 0;
    }
    return cardCount;
}

int
getIndex(int *cards, int start, int x)
{
    printf("");
    for (int i = start; i < 26; i++) {
        if (cards[i] == x) {
            return i;
        }
    }
    return -1;
}

// Transfers cards from cards2 to cards1. The int card is the card that is
// being transfered, and x is how many of that card there are in the cards2
// array
void
moveCards(int **cards1, int **cards2, int card, int x)
{
    int lastIndex1;
    int lastIndex2;

    for (int i = 0; i < x; i++) {
        // adds card to the first available spots in cards1
        lastIndex1 = getIndex(*cards1, lastIndex1, -1);
        *cards1[lastIndex1] = card;
        lastIndex1++;

        // removes cards from cards2. lastIndex2 and lastIndex1 keep track of
        // the index of the last card that was added/removed so that the for
        // loop in getIndex() doesn't have to keep iterating over the same
        // numbers
        lastIndex2 = getIndex(*cards2, lastIndex2, card);
        *cards2[lastIndex2] = -1;
        lastIndex2++;
    }
}

The getIndex() function, which is on lines 288-296, is called in the moveCards() function, which is on lines 299-311. moveCards() is called on line 153, but I don't believe that is the problem. I have added comments to both moveCards() and getIndex() to explain.

Also, I am very new to C, so if you see anything else that could be improved upon, let me know.

Craig Estey
  • 26,185
  • 3
  • 20
  • 42
  • 3
    `printf` wouldn't cause a segfault, so the problem is somewhere else. Compile your code with the address sanitizer enabled (available in gcc and clang) and crank up warnings as high as you can. If you need more help, then [edit] your question to provide a [mcve] directly (not as an external link). – Stephen Newell Jun 04 '22 at 19:08
  • 2
    Turn on compiler warnings. You are using uninitialized variables, which can cause all sorts of problems. – Raymond Chen Jun 04 '22 at 19:10
  • Read the documentation of your compiler e.g. [GCC](https://gcc.gnu.org/) to be invoked with all warnings and debug info : `gcc -Wall -Wextra -g`. Then read the documentation of your debugger, e.g. [GDB](https://www.sourceware.org/gdb/). Read of course a good [C reference website](https://en.cppreference.com/w/c) and provide some [mre]. Study for inspiration the source code of open source programs (on https://github.com/ ...) or GNU programs like [GNU bash](https://www.gnu.org/software/bash/) or [GNU make](https://www.gnu.org/software/make/)... Learn to use https://valgrind.org/ – Basile Starynkevitch Jun 04 '22 at 19:16
  • 2
    Welcome to the world of Undefined Behavior, where removing or adding debug prints may change what happens. – hyde Jun 04 '22 at 19:17
  • 2
    In particular `lastIndex1` and `lastIndex2` are uninitialised. – Weather Vane Jun 04 '22 at 19:27
  • Aside: consider putting the names of the cards into an array, this will reduce the size and complexity of the code. – Weather Vane Jun 04 '22 at 19:34
  • 2
    This is a great opportunity to learn how to use your debugger. It gives you the point of the crash, and you can inspect the variables to see what went wrong. – Raymond Chen Jun 04 '22 at 19:37
  • 1
    You may want to read this: [Why should I always enable compiler warnings?](https://stackoverflow.com/q/57842756/12149471) – Andreas Wenzel Jun 04 '22 at 19:38
  • Lsell20, Hint: what is the value of `playerHand[index[0]] = -1;` when `playerHand[index[0]] = -1;` is first executed? – chux - Reinstate Monica Jun 05 '22 at 01:50

1 Answers1

0

Most likely it is the line if(cards[i]==x){ that causes the error, because your function is called with an uninitialized variable. The C language requires you to assign a value to a variable before you use it.

The problem appears to be related to the presence of the printf because in some very specific cases the compiler puts the same value (garbage) in the same place due to the order the lines were processed during code generation. Most likely by a big coincidence, when you put the printf the garbage value used is outside your array, and is most likely a low value otherwise. You must never expect a variable to have a useful value if you don't initialize it.

In this specific case, you did not initialize the vars lastIndex1 and lastIndex2. Assign a valid value (0) to them and this cause for a segmentation fault will go away.