Search

6.8b — C-style string symbolic constants

C-style string symbolic constants

In the lesson 6.6 -- C-style strings, we discussed how you could create and initialize a C-style string, like this:

C++ also supports a way to create C-style string symbolic constants using pointers:

While these above two programs operate and produce the same results, C++ deals with the memory allocation for these slightly differently.

In the fixed array case, the program allocates memory for a fixed array of length 5, and initializes that memory with the string “Alex\0”. Because memory has been specifically allocated for the array, you’re free to alter the contents of the array. The array itself is treated as a normal local variable, so when the array goes out of scope, the memory used by the array is freed up for other uses.

In the symbolic constant case, how the compiler handles this is implementation defined. What usually happens is that the compiler places the string “Alex\0” into read-only memory somewhere, and then sets the pointer to point to it. Multiple string literals with the same content may point to the same location. Because this memory may be read-only, and because making a change to a string literal may impact other uses of that literal, best practice is to make sure the string is const. Also, because strings declared this way are persisted throughout the life of the program, we don’t have to worry about scoping issues. Thus, the following is okay:

In the above code, getName() will return a pointer to C-style string “Alex”. This is okay since “Alex” will not go out of scope when getName() terminates, so the caller can still successfully access it.

Rule: Feel free to use C-style string symbolic constants if you need read-only strings in your program, but always make them const!

std::cout and char pointers

At this point, you may have noticed something interesting about the way std::cout handles pointers of different types.

Consider the following example:

On the author’s machine, this printed:

003AF738
Hello!
Alex

Why did the int array print an address, but the character arrays printed strings?

The answer is that std::cout makes some assumptions about your intent. If you pass it a non-char pointer, it will simply print the contents of that pointer (the address that the pointer is holding). However, if you pass it an object of type char* or const char*, it will assume you’re intending to print a string. Consequently, instead of printing the pointer’s value, it will print the string being pointed to instead!

While this is great 99% of the time, it can lead to unexpected results. Consider the following case:

In this case, the programmer is intending to print the address of variable c. However, &c has type char*, so std::cout tries to print this as a string! On the author’s machine, this printed:

Q╠╠╠╠╜╡4;¿■A

Why did it do this? Well, it assumed &c (which has type char*) was a string. So it printed the ‘Q’, and then kept going. Next in memory was a bunch of garbage. Eventually, it ran into some memory holding a 0 value, which it interpreted as a null terminator, so it stopped. What you see may be different depending on what’s in memory after variable c.

This case is somewhat unlikely to occur in real-life (as you’re not likely to actually want to print memory addresses), but it is illustrative of how things work under the hood, and how programs can inadvertently go off the rails.

6.9 -- Dynamic memory allocation with new and delete
Index
6.8a -- Pointer arithmetic and array indexing

