0

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?

3
  • Use card_names[i][j] — you're trying to index i (you've got [i[j]]) and it isn't an array, like the error says. Commented Apr 9, 2022 at 19:19
  • 2
    There are multiple problems with this code. As mentioned, i[j] is meaningless. For example, what do you expect something like 3[5] to evaluate to? Answer: You'll get a compile-time error. Also, sizeof(array) does not give the number of elements in an array. It gives the number of bytes in an array. You need to divide it by the element size to get the number of elements. Commented Apr 9, 2022 at 19:27
  • 2
    Also, using strlen in a for loop test is almost always a mistake. If the string is loop-invariant, make the call once, before entering the loop. Don't make it every time through the loop. Commented Apr 9, 2022 at 19:29

3 Answers 3

1

There are many problems in the original code, including:

  • Mishandling subscripts, using card_names[i[j]] instead of the correct and intended card_names[i][j].
  • Not null terminating the strings.
  • Using sizeof(card_names) where you want a count of the elements in the array (that's sizeof(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]
Sign up to request clarification or add additional context in comments.

Comments

0

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]);
}

Comments

0

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;
        }
        
    }
  
}

2 Comments

"Queen of DIamonds" (possibly without the 'of', and possibly without the spaces) requires more than char answer[5] — maybe even char answer[sizeof("Queen of Diamonds")];.
Great solution. Not sure how strcat() managed to write more than the size of the array here. This link attempts to explain: reddit.com/r/C_Programming/comments/glb3n8/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.