For my program, I am building a string that will represent a card from a standard 52-card deck in C. However, I am having some trouble understanding how when I find the string in the array I want to copy, how to iterate through each character in that string and copy it. Here was my approach:
char * card_names[]={"Ace","2","3","4","5","6","7","8","9","10","Jack","Queen","King"};
char * suit_names[]={"Hearts","Diamonds","Clubs","Spades"};
void names(int card, int suit, char *answer) {
int i;
int index = 0;
for (i = 0; i < strlen(answer); i ) {
answer[i] = ' '; // empty the current string just in case
}
for (i = 0; i < sizeof(card_names); i ) {
if (i == card) {
for (int j = 0; j < strlen(card_names[i]); j ) {
answer[j] = card_names[i[j]];
index ; // keeps track of how big our current string is
}
}
}
for (i = 0; i < sizeof(suit_names); i ) {
if (i == suit) {
for (int j = 0; j < strlen(suit_names[i]); j ) {
answer[index] = suit_names[i[j]];
index ;
}
}
}
}
But I am getting this error:
c_asgn01_empty.c:534:33: error: subscripted value is neither array nor pointer nor vector
534 | answer[j] = card_names[i[j]];
| ^
My idea was that strings in C are treated as arrays of characters, and I have iterated through them in the past to add in characters or remove characters.
What could be a potential fix to this?
CodePudding user response:
There are many problems in the original code, including:
- Mishandling subscripts, using
card_names[i[j]]
instead of the correct and intendedcard_names[i][j]
. - Not null terminating the strings.
- Using
sizeof(card_names)
where you want a count of the elements in the array (that'ssizeof(card_names) / sizeof(card_names[0])
). - (Cosmetic): not separating the card name from the suit name in the answer.
- Using
strlen()
in a loop condition.
The original names
function can be made to 'work' as shown below.
However, the whole business of looping through all the indexes of the arrays,
copying the value in when the current index matches the one you were given is, to be polite about, pointless.
You should use the indexes directly to access the correct elements of
card_names
and suit_names
.
You can then decide whether to use snprintf()
or calls to strcpy()
and strcat()
to assemble the card name. The function alt_names_1()
uses snprintf()
and is probably what I'd use. The function alt_names_2()
uses strcpy()
and strcat()
and might even be faster, though not as compact, as alt_names_1()
.
#include <assert.h>
#include <stdio.h>
#include <string.h>
static const char * const card_names[] =
{
"Ace", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "Jack", "Queen", "King"
};
enum { NUM_CARD_NAMES = sizeof(card_names) / sizeof(card_names[0]) };
static const char * const suit_names[] =
{
"Hearts", "Diamonds", "Clubs", "Spades"
};
enum { NUM_SUIT_NAMES = sizeof(suit_names) / sizeof(suit_names[0]) };
static void names(int card, int suit, char *answer)
{
int i;
int index = 0;
answer[index] = '\0';
for (i = 0; i < NUM_CARD_NAMES; i )
{
if (i == card)
{
int len = strlen(card_names[i]);
for (int j = 0; j < len; j )
{
answer[index] = card_names[i][j];
index ; // keeps track of how big our current string is
}
}
}
for (i = 0; i < NUM_SUIT_NAMES; i )
{
if (i == suit)
{
int len = strlen(suit_names[i]);
for (int j = 0; j < len; j )
{
answer[index] = suit_names[i][j];
index ;
}
}
}
answer[index] = '\0';
}
static void alt_names_1(int card, int suit, size_t ans_len, char *answer)
{
assert(card >= 0 && card < NUM_CARD_NAMES);
assert(suit >= 0 && suit < NUM_SUIT_NAMES);
snprintf(answer, ans_len, "%s of %s", card_names[card], suit_names[suit]);
}
static void alt_names_2(int card, int suit, char *answer)
{
assert(card >= 0 && card < NUM_CARD_NAMES);
assert(suit >= 0 && suit < NUM_SUIT_NAMES);
strcpy(answer, card_names[card]);
strcat(answer, " of ");
strcat(answer, suit_names[suit]);
}
int main(void)
{
for (int card = 0; card < NUM_CARD_NAMES; card )
{
for (int suit = 0; suit < NUM_SUIT_NAMES; suit )
{
char answer1[sizeof("Queen of Diamonds")] = "";
char answer2[sizeof("Queen of Diamonds")] = "";
char answer3[sizeof("Queen of Diamonds")] = "";
names(card, suit, answer1);
alt_names_1(card, suit, sizeof(answer2), answer2);
alt_names_2(card, suit, answer3);
printf("Card %d, Suit %d: [%s] [%s] [%s]\n",
card 1, suit 1, answer1, answer2, answer3);
}
}
return 0;
}
Output:
Card 1, Suit 1: [AceHearts] [Ace of Hearts] [Ace of Hearts]
Card 1, Suit 2: [AceDiamonds] [Ace of Diamonds] [Ace of Diamonds]
Card 1, Suit 3: [AceClubs] [Ace of Clubs] [Ace of Clubs]
Card 1, Suit 4: [AceSpades] [Ace of Spades] [Ace of Spades]
Card 2, Suit 1: [2Hearts] [2 of Hearts] [2 of Hearts]
Card 2, Suit 2: [2Diamonds] [2 of Diamonds] [2 of Diamonds]
Card 2, Suit 3: [2Clubs] [2 of Clubs] [2 of Clubs]
Card 2, Suit 4: [2Spades] [2 of Spades] [2 of Spades]
Card 3, Suit 1: [3Hearts] [3 of Hearts] [3 of Hearts]
Card 3, Suit 2: [3Diamonds] [3 of Diamonds] [3 of Diamonds]
Card 3, Suit 3: [3Clubs] [3 of Clubs] [3 of Clubs]
Card 3, Suit 4: [3Spades] [3 of Spades] [3 of Spades]
Card 4, Suit 1: [4Hearts] [4 of Hearts] [4 of Hearts]
Card 4, Suit 2: [4Diamonds] [4 of Diamonds] [4 of Diamonds]
Card 4, Suit 3: [4Clubs] [4 of Clubs] [4 of Clubs]
Card 4, Suit 4: [4Spades] [4 of Spades] [4 of Spades]
Card 5, Suit 1: [5Hearts] [5 of Hearts] [5 of Hearts]
Card 5, Suit 2: [5Diamonds] [5 of Diamonds] [5 of Diamonds]
Card 5, Suit 3: [5Clubs] [5 of Clubs] [5 of Clubs]
Card 5, Suit 4: [5Spades] [5 of Spades] [5 of Spades]
Card 6, Suit 1: [6Hearts] [6 of Hearts] [6 of Hearts]
Card 6, Suit 2: [6Diamonds] [6 of Diamonds] [6 of Diamonds]
Card 6, Suit 3: [6Clubs] [6 of Clubs] [6 of Clubs]
Card 6, Suit 4: [6Spades] [6 of Spades] [6 of Spades]
Card 7, Suit 1: [7Hearts] [7 of Hearts] [7 of Hearts]
Card 7, Suit 2: [7Diamonds] [7 of Diamonds] [7 of Diamonds]
Card 7, Suit 3: [7Clubs] [7 of Clubs] [7 of Clubs]
Card 7, Suit 4: [7Spades] [7 of Spades] [7 of Spades]
Card 8, Suit 1: [8Hearts] [8 of Hearts] [8 of Hearts]
Card 8, Suit 2: [8Diamonds] [8 of Diamonds] [8 of Diamonds]
Card 8, Suit 3: [8Clubs] [8 of Clubs] [8 of Clubs]
Card 8, Suit 4: [8Spades] [8 of Spades] [8 of Spades]
Card 9, Suit 1: [9Hearts] [9 of Hearts] [9 of Hearts]
Card 9, Suit 2: [9Diamonds] [9 of Diamonds] [9 of Diamonds]
Card 9, Suit 3: [9Clubs] [9 of Clubs] [9 of Clubs]
Card 9, Suit 4: [9Spades] [9 of Spades] [9 of Spades]
Card 10, Suit 1: [10Hearts] [10 of Hearts] [10 of Hearts]
Card 10, Suit 2: [10Diamonds] [10 of Diamonds] [10 of Diamonds]
Card 10, Suit 3: [10Clubs] [10 of Clubs] [10 of Clubs]
Card 10, Suit 4: [10Spades] [10 of Spades] [10 of Spades]
Card 11, Suit 1: [JackHearts] [Jack of Hearts] [Jack of Hearts]
Card 11, Suit 2: [JackDiamonds] [Jack of Diamonds] [Jack of Diamonds]
Card 11, Suit 3: [JackClubs] [Jack of Clubs] [Jack of Clubs]
Card 11, Suit 4: [JackSpades] [Jack of Spades] [Jack of Spades]
Card 12, Suit 1: [QueenHearts] [Queen of Hearts] [Queen of Hearts]
Card 12, Suit 2: [QueenDiamonds] [Queen of Diamonds] [Queen of Diamonds]
Card 12, Suit 3: [QueenClubs] [Queen of Clubs] [Queen of Clubs]
Card 12, Suit 4: [QueenSpades] [Queen of Spades] [Queen of Spades]
Card 13, Suit 1: [KingHearts] [King of Hearts] [King of Hearts]
Card 13, Suit 2: [KingDiamonds] [King of Diamonds] [King of Diamonds]
Card 13, Suit 3: [KingClubs] [King of Clubs] [King of Clubs]
Card 13, Suit 4: [KingSpades] [King of Spades] [King of Spades]
CodePudding user response:
As the compiler error shows, you can't do [i[j]]
so instead you can change it to [i][j]
:
char *card_names[] = {"Ace","2","3","4","5","6","7","8","9","10","Jack","Queen","King"};
char *suit_names[] = {"Hearts","Diamonds","Clubs","Spades"};
void names(int card, int suit, char *answer) {
int i;
int index = 0;
for (i = 0; i < strlen(answer); i ) {
answer[i] = ' '; // empty the current string just in case
}
for (i = 0; i < sizeof(card_names); i ) {
if (i == card) {
for (int j = 0; j < strlen(card_names[i]); j ) {
answer[j] = card_names[i][j];
index ; // keeps track of how big our current string is
}
}
}
for (i = 0; i < sizeof(suit_names); i ) {
if (i == suit) {
for (int j = 0; j < strlen(suit_names[i]); j ) {
answer[index] = suit_names[i][j];
index ;
}
}
}
}
This will make the code work but there are still plenty of mistakes. You should not empty a string with a ' ' (space) but a '\0' (null byte) instead. You should call strlen only once at the start of the loop or use something else. The outer for loops where you have if (i == card)
and if (i == suit)
are unnecessary.
In this case, you may want to use strcat:
char *card_names[] = {"Ace","2","3","4","5","6","7","8","9","10","Jack","Queen","King"};
char *suit_names[] = {"Hearts","Diamonds","Clubs","Spades"};
void names(int card, int suit, char *answer) {
memset(answer, 0, strlen(answer)); // empty the current string just in case
strcat(answer, card_names[card]);
strcat(answer, suit_names[suit]);
}
CodePudding user response:
You could initialize your answer variable in the method that calls names as follows.
char answer[sizeof("Queen of Diamonds")];
Be sure to include necessary modules...
#include<stdio.h>
#include<string.h>
Then the following code will work.
void names(int card, int suit, char *answer) {
for(int i=0;i<13;i ){
if(card_names[i]==card_names[card]){
for(int j=0;j<4;j ){
if(suit_names[j]==suit_names[suit]){
strcpy(answer,card_names[card]);
strcat(answer,suit_names[suit]);
printf("%s",answer);
break;
}
}
}
else{
continue;
}
}
}