49 comments to 6.8b — C-style string symbolic constants

  • Boyan

    On the first line below the "std::cout and char pointers" headline - I believe you meant to write std::cout instead of std::string. As in "At this point, you may have noticed something interesting about the way std::COUT handles pointers of different types.”

  • Can you add a lesson describing smart pointers. I found this in primer(C++ primer) but unable to understand what it is.
    Thanks.

  • Awesome…we’ll wait.
    May be a typo here:
    "Why did the int array print an address, but the strings printed strings?
    should be: "Why did the int array prints an address, but the char array printed string?"

  • JJ

    So when do you prefer "const char* string" over "std::string string". Is it just personally preference or is there a time and place for each of them?

    • Alex

      Personally, I only use const char* if I’m hardcoding a string that will only be displayed (e.g. the application name).

      Otherwise, std::string for everything (or my own string class).

  • vish

    Hey!! alex please help me to figure out run time error in this program i just don’t know program is running smoothly but still there is some run time error.
    #include<iostream>
    #include<string>
    using namespace std;
    int main(){

        int cases,count=1,shift;
        string a;
        int arr[27];
        cout<<"ENTER NO OF CASEA"<<endl;
        cin>>cases;
        while(count<=cases){
            cin>>a;
            cin>>shift;
            for( int i=0;i<a.size();i++){
                arr[i]=a[i];
                
                arr[i]=arr[i]-shift;
                if(arr[i]>90)
                arr[i]=arr[i]-90+64;
                if(arr[i]<65)
                arr[i]=90-64+arr[i];
                a[i]=arr[i];
            }
            cout<<a<<endl;
            count++;
        }
        return 0;
        
    }
    Thank you.

    • Alex

      What is this program supposed to do?

      • vish

        very much thanks for reply.
        the problem  is to shift each letter 2 places further through the alphabet (e.g. ‘A’ shifts to ‘C’, ‘R’ shifts to ‘T’, etc.). At the end of the alphabet we wrap around, that is ‘Y’ shifts to ‘A’. We can, of course, try shifting by any number.
        The input contains several test cases. The first line of input contains an integer variable that indicates the number of test cases. Each test case is composed by two lines. The first line contais a string that is a codified sentence. This string will contain between 1 and 50 characters, inclusive. Each character is an uppercase letter (‘A’-‘Z’), that is the codified sentence to this modified string. The second line contains the number of right shift, this value is between 0 and 25, inclusive.

        • Alex

          Okay then.

          First, you need much better prompting to the user as to how to use the program.

          Second, this program desperately needs some comments indicating what it’s doing.

          Third, why are you using variable arr? Why don’t you just modify variable a?

          Fourth, arr[i] -= arr[i] - 90 + 64; could be rewritten as arr[i] -= 32; which is much easier to understand.

          Finally, it looks like you’re handling upper case letters okay, but not lower case letters.

  • vish

    hey thanks alex..
    when code gets longer these small error or small imporatnt issue becomes nightmare
    i modified my program according to your suggestion and it saves a lot of runtime and runtime error and preincrement helps too it saves time and one thing more i m missing here was to define limit of no of shifts.. it gives some direction to while loop.
    if(shift>25||shift<0)
            break;  
    and yes you are absolutely correct i saved my code without commenting and day after i opene it again it takes me years to realize what is going on with my code? what is this?. I will never forgot to commenting my code now i am finding how all these things are life saver.

  • Diksha

    Alex I am unable to understand this
    "However &c has type char*".
    Isn’t &c an address. So how come it is a pointer.

    • Alex

      The address-of operator (&) returns the address as a pointer derived from underlying type (e.g. taking the address of an int variable returns an int pointer).

  • PN

    I’m using Xcode 7.1 - when I try:

    I don’t get the error that you did. Instead I get ‘Q’ without the rest. Is this something that XCode has built-in to fix that issue?

    • Alex

      I doubt it. It’s more likely that the memory address after variable c contained a 0, which std::cout interpreted as a terminator, so it only printed the ‘Q’ and stopped.

  • Javad

    According to the tutorial, the pointer myString in the following snippet is supposed to point to a ‘constant’ string.

    const char *myString = "Name";

    As I understand, a ‘constant’ is not modifiable. What confuses me is that if myString points to a ‘constant’ string why can I change it using the following snippet:

    const char *myString = "Name";
    myString = "Andy";
    std::cout << myString;

    I do not get any compiler errors and it prints out:
    Andy

    Also I think there is something wrong with the following sentence, or there is something that I do not get it:

    “Multiple string literals with the same content may point to the same location. Because there’s no guarantee that this memory will be writable, best practice is to make sure the string is const.”

    • Javad

      Alright! I think I resolved my confusion.

      In the assignment
      myString="Andy";
      only the pointer myString changes and points to a new string. But the constant string "Name" does not change in the memory. However, this brings up another question.

      After the above assignment I loose the address of the constant string "Name" which is sitting somewhere in the memory. Since this string was defined to be constant, its corresponding memory should not be assigned to another application as long as it does not go out of scope. Does this imply memory leak?

      • Alex

        > After the above assignment I loose the address of the constant string “Name” which is sitting somewhere in the memory.

        Yes, unless you’ve copied the address into another pointer, once you’ve assigned myString to another string literal, the address of the original string literal is lost.

        > Since this string was defined to be constant, its corresponding memory should not be assigned to another application as long as it does not go out of scope. Does this imply memory leak?

        Not really. A “memory leak” means we’ve lost track of some bit of dynamically allocated memory that now can’t be returned to the OS for reassignment to another program while your program is running.

        String literals aren’t dynamically allocated, and there’s no way to return them to the OS. They get set up when your program starts, and destroyed when your program ends, so your program owns that memory for the entire time it’s running, whether you’re using it or not.

    • Alex

      The thing to note here is that myString points to a const string (of type const char*). It is not a const pointer itself! This means the pointer can be changed to point at another string, which you do in your example by assigning it to a different string literal.

      > “Multiple string literals with the same content may point to the same location. Because there’s no guarantee that this memory will be writable, best practice is to make sure the string is const.”

      Let’s say I have this:
      char *name1 = “Alex”;
      char *name2 = “Alex”;

      You’d expect if I did this: name1[1]=’r’, that name1 would now be “Arex” and name2 would now be “Alex”. But some compilers will only keep one copy of string literal “Alex”, and set both name1 and name2 to point at that literal. So when you change the value of name1, you end up inadvertently changing the value of any other string pointing to that location (in this case, name2).

      Because of this, it’s really only safe to use C-style strings for “read-only” purposes.

  • dex

    Hi Alex,

    I am just a little confused about the program below:

    In the previous lessons, you taught that pointers only hold memory address thus, we can’t initialized it with a value other than the memory address of that value. But how come the pointer "myName" is initialized with a string. Although, arrays are somehow identical with pointers as the previous lessons denotes but different is size etc., and C-strings are of array type, is this has something to do with it?

    Thanks.

    • Alex

      String literal “Alex” is treated as a C-style array of const chars. As you’ve learned, arrays can decay into pointers to the first element of the array. Thus, const char* myName = “Alex” assigns myName the address of the first character in “Alex”. We can then pass this to std::cout, which knows that char pointers should be printed as strings.

  • dex

    Hi Alex,

    Thanks for the reply. Does it mean that the string literal "Alex", was put in a char array "variable" somewhere in the memory address prior to assigning it to the pointer? I am somehow confused how it skips the process of assigning this string literal "Alex" in a char array "variable" initialization. But the rest of the process I now understand.

  • dex

    Hi Alex,

    Thanks for the clarification. I understand it more clearly now. Thanks again. You’ve done a great job with this tutorial.

  • Lokesh

    There’s a semi-colon at the end of main() block in "std::cout and char pointers" section.

  • Soul

    "Because there’s no guarantee that this memory will be writable, best practice is to make sure the string is const."

    Do you mean unwritable? If you meant that you would WANT it to be writable, wouldn’t const defeat that purpose?

    EDIT: I read a post of yours above and now get it. I’d like to suggest (just an innocent suggestion, not trying to be rude) that perhaps you mention that you make it const so it doesn’t become affected by what happens to other entries.

  • Kenneth Andersen

    Hey Alex, thx for some awesome articles about c++

    I’m a little confused about the usage of const. It states that it places the string into a read-only memory. But I think that I’m still able to change whats on that memory address. For example if I do the following. I’m pretty sure that I’m misunderstanding something here.
        

    Can you give an example of something that you can do without const that isn’t possible when you use the const keyword.

        cout << myName;

    • Alex

      This means we’re allocating a normal (non-const) pointer named myName to a C-style string of type const char. This means the pointer treats the value being pointed to as const. However, because the pointer itself is a non-const pointer, it can be changed to point at a different string (which is what you’re doing when you assign it to string “Doe”.

      With the above string, you couldn’t do this:

  • Michael

    Help!
    How do I use the same pointer accross the scopes of multiple functions

    Thanks

    • Alex

      If you want a pointer to be available in the scope of multiple functions, you have a few options:
      1) Best option: pass it as a parameters to the functions that need it
      2) Worst option: declare it as a global variable

  • Krishnamurthy

    Hi Alex,

    One doubt regarding your explanation,

    > “Multiple string literals with the same content may point to the same location. Because there’s no guarantee that this memory will be writable, best practice is to make sure the string is const.”

    Let’s say I have this:
    char *name1 = “Alex”;
    char *name2 = “Alex”;

    You’d expect if I did this: name1[1]=’r’, that name1 would now be “Arex” and name2 would now be “Alex”. But some compilers will only keep one copy of string literal “Alex”, and set both name1 and name2 to point at that literal.

    I tried to execute this scenario which result in segmentation fault.
    #include<iostream>
    #include<cstring>
    #include<stdio.h>
    using namespace std;

    int main()
    {
        char *name1 = "Alex";
        char *name2 = "Alex";
        name1[1] = ‘r’;
        cout<<name1<<endl;
        cout<<name2<<endl;
    }

    Output:
    +++++++
    Segmentation fault

    is the segmentation fault is because i try to change the read only memory? will compiler doesnot issue any warning regarding this?

    Thanks and Regards,
    Krishna

  • Elpidius

    Hi Alex, you’re doing a wonderful job with these tutorials!!!

    In one of the comments you mentioned:
    "String literal “Alex” is treated as a C-style array of const chars. As you’ve learned, arrays can decay into pointers to the first element of the array. Thus, const char* myName = “Alex” assigns myName the address of the first character in “Alex”."

    However because std::cout prints char pointers as strings I casted the pointer to a const general pointer type using a static_cast, and found that this was indeed the case!

    We can see proof of this in the following code:

    On my machine the above printed:
    Alex

    010A9B30

    010A9B30
    010A9B31
    010A9B32
    010A9B33

    As you can see the address of "Alex", which decays into a pointer to the first element of the array (in this case ‘A’), is exactly the same as the address of ‘A’.

    Perhaps you could consider adding this example to the lesson (as well as your comment I’ve quoted above), to facilitate the comprehension of C-style symbolic constants.

    • Elpidius

      Edit: in the last paragraph I was meant to write "… to facilitate the comprehension of C-style string symbolic constants".

      • Alex

        Thanks for validating this and providing some other code for other readers of the site! Since my original comment was made as a comment, I think I’ll leave this snippet in the comment section as well.

        • Elpidius

          You’re welcome! The only reason I suggested adding the code to the lesson is because when I read through your lessons I don’t always read through the comments. Maybe you could make a reference to the code I’ve provided. However, I’ll leave that up to you 😉

  • David

    Your website is awesome. Incredible!

  • Joshua

    Hi Alex, many thanks for the efforts put into these tutorials. They’re so much clearer on the concepts than the books I’ve came across!

    I understand that std::cout implicitly inteprets a char* pointer as the array’s string value. In this case, how do I find out what the memory address of the read only memory variable created as the & operator only gives me the address of the pointer? Thanks.

    • Alex

      You could try casting it to a void pointer and printing that/

  • Hey Alex! I tried this:

    and what I got was:
    Alex
    lex
    ex
    x
    (blank)

    Could it be that cout prints the array output from the point you specified onward, instead of only the array element?

    • Alex

      In general, no.

      If you remove the ampersands from in front of the array elements, it’ll print each array element (of type char) individually. However, with the ampersand, you’re passing std::cout a pointer to a char, which it will interpret as a C-style string, and print all of the array elements onwards until it encounters a null terminator.

      This only happens for char pointers due to the way std::cout interprets those. std::cout won’t exhibit that behavior for pointers to other types of types.

  • Matt

    Third paragraph from the top, you wrote:
    " Also because strings declared this way are persisted throughout the life of the program, we don’t have to worry about scoping issues."

    I think there should be a comma after "also".

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter