Editing an array of strings in c - c

I'm writing code for a poker game and in my main function I have:
const char *suits[4] = { "Spades", "Clubs", "Hearts", "Diamonds" };
const char *faces[13] = { "Ace", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King" };
int deck[4][13] = { 0 };
srand((unsigned)time(NULL));
char *hand[5] = { "\0" };
shuffle(deck);
deal(deck, faces, suits, hand);
for (int i = 0; i < 5; i++) {
printf("%s", hand[i]);
}
This is where my general problem is. hand wont print out the values given to it in deal, which are 5 cards.
shuffle() simply shuffles the deck, no errors there so I am not going to include it in this question.
deal() has the following code (ignore the curly-bracket/whitespace discrepancies, I'm still adjusting to the formatting of this site):
void deal(const int wDeck[][13], const char *wFace[], const char *wSuit[],
char *hand[]) {
int row = 0; /* row number */
int column = 0; /*column number */
int card = 0; /* card counter */
/* deal 5 of the 52 cards */
for (card = 1; card <= 5; card++)
{
/* loop through rows of wDeck */
for (row = 0; row <= 3; row++)
{
/* loop through columns of wDeck for current row */
for (column = 0; column <= 12; column++)
{
/* if slot contains current card, deal card */
if (wDeck[row][column] == card)
{
char str1[10];
strcpy(str1, wFace[column]);
char str2[10];
strcpy(str2, wSuit[row]);
char str3[6] = " of ";
char str[26] = "";
strcat(str, str1);
strcat(str, str3);
strcat(str, str2);
puts(str);
hand[card - 1] = str;
printf("%s\n", hand[card - 1]);
}
}
}
}
}
The code in the if statement works just fine.
The problem arises in main() when I try to print the values given to hand, however in deal() the values in hand print fine. I assume that I am not passing hand into the function correctly, but no matter the different methods I've tried to get the program to run correctly, nothing works.
An example of the program as is can be seen here:
Example of program running

in you deal() function:
hand[card - 1] = str;
str is local character array whose address will get invalidated once you return from deal()
right way to do it will be allocate memory to each element(max number of elements being 5) of hand, then copy value of str using strcpy into element of hand
e.g.
hand[card - 1] = malloc(26);
strcpy(hand[card - 1],str);

Related

How to check first letter of one string with last letter of another string inside of same char array

How can I complete the function canArrangeWords() ?
Question : Given a set of words check if we can arrange them in a list such that the last letter of any word and first letter of another word are same. The input function canArrangeWords shall contain an integer num and array of words arr. num denotes the number of word in the list (1<=num<=100). arr shall contain words consisting of lower case letters between 'a' - 'z' only . return 1 if words can be arranged in that fashion and -1 if cannot.
Input : 4 pot ten nice eye
output : 1
input : 3 fox owl pond
output: -1
Please help me complete this program .
**
#include<stdio.h>
#include<string.h>
int canArrangewords(int,char [100][100]);
void main(){
int n ,count=0 , i ;
char arrayS[100][100];
scanf("%d",&n);
for (i = 0; i < n; ++i)
{
scanf("%s",arrayS[i]);
}
for(i=0;i<n;i++)
{
printf("%s",arrayS[i]);
printf("\n");
}
printf("%c\n",arrayS[2][4]);
canArrangewords(n , arrayS);
}
int canArrangewords(int n,char arrayS[100][100]){
int i , j ;
for ( i = 0; i < n; i++)
{
for ( j = i+1 ; j < strlen(arrayS[j+1]); i++)
{
int flag = strlen(arrayS[j+1]) - 1;
int temp = strcmp(arrayS[i][0],arrayS[j][flag]);
}
}
}
}
Well, first of all think of the way you can reach that answer.
If you only need to know if they can or can not be arranged and you do not have to do so your self you can use an empty array of int array[26] for each letter a-z.
The rule is that from all the first and last letters for all the words only two MAY appear an odd amount of times - the first letter of first word in list and the last letter in the last word in the list, the rest MUST appear an even amount of times. I would add a check to make sure the letters are lowercase as well. good luck!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MINASCII 97
#define LETTERS 26
void UpdateArray(char letter, int* arr)
{
if(arr[letter - MINASCII] == 0)
{
++arr[letter - MINASCII];
}
else
{
--arr[letter - MINASCII];/*for each second time same letter is seen reduce back to zero */
}
}
int canArrangewords(int wordNum, char* wordArr[])
{
int arr[LETTERS] = {0};
int i = 0;
int count = 0 ;
char first;
char last;
char* string;
for (i= 0; i< wordNum; ++i)
{
string = wordArr[i];
first = string[0];
last = string[strlen(string)-1];
UpdateArray(first, &arr[0]);
UpdateArray(last, &arr[0]);
}
for(i = 0; i< LETTERS; ++i)
{
count+=arr[i];
}
if(count == 2 || count == 0)/*either once each or twice -see word1 example in main*/
{
return 1;
}
return -1;
}
int main()
{
int i = 0;
char* words[] = {"pot", "ten", "nice", "eye"};
char* words1[] = {"pot", "ten", "nip"};
char* words2[] = {"fox", "owl", "pond"};
i = canArrangewords(4,words);
printf("%d\n", i);
i = canArrangewords(3,words1);
printf("%d\n", i);
i = canArrangewords(3,words2);
printf("%d\n", i);
return 0;
}
Change your array of words into an array of pointers to words. Then you can simply exchange the pointers.
To speed things up, instead of a pointer to a word, have it point to a structure:
struct WORD {
char *firstchar; // begin of word
char *lastchar; // last char of word
} *words[100]; // array of 100 pointers to words
To read the words:
char buf[100];
for (i = 0; i < n; ++i)
{
scanf("%s",buf);
int len= strlen(buf);
words[i]= malloc(sizeof(struct WORDS));
words[i]->firstchar= malloc(len+1);
strcpy(words[i]->firstchar, buf);
words[i]->lastchar= words[i]->firstchar + len-1;
}
Now compare and sort:
if (*words[i]->lastchar == *words[j]->firstchar) {
struct WORDS *tmp= words[i+1];
words[i+1]= words[j];
words[j]= tmp;
}
Do this in a loop, a kind of bubble sort. I leave that to you.

How to iteratively generate all possible combinations of letters and numbers for matching with a variable length string?

I wish to write a iterative logic program where there is an input string and the program starts from length 1 and tries all possible combinations of letters and numbers. If the match is not found, it tries all possible combinations of letters and numbers for length 2 and so on until it finds a match with the input string.
For example,
string input = "xG7a";
// loop all possible combinations for length 1, i.e., 0-9 then A-Z, then a - z
// check for all if matches the input string
// loop all possible combinations for length 2, i.e., 00-09, then 0A-0Z, then 0a - 0z. Then
// for 10-19, then 1A-1Z, then 1a - 1z ... till z0-z9, then zA-zZ, then za - zz
// again check for all if matches the input string
// Keep doing this for lengths 3, 4, 5 and so on till it matches with the input string.
// exit with status success if match else keep going till infinity
// This example would exit at length 4 when it matches with "xG7a"
Number of all possible combinations being matched here are (10 + 26 + 26 = 62) = 62^1 + 62^2 + 62^3 + ... till there is a match.
EDIT
More details:
This is part of an exercise on writing brute-forcing logic
The input string is not known beforehand. The above example is for illustration. I've figured out the rest of the logic. The generated string is being passed into a hash function that generates a hash to match with a password hash in a database. Hence the dynamic nature of the string to be generated.
It is known beforehand that the password string is only comprised of numbers and lower and upper case letters.
Thank you in advance for all the help.
You say - a bit of pseudocode, I say - full working program!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MARGIN 5
// if you're getting errors due to redeclaration of 'strdup', just remove that
const char *strdup(const char *string) {
const size_t len = strlen(string);
char *dst = calloc(len + 1, sizeof(char));
memmove(dst, string, len);
return dst;
}
struct NumeralSystem {
char *alphabet;
size_t base;
};
struct Word {
struct NumeralSystem ns;
char *data; // the current combination, null-terminated
unsigned int *_internal; // indices of the characters of 'data' in 'ns.alphabet'
size_t length, maxLength;
};
struct NumeralSystem NewSystem(const char *alpha) {
struct NumeralSystem ret = {strdup(alpha), strlen(alpha)};
return ret;
}
struct Word NewWordEmpty(const struct NumeralSystem ns, const size_t maxLength) {
struct Word ret;
ret.ns = ns;
ret.data = calloc(maxLength + 1, sizeof(char));
ret._internal = calloc(maxLength + 1, sizeof(unsigned int));
ret.maxLength = maxLength;
*ret._internal = 0;
*ret.data = *ret.ns.alphabet;
ret.length = 1;
return ret;
}
struct Word NewWordPreset(const struct NumeralSystem ns, const char *data) {
struct Word ret;
ret.length = strlen(data);
const size_t maxLength = ret.length + MARGIN;
ret.ns = ns;
ret.data = calloc(maxLength + 1, sizeof(char));
ret._internal = calloc(maxLength + 1, sizeof(unsigned int));
ret.maxLength = maxLength;
memmove(ret.data, data, ret.length);
for (size_t i = 0; i < ret.length; ++i) {
const char *found = strchr(ns.alphabet, ret.data[i]);
if (found == NULL) return NULL;
ret._internal[i] = found - ns.alphabet;
}
return ret;
}
void EnlargeWord(struct Word *wrd) { // here, wrd->length - wrd->maxLength == 1
const size_t newSize = wrd->maxLength + MARGIN;
wrd->data = realloc(wrd->data, newSize * sizeof(char));
wrd->_internal = realloc(wrd->_internal, newSize * sizeof(int));
memset(wrd->data + wrd->maxLength + 1, 0, MARGIN);
memset(wrd->_internal + wrd->maxLength + 1, 0, MARGIN);
wrd->maxLength = newSize;
}
void DestroyWord(struct Word *wrd) {
free(wrd->data), free(wrd->_internal);
}
struct Word *next(struct Word *wrd) {
int len = (int)(wrd->length - 1); // this can be negative, see below
// handle the overflow if current digit is equal to the last_digit of the alphabet
// 1. last_digit -> first_digit
// 2. go to previous position
while ((len >= 0) && (wrd->_internal[len] == wrd->ns.base - 1)) {
wrd->_internal[len] = 0;
wrd->data[len--] = *wrd->ns.alphabet;
}
// if all the digits in the word were equal to the last_digit of the alphabet,
// 'len' will be exactly (-1), and the word's length must increase
if (len == -1) {
wrd->data[wrd->length++] = *wrd->ns.alphabet;
// UH-OH, we're about to run out of bounds soon!
if (wrd->length > wrd->maxLength)
EnlargeWord(wrd);
return wrd;
}
// if 'len' is still nonnegative, it's the position of the digit
// that we haven't increased yet
wrd->data[len] = wrd->ns.alphabet[++wrd->_internal[len]];
return wrd;
}
int main(void) {
const struct NumeralSystem ns = NewSystem("abcdef");
struct Word wrd = NewWordPreset(ns, "deadbeef");
printf("%s\n", wrd.data);
for (unsigned int i = 0; i < 30; ++i)
printf("%s\n", next(&wrd)->data);
DestroyWord(&wrd);
return 0;
}
Create a string with all possible characters in the proper order:
char charlist[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
Then for each character you want to check, loop through this string build your test string and compare:
int i, found;
char str_to_test[5];
for (i=0, found=0; !found && i<strlen(charlist); i++) {
str_to_test[0] = charlist[i];
str_to_test[1] = 0;
if (!strcmp(str_to_test, target_string)) {
found = 1;
}
}
if (found) {
printf("found it!\n");
} else {
printf("not found\n");
}
Repeat in nested loops for each substring.

Not sure why I'm getting a segmentation fault when shuffling cards in C

I know it has to do with my pointer variable, my goal is to implement the color of the suit to the preexisting code I was given. So I created a char pointer under the deck structure. It will print out everything correctly until I get to shuffle, in which case I get a segmentation fault.
#include <stdio.h>
#include <time.h> //time function
#include <stdlib.h> //random number generator functions
#include <string.h> //need for Linux
#define MAX 9
#define MAX_CARDS 52
#define MAX_RANKS 13
#define MAX_SUITS 4
#define COLS 2 //number of columns to display in output
//structure definition
struct card{
char *rank;
char suit[MAX];
char *color;
};
typedef struct card Card;
//array of pointers to strings for ranks
char *ranks[MAX_RANKS] = {"Ace", "Two", "Three", "Four", "Five", "Six", "Seven",
"Eight", "Nine", "Ten", "Jack", "Queen", "King"};
char *color[2] = {"(black)", "(red)"};
//two-dimensional array of strings for suits
char suits[MAX_SUITS][MAX] = {"Clubs", "Diamonds", "Hearts", "Spades"};
//[0][1] [0][2][0][3]
void initialize(Card []);
void shuffle(Card []);
void display(const Card[]);
int main(){
char newline = '\n'; //to repeat while loop
//declare an array of 52 cards
Card deck[MAX_CARDS] = {"","",""};
initialize(deck);
deck[0].color = "(black)" ;
deck[1].color = "(red)";
printf("Display an ordered deck of cards:\n");
display(deck);
while('\n' == newline){
printf("\nshuffling deck ... \n\n");
shuffle(deck);
display(deck);
printf("\n\nWould you like to shuffle again?\nIf so, press \"Enter\" key. If not, enter any other char. ");
newline = getchar();
}
return 0;
}
/*
initialize the deck of cards to string values
deck: an array of structure cards
*/
void initialize(Card deck[]){
int i = 0;
for(i=0;i<MAX_CARDS;i++){
deck[i].rank = ranks[i%MAX_RANKS];
strncpy(deck[i].suit, suits[i/MAX_RANKS], MAX);
}
}
/*
use the pseudo-random number generator to shuffle the cards
deck: an array of structure cards
*/
void shuffle(Card deck[]){
int swapper = 0; //index of card to be swapped
int i = 0; //counter
Card temp = {"", ""}; //temp holding place for swap
srand(time(NULL)); //seed the random numbers with current time
for(i=0;i<MAX_CARDS;i++){
//generate a pseudo-random number from 0 to 51
swapper = rand() % MAX_CARDS;
//swap current card with da swapper
temp = deck[i];
deck[i] = deck[swapper];
deck[swapper] = temp;
}
}
/*
display the deck of cards
deck: an array of structure cards
*/
void display(const Card deck[]){
int i = 0;
for(i=0;i<MAX_CARDS;i++)
{
printf("%5s of %-10s", deck[i].rank, deck[i].suit);//%5s makes "of" line up -10 makes cols.
if (strcmp(deck[i].suit, "Clubs") == 0 || strcmp(deck[i].suit, "Spades") == 0)
{
printf(" %5s", deck[0].color);
}
else
{
printf(" %5s", deck[1].color);
}
//put in a newline every %x loops
if((COLS-1) == (i%COLS)){
printf("\n");
}
}
}
This is because your cards have the color which you actually don't use, except here:
deck[0].color = "(black)" ;
deck[1].color = "(red)";
Now, when you shuffle the deck the chances are that you'd get another card there, whose .color is still NULL and your code crashes in printf("...%s...", deck[0].color);
The solution of course is to a) remove the color member altogether, b) then modify the printing code to
if (strcmp(deck[i].suit, "Clubs") == 0 || strcmp(deck[i].suit, "Spades") == 0) {
printf(" (black)");
}
else {
printf(" (red) ");
}
However, I'd personally use enums to represent the ranks and suits, for example
enum Suit {
HEARTS = 0,
SPADES,
DIAMONDS,
CLUBS
};
struct Card {
enum Suit suit;
...
};
and for printing
char *suit_to_string[4] = {"Hearts", "Spades", "Diamonds", "Clubs"};
...
printf("%s", suit_to_string[deck[i].suit]);

