Search code examples
arrayscpointerscs50implicit-conversion

CS50 Week 4 are these 2 different ways of creating strings?


from my understanding char* is a pointer to the first char byte of our allocated memory. Char z[4] creates a array of 4 chars and z is a pointer to the first char? Are these the same thing?

Does the z[4] allocate memory?

  char *s = malloc(5);
  char z[4];


Solution

  • I don't think it's possible to explain/understand these without pictures.

    char z[4];
    

    This gives you an array of 4 chars, known by the name z:

       +---+---+---+---+
    z: |   |   |   |   |
       +---+---+---+---+
    

    This can hold a string up to three characters long (leaving room for the trailing \0).

    char *s = malloc(5);
    

    The char *s part gives you a pointer to char, that can point to any character anywhere. The malloc(5) part gives you, in effect, a nameless array of 5 characters somewhere in memory (more formally, on "the heap"). And then the = (assignment) operator makes the former point to the latter. You can imagine it looking like this:

       +---------------+
    s: |       *       |
       +-------|-------+
               |
               V
             +---+---+---+---+---+
             |   |   |   |   |   |
             +---+---+---+---+---+
    

    The malloc'ed region gives you room for a string up to 4 characters long.

    Because pointers can point anywhere, you can reassign them later. For example, you could make s point to the first character of the z array, by saying

    s = &z[0];
    

    Then you'd have this picture:

             +---+---+---+---+
          z: |   |   |   |   |
             +---+---+---+---+
               ^
               |
       +-------|-------+
    s: |       *       |
       +---------------+
               
               
             +---+---+---+---+---+
             |   |   |   |   |   |
             +---+---+---+---+---+
    

    But now we come to the "fun" part. It's going to sound strange or absurd at first, but once you get it, suddenly C's handling of pointers and arrays (and therefore strings) is going to make much more sense. What if you say

    s = z;
    

    At first this may make no sense. It looks like we're trying to take an array (on the right) and assign it to a pointer (on the left). That looks like a type mismatch. Also you may have heard (truly) that you cant assign arrays in C. So this looks doubly impossible. But, by special dispensation of Dennis Ritchie, you can do this, and it is, by definition, exactly the same as if you had said

    s = &z[0];
    

    That is: Whenever you try to use an array in an expression, what you get is a pointer to the array's first element. That is, in this example, just as if you you had said &z[0].

    So, it's true, there are two ways of slinging strings around in C: as arrays, and as pointers. You can do it the array way and say

    char y[] = "cat";
    char z[4];
    strcpy(z, y);
    

    Or you can do it the pointer way and say

    char *s = "bear";
    char *t;
    
    t = s;
    

    Both of these "assign" one string to the other, but one of them does it by copying characters (using strcpy), and one of them does it by just manipulating pointers.

    I also glossed over a little point. When I said

    char y[] = "cat";
    

    the compiler initialized the array for me, giving me this:

       +---+---+---+---+
    y: | c | a | t | \0|
       +---+---+---+---+
    

    But when I said

    char *s = "bear";
    

    the compiler created that string "bear" for me somewhere, in anonymous memory, sort of like (but definitely not exactly like) when I called malloc:

       +---------------+       +---+---+---+---+---+
    s: |       *-------------->| b | e | a | r | \0|
       +---------------+       +---+---+---+---+---+
    

    You can also mix'n'match, up to a point. As we saw earlier, you can make a pointer point to an array, so this is fine:

    t = z;
    

    When you copy strings, however, you have to make sure theres enough space. If you said

    strcpy(z, "kangaroo");
    

    for example, things might explode, because "kangaroo" has more characters than array z can hold.

    You also have to be careful with constant strings. If you've just said

    char *s = "bear";
    

    you cannot say

    strcpy(s, "kangaroo");
    

    for two reasons: One, the anonymous array that s points to isn't big enough, but perhaps even more importantly, the anonymous array that s points to is constant, and you're not allowed to scribble on it.