I'm writing some functions for a poker game, running it with my input and debugging with Valgrind returns no errors, but when I run it through the course grader with their input using Valgrind, it returns this error message:
Grading at Wed 02 Mar 2022 10:45:38 PM UTC
Compiling your code
rm -f test poker cards.o my-test-main.o *~
cc -ggdb3 -Wall -Werror -pedantic -std=gnu99 -c -o deck.o deck.c
cc -ggdb3 -Wall -Werror -pedantic -std=gnu99 -c -o eval.o eval.c
cc -ggdb3 -Wall -Werror -pedantic -std=gnu99 -c -o cards.o cards.c
gcc -o test-eval -ggdb3 deck.o deck-c4.o eval-c4.o eval.o test-eval.o cards.o input.o future.o
Testcase 1: Trying hands with nothing //<----- Poker hand with nothing special
Valgrind returned an error status
==220== Memcheck, a memory error detector
==220== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==220== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==220== Command: ./test-eval inp.1.txt
==220== Parent PID: 219
==220==
==220== Use of uninitialised value of size 8
==220== at 0x109419: print_hand (deck.c:12)
==220== by 0x10B9C6: describe_hand (in /graderhome/work/c3prj2_eval/test-eval)
==220== by 0x10BBBE: main (in /graderhome/work/c3prj2_eval/test-eval)
==220==
==220== Use of uninitialised value of size 8
==220== at 0x109419: print_hand (deck.c:12)
==220== by 0x10B9C6: describe_hand (in /graderhome/work/c3prj2_eval/test-eval)
==220== by 0x10BBE2: main (in /graderhome/work/c3prj2_eval/test-eval)
==220==
==220==
==220== HEAP SUMMARY:
==220== in use at exit: 0 bytes in 0 blocks
==220== total heap usage: 278 allocs, 278 frees, 14,160 bytes allocated
==220==
==220== All heap blocks were freed -- no leaks are possible
==220==
==220== Use --track-origins=yes to see where uninitialised values come from
==220== For lists of detected and suppressed errors, rerun with: -s
==220== ERROR SUMMARY: 10 errors from 2 contexts (suppressed: 0 from 0)
print_hand()
is some code that I've written in past assignments ( within deck.c
) that complements the one I'm struggling with ( eval.c
), it just calls print_card()
for each card in the hand
:
void print_hand(deck_t * hand){
for(int i = 0; i < hand->n_cards; i ) {
print_card(*hand->cards[i]);//Prints a card. //<----Line 12 here!
printf(" ");//Then a space.
}
}
print_card()
just receives a type card_t
and prints it's card_t.value
and card_t.suit
as type char
, for example: "As", "Qc", "6d". (A hand could be "Kd Kh Ks 9h 7c 7h 2h")
But I really don't think the error is coming from these codes I've written before, everything had to pass the grader for that assignment.
Even so I went back and initialized every variable as well as in the code of eval.c
(where I presume the error is), even though they were not being dereferenced before being initialized with a value.
Everything still works as expected for me, but the grader system still returns the same error message using Valgrind.
I really don't understand why the error still persists.
Could you please give me some help with this?
Thank you very much in advance.
I'll post the code that I wrote for this assignment bellow ( eval.c
), is not that big of a code, but it's bigger than what I've seen here, so please let me know if I shouldn't post this here.
I should mention that all the structs, for example: card_t
and deck_t
, all function names, types and parameters were given to me, and their main
calls these functions and the ones I've written in past assignments.
#include "eval.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
/*Return negative if card1 has higher value than card2
and vice-versa for decreasing order.*/
int card_ptr_comp(const void * vp1, const void * vp2) {
const card_t *const *cp1 = vp1;
const card_t *const *cp2 = vp2;
if((*cp1)->value == (*cp2)->value) {
//Lower ranking == better.
if((*cp1)->suit < (*cp2)->suit) return -1;
if((*cp1)->suit > (*cp2)->suit) return 1;
if((*cp1)->suit == (*cp2)->suit) return 0;
}
if((*cp1)->value != (*cp2)->value)return (*cp2)->value - (*cp1)->value;
printf("\n card_ptr_comp: This shouldn't have happened. ");
return 0;
}
//Checks if there is a flush in hand.
suit_t flush_suit(deck_t * hand) {
assert(hand->n_cards > 0);
int sp = 0, he = 0, di = 0, cl = 0;
for(int i = 0; i < hand->n_cards; i ) {
switch((*hand->cards[i]).suit) {
case SPADES:
sp ;
break;
case HEARTS:
he ;
break;
case DIAMONDS:
di ;
break;
case CLUBS:
cl ;
break;
default:
printf("Card doesn't have a correct suit");
break;
}
}
/*Counts how many times each suit has appeared in the hand.
If any is equal to 5, returns it, else, returns NUM_SUITS.*/
if(sp >= 5) return SPADES;
if(he >= 5) return HEARTS;
if(di >= 5) return DIAMONDS;
if(cl >= 5) return CLUBS;
else return NUM_SUITS;
}
//Get the largest element in passed in array.
unsigned get_largest_element(unsigned * arr, size_t n) {
int temp = 0;
for(int i = 0; i < n; i ) {
if(arr[i] > temp) temp = arr[i];
}
return temp;
}
//Returns the lowest index of a pair or a 3 of a kind.
size_t get_match_index(unsigned * match_counts, size_t n,unsigned n_of_akind) {
for(int i = 0; i < n; i ) {
if(n_of_akind == match_counts[i]) return i;
}
return EXIT_FAILURE;
}
//Finds secondary pair of cards in hand.
ssize_t find_secondary_pair(deck_t * hand,
unsigned * match_counts,
size_t match_idx) {
for(int i = 0; i < hand->n_cards; i ) {
if(match_counts[i] > 1 && (*hand->cards[i]).value != (*hand->cards[match_idx]).value) {
return i;
}
}
return -1; //Return -1 if nothing is found.
}
//Helper function to find index of 5 if the hand starts with an Ace
int where_5_at(deck_t * hand) {
for(int i = 0; i < hand->n_cards; i ) {
if((*hand->cards[i]).value == 5) return i;
}
return -1;
}
//Helper function that looks for Straights.
int straight_helper(deck_t *hand, size_t index, suit_t fs) {
int check = 1, dif = 0;
card_t temp = *hand->cards[0];
for(int i = index; i < hand->n_cards; i ) {
if(i == index) { //If first iteration, set temp to card at index.
temp = *hand->cards[i];
continue;
}
dif = temp.value - (*hand->cards[i]).value;
if(dif == 0) continue; //If the value of both cards are the same, continue.
if(dif == 1) { //If dif is 1, hand->cards[i] is adding to the Straight.
check ;
if(check == 5) return 1; //If check is equal to 5, there is a Straight in hand.
temp = *hand->cards[i];
continue;
}
if(dif > 1) return 0; //If dif > 1, there is no Straight in the hand.
}
return 0;
}
//Helper function that looks for Straight Flushes.
int straightFlush_helper(deck_t *hand, size_t index, suit_t fs) {
if((*hand->cards[index]).suit != fs) return 0;
int check = 1, strike = 0, dif = 0;
card_t temp = *hand->cards[0];
for(int i = index; i < hand->n_cards; i ) {
if(i == index) { //If first iteration, set temp to card at index.
temp = *hand->cards[i];
continue;
}
dif = temp.value - (*hand->cards[i]).value;
//If strike = 1.
if(strike == 1) {
if(dif == 1 && (*hand->cards[i]).suit == fs) { //If [i] suit is fs it adds to the Straight Flush.
strike = 0;
check ;
if(check == 5) return 1; //If check is equal to 5, there is a Straight in hand.
temp = *hand->cards[i];
continue;
}
if(dif == 1 && (*hand->cards[i]).suit != fs) {
strike = 2;
continue;
}
return 0;
}
if(strike == 2) { //If strike = 2.
if(dif == 1 && (*hand->cards[i]).suit == fs) { //If [i] suit is fs it adds to the Straight Flush.
strike = 0;
check ;
if(check == 5) return 1; //If check is equal to 5, there is a Straight in hand.
temp = *hand->cards[i];
continue;
}
return 0;
}
//If strike = 0.
if(dif == 0) continue; //If cards are the same, get next card.
if(dif == 1 && (*hand->cards[i]).suit != fs) { /*If [i] is not Fs, the hand can still
contain a Straight Flush.*/
strike = 1; //Sets strike to 1, so next card has to be the same value and suit == fs.
continue;
}
if(dif == 1 && (*hand->cards[i]).suit == fs) { /*If dif is 1 and [i] is fs,
[i] is adding to the Straight Flush.*/
check ;
if(check == 5) return 1; //If check is equal to 5, there is a Straight in hand.
temp = *hand->cards[i];
continue;
}
if(dif > 1) return 0; //If dif > 1, there is no Straight in the hand.
}
return 0;
}
//Helper function that looks for Ace-low Straights.
int ace_straight_helper(deck_t *hand, size_t index, suit_t fs) {
if(where_5_at(hand) == -1) return 0;
//check receives 2, because we have the Ace on index 0 or 1, and the 5.
int check = 2, dif = 0;
card_t temp = *hand->cards[where_5_at(hand)];
for(int i = where_5_at(hand); i < hand->n_cards; i ) {
if(i == where_5_at(hand)) { //If first iteration, set temp to card at index of 5.
temp = *hand->cards[i];
continue;
}
dif = temp.value - (*hand->cards[i]).value;
if(dif == 0) continue; //If value of both cards are the same, continue.
if(dif == 1) { //If dif is 1, hand->cards[i] is adding to the Straight.
check ;
if(check == 5) return -1; //If check is equal to 5, there is a Straight in hand.
temp = *hand->cards[i];
continue;
}
if(dif > 1) return 0; //If dif > 1, there is no Straight in the hand.
}
return 0;
}
//Helper function that looks for Ace-low Straight Flushes.
int ace_straightFlush_helper(deck_t *hand, size_t index, suit_t fs) {
if((*hand->cards[index]).suit != fs) return 0;
if(where_5_at(hand) == -1) return 0;
if((*hand->cards[where_5_at(hand)]).suit != fs) return 0;
//check receives 2, because we have the Ace on index 0 or 1, and the 5.
int check = 2, strike = 0, dif = 0;
card_t temp = *hand->cards[where_5_at(hand)];
for(int i = where_5_at(hand); i < hand->n_cards; i ) {
if(i == where_5_at(hand)) { //If first iteration, set temp to card at index of 5.
temp = *hand->cards[i];
continue;
}
dif = temp.value - (*hand->cards[i]).value;
//If strike = 1.
if(strike == 1) {
if(dif == 1 && (*hand->cards[i]).suit == fs) { /*If [i] suit is fs it adds
to the Straight Flush.*/
strike = 0;
check ;
if(check == 5) return -1; //If check is equal to 5, there is a Straight in hand.
temp = *hand->cards[i];
continue;
}
if(dif == 1 && (*hand->cards[i]).suit != fs) {
strike = 2;
continue;
}
return 0;
}
if(strike == 2) { //If strike = 2.
if(dif == 1 && (*hand->cards[i]).suit == fs) { //If [i] suit is fs it adds to the Straight Flush.
strike = 0;
check ;
if(check == 5) return -1; //If check is equal to 5, there is a Straight in hand.
temp = *hand->cards[i];
continue;
}
return 0;
}
//If strike = 0.
if(dif == 0) continue; //If cards are the same, get next card.
if(dif == 1 && (*hand->cards[i]).suit != fs) { /*If [i] is not Fs, the hand can still
contain a Straight Flush.*/
strike = 1; //Sets strike to 1, so next card, has to be the same value and suit = fs.
continue;
}
if(dif == 1 && (*hand->cards[i]).suit == fs) { /*If dif is 1 and [i] is fs,
[i] is adding to the Straight Flush.*/
check ;
if(check == 5) return -1; //If check is equal to 5, there is a Straight Flush in hand.
temp = *hand->cards[i];
continue;
}
if(dif > 1) return 0; //If dif > 1, [i] is not adding to the Straight Flush.
}
return 0;
}
//Uses helper functions to look for Straights and Straight flushes.
int is_straight_at(deck_t * hand, size_t index, suit_t fs) {
assert(hand->n_cards > 0);
//Ace-low Straight.
if((*hand->cards[index]).value == VALUE_ACE && fs == NUM_SUITS) {
if(straight_helper(hand, index, fs) == 0) {
//If straigh_helper returns 0, It looks for an Ace-low Straight.
return ace_straight_helper(hand, index, fs);
}else{
return 1;
}
//Ace-low Straight Flush.
}else if((*hand->cards[index]).value == VALUE_ACE && fs != NUM_SUITS) {
if(straightFlush_helper(hand, index, fs) == 0) {
//If straighFlush_helper returns 0, It looks for an Ace-low Straight Flush.
return ace_straightFlush_helper(hand, index, fs);
}else{
return 1;
}
}
//Regular Straight.
if((*hand->cards[index]).value != VALUE_ACE && fs == NUM_SUITS) {
return straight_helper(hand, index, fs);
//Straight Flush.
}else if((*hand->cards[index]).value != VALUE_ACE && fs != NUM_SUITS) {
return straightFlush_helper(hand, index, fs);
}
return 0;
}
//Builds a hand with a Pair, 3 of a kind or a Full House.
hand_eval_t build_hand_from_match(deck_t * hand,
unsigned n,
hand_ranking_t what,
size_t idx) {
assert(hand->n_cards > 4);
hand_eval_t ans;
ans.ranking = what;
int count = 0;
//Copies 'n' cards starting at 'idx'.
for(int i = idx; i < idx n; i ) {
ans.cards[count] = hand->cards[i];
count ;
}
//Copies the rest of the highest cards into the array.
for(int i = 0; i < 5; i ) {
if((*hand->cards[i]).value == (*hand->cards[idx]).value) continue;
ans.cards[count] = hand->cards[i];
count ;
}
return ans;
}
//Sorts and compares two hands to get the winner.
int compare_hands(deck_t * hand1, deck_t * hand2) {
//Sorts hand1 and hand2.
qsort(hand1->cards, hand1->n_cards, sizeof(struct card_tag), card_ptr_comp);
qsort(hand2->cards, hand2->n_cards, sizeof(struct card_tag), card_ptr_comp);
//Compares the two hands.
hand_eval_t cleanHand1 = evaluate_hand(hand1);
hand_eval_t cleanHand2 = evaluate_hand(hand2);
if(cleanHand1.ranking < cleanHand2.ranking) return 1;
else if(cleanHand1.ranking > cleanHand2.ranking) return -1;
else if(cleanHand1.ranking == cleanHand2.ranking) {
int dif = 0;
for(int i = 0; i < 5; i ) {
dif = cleanHand1.cards[i]->value - cleanHand2.cards[i]->value;
if(dif > 0) return 1;
if(dif < 0) return -1;
}
return 0;
}
printf("Something went wrong call 911 right now!");
return 0;
}
CodePudding user response:
"Use of uninitialised value" means exactly what it says. In context of the line for which that message was reported, the uninitialized value must be that of *hand->cards[i]
for some i
. That the issue is recognized by valgrind probably means that that expression designates part of a dynamically allocated object. Note well that malloc()
returns pointers to (formally) uninitialized memory.
I leave it to you to determine why the memory in question goes uninitialized in the case in question.
CodePudding user response:
Initialise the memory allocated using malloc
with a call to memset
, before operating on the allocated memory.
void* ptr = malloc(sizeof(hand));
memset(ptr, 0, sizeof(hand));