Deleting an element from an array of pointers to structs

I have an array of pointers to structs, and what I want to do is delete an element and shift all the rest to fill the gap. I have written a function which seems to work, however valgrind complains about 'invalid read/write of size 8' so now I'm wondering if what I did was incorrect.
Here's the code:
for (int i = (numOfApartments-1); i >= 0; i--) {
if (apartmentIsIdentical(apartment, apartmentArray[i]->apartment)) {
apartmentDestroy(apartmentArray[i]->apartment);
free(apartmentArray[i]);
shiftApartments(apartmentArray, i, numOfApartments);
numOfApartments--;
return 1;
}
}
static void shiftApartments(ApartmentInfo* array, int startIndex, int endIndex) {
for (int i = startIndex; i < endIndex; i++) {
swapApartments(&array[i], &array[i + 1]);
}
}
static void swapApartments(ApartmentInfo* apartment1, ApartmentInfo* apartment2) {
ApartmentInfo temp = *apartment1;
*apartment1 = *apartment2;
*apartment2 = temp;
}
My question is mainly whether the free(apartmentArray[i]) is correct. The way I see it, it should leave an empty slot which I just move to the end of the array and place something else there later. However the error of 'invalid read/write of size 8' made me wonder whether freeing apartmentArray[i] actually make the slot inaccessible..? Why does it say I can't write to it?
Thanks!
since you freed apartmentArray[i], you cant swap the values, just assign the pointer in shiftApartments
try to replace
swapApartments(&array[i], &array[i + 1]);
with
array[i] = array[i+1];
memmove() is your friend here. Memmove handles the cases of overlapping moves, and can avoid an explicit loop. The only difficulty is to get the sizes right!
(I use an array of pointers to character, but this is essentially not different from pointers to struct. Except that you should not attempt to free() them ;-)
#include <stdio.h>
#include <string.h>
int main(void)
{
char *array[] = { "one", "two", "three", "four"
, "five", "six", "seven", "eight" };
/* using an array of pointers to string literals
** , so free() should not be used here ...
*/
#define SHOULDFREE(s) fprintf(stderr,"Should free %s\n", s)
unsigned size = 8;
unsigned idx,top;
for (top=idx=size; idx-- > 0; ) {
/* only delete words that start with 't' */
if (*array[idx] != 't') continue;
SHOULDFREE(array[idx]);
top--;
if (idx >=top) continue;
fprintf(stderr,"about to move %u (%s) (%u elements) one place down\n"
, idx+1, array[idx+1], top-idx);
memmove( &array[idx], &array[idx+1], (top-idx) * sizeof array[0] );
}
for (idx=0; idx < top; idx++) {
printf("[%u]: %s\n", idx, array[idx] );
}
return 0;
}
And, of course the
memmove( &array[idx], &array[idx+1], (top-idx) * sizeof array[0] );
could be replaced by:
memmove( array+idx, array+idx+1, (top-idx) * sizeof array[0] );

