3

Im trying to solve some problem sets of CS50. I need to extract the first two characters of a string "stra", then concatenate them and convert to a string, then compare that string to strings in an array. I have read vastly that in C there are no string, only arrays of chars, but in CS50 they use string declaration type. when I run the code it gives me the folowing error

runtime error: index 4 out of bounds for type 'string [4]'

#include <cs50.h>
#include <stdio.h>
#include <string.h>

int main(void){

   string stra = "GH7";

   int x = 0;
   //extract first two chars of stra
   char strb[3] = {stra[0], stra[1], '\0'};
   //concatenate chars
   string strc = strb;

   string letters[] = {"AB","CD","ED","GH"};

   for (int i = 0, n = sizeof(letters); i < n; i++)
   {
      if (strc == letters[i])  // <--the error happens here
      {
         break;
      }
      else
      {
         x++;
      }
   }
   printf("%i", x);
}

and it gives me this error

runtime error: index 4 out of bounds for type 'string [4]'

Tormund Giantsbane
  • 355
  • 1
  • 4
  • 12

3 Answers3

5

the issue is that initialization

n = sizeof(letters)

sizeof(letters) should be divided by the size of the individual element (pointer):

n = sizeof(letters) / sizeof(*letters)

(unless you're sure that letters points to a string literal, where this is redundant, this is the best way to compute the size of a litteral array, and it even follows a possible type change)

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
0

You want to iterate over the elements 'string' array letters. To calculate the number elements the best way is to take the size of the array and divide it by the size of the first element.

See example below:

//#include <cs50.h>
#include <stdio.h>
#include <string.h>

int main(void){

    char *stra = "GH7";

    int x = 0;
    //extract first two chars of stra

    char strb[3] = {stra[0], stra[1], '\0'};

    //concatenate chars
    char *strc = strb;

    printf("strc: %s\n", strc);

    char * letters[] = {"AB","CD","ED","GH"};

    // number of element in the `letters` 

    int nr_of_elements = sizeof(letters)/sizeof(letters[0]);

    printf("sizeof letters= %d,  sizeof the element= %d   nr_of_elements= %d \n", sizeof(letters), sizeof(letters[0]), nr_of_elements);

    for (int i = 0, n = nr_of_elements;  i < n;  i++)
    {
      if (strc == letters[i])  // <--the error happens here
      {
         break;
      }
     else
      {
         x++;
      }
    }

    printf("x= %i", x);
    return 0;
}

Output:

strc: GH
sizeof letters= 32,  sizeof the element= 8   nr_of_elements= 4 
x= 4
sg7
  • 6,108
  • 2
  • 32
  • 40
0

<gratuitous rant>

The string is a lie. It is a typedef (alias) for the type char *, which is not a string. A string is a sequence of characters followed by a 0-valued terminator. Strings are stored in arrays of char (or wchar_t for "wide" strings). A char * may point to the first character in a string, or it may point to the first character in a sequence that is not a string, or it may point to a single character that is not part of any sequence. It is most definitely not a string. An object of type string contains an address, not an actual string.

Its presence in the CS50.h header is a source of confusion and an active hinderance to you learning proper C string semantics. If you have a choice in the matter, don't use it.

</gratuitous rant>

As Jean-Francois pointed out, sizeof returns the total number of bytes in an object; if you want to get the number of elements in the array, you must divide the total size of the array by the size of an individual element:

T arr[] = { /* some values of type T */ }; // for any type T
size_t count = sizeof arr / sizeof arr[0]; // or divide by sizeof *arr

Remember that sizeof is an operator, not a function - if the operand is not a type name, it doesn't need to be surrounded by parentheses (although they don't hurt).

Note that this only works with array expressions, not with pointers. Remember that under most circumstances, an expression of array type will be converted ("decay") to an expression of pointer type, and the value of the expression will be the address of the first element1. If you tried to write a function that took an array as a parameter and returned the count, something like

size_t elt_count( int arr[] )
{
  return sizeof arr / sizeof arr[0];
}

you won't get what you expect, because in this case arr is a pointer, not an array2.


  1. Unless it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array.
  2. In the context of a function parameter declaration, T a[N] and T a[] are interpreted as T *a; all three declare a as a pointer to T.

John Bode
  • 119,563
  • 19
  • 122
  • 198