Search code examples
ccs50

Integer to pointer type conversion


int count_words(string word)
{
    string spaces = "";
    int total_words = 1;
    int i, j = 0 ;
    for (i = 0;  i < strlen(word); i++)
    {
        strcpy(spaces, word[i]);
        if (strcmp(spaces, " ") == 0)
        {
            total_words = total_words + 1;
        }
    }
    return total_words;
}

I am trying to make a function in c that gets the total number of words, and my strategy is to find the number of spaces in the string input. However i get an error at strcpy about integer to ptrtype conversion,. I cant seem to compare the 2 strings without getting the error. Can someone explain to me whats how the error is happening and how I would go about fixing it. The IDE is also suggesting me to add an ampersand beside word[i] but it then makes a segmentation fault output


Solution

  • You need to learn a little more about the distinction between characters and strings in C.

    When you say

    strcpy(spaces, word[i]);
    

    it looks like you're trying to copy one character to a string, so that in the next line you can do

    if (strcmp(spaces, " ") == 0)
    

    to compare the string against a string consisting of one space character.

    Now, it's true, if you're trying to compare two strings, you do have to call strcmp. Something like

    if (spaces == " ")        /* WRONG */
    

    definitely won't cut it.

    In this case, though, you don't need to compare strings. You're inspecting your input a character at a time, so you can get away with a simple character comparison instead. Get rid of the spaces string and the call to strcpy, and just do

    if (word[i] == ' ')
    

    Notice that I'm comparing against the character ' ', not the string " ". Using == to compare single characters like this is perfectly fine.

    Sometimes, you do have to construct a string out of individual characters, "by hand", but when you do, it's a little more elaborate. It would look like this:

    char spaces[2];
    spaces[0] = word[i];
    spaces[1] = '\0';
    if (strcmp(spaces, " ") == 0)
        ...
    

    This would work, and you might want to try it to be sure, but it's overkill, and there's no reason to write it that way, except perhaps as a learning exercise.

    Why didn't your code

    strcpy(spaces, word[i]);
    

    work? What did the error about "integer to pointer conversion" mean? Actually there are several things wrong here.

    1. It's not clear what the actual type of the string spaces is (more on this later), but it has space for at most 0 characters, so you're not going to be able to copy a 1-character string into it.
    2. It's also not clear that spaces is even writable. It might be a constant, meaning that you can't legally copy any characters into it.
    3. Finally, strcpy copies one string to another. In C, although strings are arrays, they're usually referred to as pointers. So strcpy accepts two pointers, one to the source and one to the destination string. But you passed it word[i], which is a single character, not a string. Let's say the character was A. If you hadn't gotten the error, and if strcpy had tried to do its job, it would have treated A as a pointer, and it would have tried to copy a string from address 65 in memory (because the ASCII value of the character A is 65).

    This example shows that working with strings is a little bit tricky in C. Strings are represented as arrays, but arrays are second-class citizens in C. You can't pass arrays around, but arrays are usually referred to by simple pointers to their first element, which you can pass around. This turns out to be very convenient and efficient once you understand it, but it's confusing at first, and takes some getting used to.

    It might be nice if C did have a built-in, first-class string type, but it does not. Since it does not, C programmers myst always keep in mind the distinction between arrays and characters when working with strings. That "convenient" string typedef they give you in CS50 turns out to be a bad idea, because it's not actually convenient at all -- it merely hides an important distinction, and ends up making things even more confusing.