Creating an array to hold a poker hand in C?

I have an assignment due in my computer science class (I posted this question a couple weeks ago but the way it was explained doesn't fit the program I'm supposed to do). I already have a program that shuffles and deals a deck right here.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void shuffle( int [][ 13 ] );
void deal ( const int[][ 13 ], const char *[], const char *[] );
int main()
{
const char *suit[4] ={"Hearts","Diamonds","Clubs","Spades"};
const char *face[13] ={"Ace", "Duece", "Three", "Four", "Five", "Six",
"Seven", "Eight","Nine", "Ten", "Jack", "Queen", "King"};
int deck[4][13] = {0};
int row, column, card = 1;
for( row = 0; row <= 3; row++ )
{
for(column = 0; column <= 12; column++)
{
deck[row][column] = card;
card++;
}
}
srand(time(0));
shuffle(deck);
deal(deck, face, suit);
return 0;
}
void shuffle( int wDeck[][13] )
{
int row, column, randomColumn, randomRow, card = 1, counter1, counter2, hold;
for( counter1 = 0; counter1 <= 3; counter1++)
{
for(counter2 = 0; counter2 <= 12; counter2++)
{
randomColumn = rand() % 13;
randomRow = rand() % 4;
hold = wDeck[counter1][counter2];
wDeck[counter1][counter2] = wDeck[randomRow][randomColumn];
wDeck[randomRow][randomColumn] = hold;
}
}
}
void deal( const int wDeck[][13], const char *wFace[], const char *wSuit[] )
{
int card, row, column;
for ( card = 1; card <= 52; card++ )
for (row = 0; row <= 3; row++ )
for ( column = 0; column <= 12; column++ )
if( wDeck[row][column] == card )
{
printf("%5s of %-8s%c",wFace[ column ], wSuit[row], card % 2 == 0 ? '\n' : '\t');
break;
}
}
I'm supposed to modify the deal function to deal a 5 card poker hand, and then later check to see what "rank" poker hand they have(two of a kind, flush). My teacher mentioned creating a separate double scripted array to do this but I could do it a different way. The problem is, I have to use the current deck/shuffle setup to do it. Could anyone explain how to do this? It's okay if it's inefficient, as long as it works.
With the existing deal prototype, there is no way to return information from it - it has no return value and all the arguments are const. Since the deck has already been shuffled (by shuffle()), I assume the idea is for the deal function to look at the first five cards in the deck array, and find the rank of them. That can either be done entirely within the deal function, or (better), by calling a int rank(int hand[5]) function from within the deal function.

Resources