3

So I know that a string is just an array of characters that are stored consecutively in a computer's memory.

I also know that in order to find out the location of a string, you just have to go to the location of the first character as its consecutive and the string ends when the program or function encounters the \0 character.

But what I don't understand is :

  1. char* s = "HI!";
    

Does it create an array of 4 characters? Or is it just a pointer pointing to the starting character location? Or is it doing both?

2.

    char* name = "BEN";
    printf("%c %c\n", *(name + 1), *name + 1);

Why do they both give two different outputs (E and C), instead of both giving E?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
King Brain
  • 57
  • 6
  • 1
    "Does it create an array of 4 characters?" --> "It", the compiler, forms a `char[4]` with the string `"HI!"` in it. `s` gets the address of the first element. Need more than that? – chux - Reinstate Monica Jul 11 '23 at 19:23
  • 3
    number 2 is a classic case of [operator precedence](https://en.cppreference.com/w/c/language/operator_precedence) – UnholySheep Jul 11 '23 at 19:24
  • 1
    `"HI!"` by itself is an array of 4 characters. `char* s` then points to its first element. – HolyBlackCat Jul 11 '23 at 19:25
  • 1
    King Brain, Why do you expect `'B' + 1` to give `'E'`? – chux - Reinstate Monica Jul 11 '23 at 19:25
  • Ah i see....the compiler does it automatically huh. What about the 2nd question? Also is there a way to print the address of the pointer itself? – King Brain Jul 11 '23 at 19:25
  • 1
    To print the address of any object, convert the object address to `void *` and use `"%p"`: `printf("%p\n", (void*) &object);`. – chux - Reinstate Monica Jul 11 '23 at 19:26
  • I see so thats why its printing C....thanks a lot for the info. – King Brain Jul 11 '23 at 19:27
  • (void*)name and *name, in printf, both give me the address of B. Is it possible to get the address of the pointer that is holding the address of B? – King Brain Jul 11 '23 at 19:29
  • 1
    `(void *)&name` is the address of the `name` variable. – Barmar Jul 11 '23 at 19:32
  • 1
    *"I know that a string is just an array of characters that are stored consecutively in a computer's memory."* In your previous questions, it has been said that the distinction between an array of characters and a string, is that the latter ends with a `0` or `'\0'` element. Without that it is only an array, not the special case of string. – Weather Vane Jul 11 '23 at 20:17
  • 1
    See [Correct format specifier to print pointer or address?](https://stackoverflow.com/q/9053658/15168) – Jonathan Leffler Jul 11 '23 at 20:28
  • 5
    Note that the `cs50.h` header includes `typedef char *string;` — a controversial decision. Your question doesn't really ask about this, though. The references to "string" seem to be to the generic concept defined in the C standard [§7.1.1 Definitions of terms ¶1](http://port70.net/~nsz/c/c11/n1570.html#7.1.1p1) rather than to the typedef in the `cs50.h` header. – Jonathan Leffler Jul 11 '23 at 20:33
  • 3
    @JonathanLeffler I suspect that OP now understands from their previous questions that `string` is a cs50 invention (supposed convenience). To King Brain: I did not do cs50, but at first I did find it helpful with more complicated syntax to `typedef` a pointer. Later I understood why it isn't helpful, see [Is it a good idea to typedef pointers?](https://stackoverflow.com/questions/750178/is-it-a-good-idea-to-typedef-pointers) – Weather Vane Jul 11 '23 at 21:05
  • Thanks a lot for all the advice. Just wanted to ask one last thing....if char* name = "Ben'; does printf("%p", &name); print the address of the pointer itself? Cuz i was getting two different addresses with and without the & in front of name – King Brain Jul 11 '23 at 21:27
  • The variable `name` is a pointer, so `printf("%p", &name);` would show where the pointer is *stored* (a pointer to a pointer haha) , but `printf("%p", name);` shows the pointer. More properly, it should be `printf("%p", (void*)name);` – Weather Vane Jul 11 '23 at 21:46

3 Answers3

3

In this declaration

char* s = "HI!";

Two entities are created.

The first one is the string literal "HI!" which has static storage duration and array type char[4]. (In C++ it has constant character array type const char[4], in opposite to C.)

You can check this using printf

printf( "sizeof( \"HI!\" ) = %zu\n", sizeof( "HI!" ) );

Here the character array is used as an initializer of the pointer s. In this case it is implicitly converted to the first element of a pointer and the pointer s points to the address of the first element of the array.

As for this code snippet

char* name = "BEN";
printf("%c %c\n", *(name + 1), *name + 1);

The expression name + 1 has type char * and points to the second character of the string literal "BEN" (thus 'E'), due to the pointer arithmetic. Dereferencing the pointer expression like *(name + 1) you get the symbol of the string literal pointed to by the expression. Actually, the expression *(name + 1) is the same as name[1] that is the same as 1[name].:)

As for this expression *name, dereferencing the pointer name you get the first symbol 'B' of the string literal. Then, 1 is added to the internal code of the symbol ( *name + 1 ), so the expression takes the value of the next symbol after 'B', which is 'C'. The expression ( *name + 1 )is equivalent to the expressionname[0] + 1`.

Using the subscript operator like name[1] and name[0] + 1 makes the expressions more clear.

I think it would be interesting for you to know that the call of printf may be rewritten using only the original string literal. Some examples:

printf("%c %c\n", *( "BEN" + 1), *"BEN" + 1);

or

printf("%c %c\n", "BEN"[1], "BEN"[0] + 1);

or even

printf("%c %c\n", 1["BEN"], 0["BEN"] + 1);
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

But what I don't understand is :

char* s = "HI!";

Does it create an array of 4 characters? Or is it just a pointer pointing to the starting character location? Or is it doing both?

The right side of the assignment, = "HI!"; provisions a constant array of chars (4 including the null character). Where/how the memory is allocated for these 4 chars is not of concern. The compiler is free to choose where "HI!" lives and how long it lives for.

The left side of the assignment: char *s = declares a local pointer on the stack to point to the first character of the array (the 'H')

char* name = "BEN";

printf("%c %c\n", *(name + 1), *name + 1);

Why do they both give two different outputs (E and C), instead of both giving E?

  • name is a pointer. It points to the address of the letter B in that string.
  • name+1 is a pointer to one character past B in that string, in this case, E.
  • *name is the value held at the address pointed to by name. In other words the character 'B'.
  • *name + 1 is the same as (*name) + 1 or 'B' + 1 or 'C'. You're adding 1 to the value, not the address in this expression.
  • *(name + 1), evaluates to the second character in the string referenced by name. Or 'E' as you might expect
selbie
  • 100,020
  • 15
  • 103
  • 173
1
  1. In char* s = "HI!"; then "HI!" is a string literal. s points at the H. The string literal is 4 char long (including the terminating \0). Another (non-idiomatic) way to look at it:
    char(*s)[4] = &"HI!";
    
    ... and here s is a pointer to a char[4].
  2. In your second example, it's about in which order you do things, the operator precedence.
    char* name = "BEN";
    printf("%c %c\n", *(name + 1), *name + 1);
    
    • (name + 1) adds 1 to the char* name so you get a pointer pointing at the E. After that you dereference the pointer with * and get E.
    • *name dereferences the pointer, which points at B and then you + 1 to it, making it C.

It's the same as doing this:

printf("%c %c\n", name[1], name[0] + 1);
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108