Search

6.6 — C-style strings

In lesson 4.4b -- An introduction to std::string, we defined a string as a collection of sequential characters, such as “Hello, world!”. Strings are the primary way in which we work with text in C++, and std::string makes working with strings in C++ easy.

Modern C++ supports two different types of strings: std::string (as part of the standard library), and C-style strings (natively, as inherited from the C language). It turns out that std::string is implemented using C-style strings. In this lesson, we’ll take a closer look at C-style strings.

C-style strings

A C-style string is simply an array of characters that uses a null terminator. A null terminator is a special character (‘\0’, ascii code 0) used to indicate the end of the string. More generically, A C-style string is called a null-terminated string.

To define a C-style string, simply declare a char array and initialize it with a string literal:

Although “string” only has 6 letters, C++ automatically adds a null terminator to the end of the string for us (we don’t need to include it ourselves). Consequently, mystring is actually an array of length 7!

We can see the evidence of this in the following program, which prints out the length of the string, and then the ASCII values of all of the characters:

This produces the result:

string has 7 characters.
115 116 114 105 110 103 0

That 0 is the ASCII code of the null terminator that has been appended to the end of the string.

When declaring strings in this manner, it is a good idea to use [] and let the compiler calculate the length of the array. That way if you change the string later, you won’t have to manually adjust the array length.

One important point to note is that C-style strings follow all the same rules as arrays. This means you can initialize the string upon creation, but you can not assign values to it using the assignment operator after that!

This would be the conceptual equivalent of the following nonsensical example:

Since C-style strings are arrays, you can use the [] operator to change individual characters in the string:

This program prints:

spring

When printing a C-style string, std::cout prints characters until it encounters the null terminator. If you accidentally overwrite the null terminator in a string (e.g. by assigning something to mystring[6]), you’ll not only get all the characters in the string, but std::cout will just keep printing everything in adjacent memory slots until it happens to hit a 0!

Note that it’s fine if the array is larger than the string it contains:

In this case, the string “Alex” will be printed, and std::cout will stop at the null terminator. The rest of the characters in the array are ignored.

C-style strings and std::cin

There are many cases where we don’t know in advance how long our string is going to be. For example, consider the problem of writing a program where we need to ask the user to enter their name. How long is their name? We don’t know until they enter it!

In this case, we can declare an array larger than we need:

In the above program, we’ve allocated an array of 255 characters to name, guessing that the user will not enter this many characters. Although this is commonly seen in C/C++ programming, it is poor programming practice, because nothing is stopping the user from entering more than 255 characters (either unintentionally, or maliciously).

The recommended way of reading strings using cin is as follows:

This call to cin.getline() will read up to 254 characters into name (leaving room for the null terminator!). Any excess characters will be discarded. In this way, we guarantee that we will not overflow the array!

Manipulating C-style strings

C++ provides many functions to manipulate C-style strings as part of the <cstring> library. Here are a few of the most useful:

strcpy() allows you to copy a string to another string. More commonly, this is used to assign a value to a string:

However, strcpy() can easily cause array overflows if you’re not careful! In the following program, dest isn’t big enough to hold the entire string, so array overflow results.

In C++11, strcpy() was deprecated in favor of strcpy_s, which adds a new parameter to define the size of the destination:

Another useful function is the strlen() function, which returns the length of the C-style string (without the null terminator).

The above example prints:

My name is: Alex
Alex has 4 letters.
Alex has 20 characters in the array.

Note the difference between strlen() and sizeof(). strlen() prints the number of characters before the null terminator, whereas sizeof() returns the size of the entire array, regardless of what’s in it.

Other useful functions:
strcat() -- Appends one string to another (dangerous)
strncat() -- Appends one string to another (with buffer length check)
strcmp() -- Compare two strings (returns 0 if equal)
strncmp() -- Compare two strings up to a specific number of characters (returns 0 if equal)

Here’s an example program using some of the concepts in this lesson:

Don’t use C-style strings

It is important to know about C-style strings because they are used in a lot of code. However, now that we’ve explained how they work, we’re going to recommend that you avoid them altogether whenever possible! Unless you have a specific, compelling reason to use C-style strings, use std::string (defined in the <string> header) instead. std::string is easier, safer, and more flexible.

Rule: Use std::string instead of C-style string

6.7 -- Introduction to pointers
Index
6.5 -- Multidimensional Arrays

67 comments to 6.6 — C-style strings

  • sandor

    Hello, I’ve got a question about the cin.getline() function.
    For example:
    char string[10];
    cin.getline(string, 10);
    cout
    If I know enter more than 10 chars the program just runs through and the first entered 10 chars doesnt get shown.How can I force the program to show the first 10 chars?

  • In your example, getline() should only show the first 9 characters you enter (the 10th is used for the terminator) and ignore the rest.

    For example, if I run this program:

    and I type 123456789abcdefghijk as input, the program outputs:

    If you actually want to show 10 chars instead of 9, you’ll have to change the size of the buffer to 11:

  • sandor

    Sorry, that was a off-by-one thinking mistake of me : ) But it doesnt really matter how many chars are shown. Its just that when I run this program, and enter more than the “maximum” of chars, it doesnt show them, but instead runs through, terminating immediatly (maybe it shows them quick, but if, then only for a millisecond). My actual question is now, how can I make the window stay open and show me the enterd chars.
    regards

    • Sandor, I believe what’s happening is that all of the keys you are entering are going into an I/O buffer, and the code you wrote is only reading 10 of them. When a program terminates, some compilers hold the window open until is key is pressed. It sounds like your compiler is doing this, but then a key from the I/O buffer is causing it to close immediately.

      I am not sure if this would work, but at the end of your program (right before main returns), try adding this:

    • Jacob Perkins

      In Visual Studio, setting the linker’s subsystem to console should fix your problem.

  • Cody

    Shouldn’t

    copy at most 49 characters to prevent the null terminator from being overwritten.

    • Cody,

      In most cases, it is a good idea to copy 1 less than the number of characters in the buffer (in this case, 49) and then explicitly ensure the last character is a null terminator. I have updated the example.

  • Abhishek

    char szSource[] = “Copy this!”;
    char szDest[50];
    strncpy(szDest, szSource, 49); // copy at most 49 characters (indices 0-48)
    szDest[49] = 0; // ensures the last character is a null terminator
    cout

    In this example you have assigned 0(zero) to a char.Will the compiler automatically cast 0 to ‘\0′?

    How about writing szDest[49]=’\0’;

    or szDest[49]=static_cast(0)

    Does cin.getline() place the null character automatically?

    char szString[255];
    cin.getline(szString, 255);
    cout

    • Yes, the compiler should treat 0 and ‘\0’ as the same.

      So:
      szDest[49] = 0;
      szDest[49] = ‘\0’;
      szDest[49] = static_cast(0);

      All should work identically.

      cin.getline() reserves one space for a null terminator, so it does place it automatically.

  • Chad

    that program will only read in my first name. How do you accept strings with spaces in them?

    • There’s a special version of getline() that you can use to read in string variables with spaces:

      • devpreet singh

        can we use this getline()function on array(c style strings) like this :
                
                 char szArray[255];      
             getline(cin, szArray);            or any other way or not?

        even if we use your above snippet:

                using namespace std;
                string strString;
                getline(cin, strString);

        here even after using statement " using namespace std;"  ,i think it should be " std::string "in place of "string" and std::getline in place of getline <IF I"M not wrong>

  • Stuart

    My compiler says that “strncpy” may be unsafe and that to consider using “strncpy_s” instead.
    What’s the difference?

    • strncpy is a standard function call that copies n bytes of a string from source to destination. Microsoft decided that this function was not safe enough, so they deprecated it in the latest version of their compiler, and replaced it with strncpy_s. The two functions are identical, except strncpy_s takes an additional parameter that is the size of the destination buffer. strncpy_s is currently a non-standard function and may not be portable.

      Personally, I’d avoid both and use a string class or std::string.

  • Jeffey

    in the code

    string strString;

    it is setting string to a variable right? How come string is not considered a “keyword”? Like instead of asking the user. I could do the following.

    string strString;
    strString = ("jeffey");

    this work the same as all other variables.

    also is there a way I can set my compiler settings to recognize the word “string” so that it shows up as a different color. I do use the text colors and rely on them a lot when looking at code. I want the word “string” to stand out from normal text.

  • string strString; is simply declaring a variable of type std::string. If I’m not mistaken, std::string will auto-initialize to the empty string if not provided a value. string isn’t a keyword because it wasn’t built into the language -- it’s part of the standard library.

    As far as I know, there isn’t a way to make string show up in a different color in Visual Studio or Code::Blocks.

    • jeremy

      In Code::Blocks,
      Go To “Settings” > “Editor” > “Syntax highlighting” > “Keywords…”
      Add “string” to the list.
      It will now appear as a keyword like “int”.

  • som shekhar

    if i use like this :
    string sName;
    then this variable doesnt take blank spaces;

    for ex;if i enter a som shekhar in the variable sName, then it prints only som
    y it is like that?

    • It has to do with the way the >> operator is implemented. Operator >> will extract characters until it hits whitespace, then it will stop.

      The reasons for this are somewhat complex -- it is discussed further in chapter 13.2 on the lesson on the >> operator.

      In the meantime, if you want to read in a string with whitespaces, you can do this:

      • som shekhar

        now i have done the same but hte problem is that i have to hit the enter key twice…
        my code is

  • When you use cin.getline, you make the string a maximum amount of 255 - surely there’s a huge chance of so much wasted memory? Is there no way to prevent this?

    • The memory isn’t really wasted, it’s just used temporarily and then gets returned to the stack when the function exits. The bigger problem is the possibility of overflowing the buffer.

      If you want to avoid using the fixed size buffer, you can use the getline() function with a std::string.

  • Hey, I have a quick question… Let’s say we have a function Fred

    Now I need to make a function Barney

    Which calls Fred and returns the result as an null-terminated-c-string. How would I go about this?

  • csvan

    In the past, I have been giving thought to the question of resource overheads when using std::string as opposed to cstrings. Just how big is this overhead in reality, and could it be preferable to use cstrings rather than std::string in code where there will be no “heavy” use of strings, in order to improve overall performance? Maybe the same goes for std::vector as opposed to arrays?

    I

    • Alex

      There’s likely a little overhead to using std::string instead of C-style strings, but not enough to worry about in all but the most extreme cases.

  • Frank

    I added to your example program just for giggles and i thought i would share my minor extension. by the way alex this is a great tutorial and i am learning a lot but i am still struggling a bit with writing a coherent program. perhaps if there were a few example programs (3-4 with explainations of what each part does ect.) at the end of each chapter just for us to copy? this would help me out tremendously to grasp what you are telling us in the sections.

    here is the code:

  • Allan

    How about something on working with strings?
    I need to add two strings together to create one longer string.

    Also when comparing strings can I just ask if string1==string2 or is there a strcompare function?

    I’m a newbie writing my first program and referencing your site.

    Thanks,
    Al

    • Alex

      You can use strncat to append one string to another, and strcmp to compare two strings.

      But you’re better off using std::string. Then you can use operator+ or operator+= to append strings, and operator== to compare. Much easier and more intuitive!

  • DaBlackIce

    I kind of found out what was wrong. Apparently it’s not the do while loop.

    If you run this program after putting in the amount of family members, it skips the question “What is your full name?”

    But if I change:

    to:

    and use nNumberOfFamilyMembers as a string instead, everything works fine. But still….I wanted to do it this way. And even so, in the loop I have to change

    to

    since it would be a string now.

    Anything I can do about it?

  • Ogre

    When you first use cin.getline() you say that the parameter 255 means it will only read the first 254 characters, to leave space for the null terminator. But if you initialize the array with [255] then it will have room for 255 characters plus the null terminator, right?

    Also, when you first use strncpy() you say that the parameter of 49 means that is the most amount of characters it will take (excluding the null terminator), but this is inconsistent with cin.getline(). Is this really how it is?

    You may also want to make it clear that we need to include for some functions.

  • emailaddress1012

    I get something curious when I do the following:

    char *szString = “string”;

    cout << sizeof(szString) << endl;
    for (int nChar = 0; nChar < sizeof(szString); nChar++)
    cout << static_cast(szString[nChar]) << " ";

    Result:
    4
    115 116 114 105

    But when I declare char szString[] = "string" as is done in the tutorial, I get the expected result:

    7
    115 116 114 105 110 103 0

    Does anyone know why this is? I thought these were equivalent ways of declaring C-style strings.

    • pravin_ms

      This is because , you have declared szString as pointer.
      Pointer is a variable that holds address of another variable. The address is a number i.e. nothing but a kind of integer.

      So using sizeof(szStrings) is similar to using sizeof(int) which returns the size of int in bytes.

      To confirm this run the following code :
      void main()
      {
      int a=20;
      cout<<sizeof(a);
      return ;
      }
      It should display value 4 i.e. 4 bytes.

  • MrFinn

    For those outside the USA, note that you will want to use 2 byte unicode characters instead of ASCII (1 byte) character set which is a small subset of Unicode. Most of the stuff in this chapter apply only to ASCII and commands for unicode character manipulation take a different form.

  • stunner

    char szString[] = “string”;

    //prints char at 0th index i.e. s
    cout<<*szString;

    //Prints the entire string i.e. string
    cout<<szString;
    //Why does it not print the address as it would do with int array in below code.

    int arrayName[2] = {2,3};
    cout<<arrayName; //Prints the address

    • alan

      Presumably because cout is being a bit clever, somehow it determines szString is of type char and performs the equivalent of %s in the C style printf function.

      I’m new to C++ but have written a lot of C so far I’m not happy using cin or cout but will persevere with the tutorials.

      I added the following to your versions:
          printf("%p\n", szString); // prints the address
      and
              std::cout << &szString << std::endl; // also prints the address

      alan

  • Seuterr

    Hi. I have been learning C++ via your site. One thing that I just cannot understand and/ or wrap my head around is null terminators. What is the mere point of a null terminator? I get that it ends in a

    . I don’t much care why it uses a double quote to represent this, more of what a null terminator is. I read the one and only part where you introduce it multiple times, and saying the Hungarian Notation isn’t helping me one bit. I just don’t understand what it does, and what the difference between not having a null terminator and having one is.

    • Jacob Perkins

      The null terminator is a special character that tells the compiler when a string ends.

      Computers deal with data as binary numbers:  a sequence of 1’s and 0’s (100101).  C and C++ use the null terminator (”) as a stop sign that lets the compiler know that it should stop interpreting memory as a series of characters.

      If your program stores a string and integer sequentially in memory, then the null terminator would prevent the integer from being read as part of the string.

      At least, this is how I imagine it.

    • Alex

      The null terminator serves as a marker to note where the end of the string is.

      This allows functions to be able to manipulate or print strings without having to know in advance how long they are.

      Consider the following case:

      The array is of length 20, but “Alex” is only length 4. Without a null terminator, how would C++ know that it should only print the first 4 characters and ignore the rest?

  • programmer, another one

    hey alex, if i wanted an array that can a bunch of words, will this be fine:

  • Deses

    Thanks again for a great lesson.

    As a minor detail: my compiler (Apple LLVM 6.1) couldn’t find strncpy before I called it std::strncpy. For some reason using namespace std didn’t work.

    • Jacob Perkins

      C++ gives you two different header files for strings:  <string> and <cstring> (string.h in c).  strncpy isn’t part of the C++ standard template library, so std::strncpy is wrong.

      Visit and compare these two web pages:
      http://www.cplusplus.com/reference/string/
      http://www.cplusplus.com/reference/cstring/

      For strncpy in c++, use <cstring>.

  • cpplx

    the lesson is missing all syntax for c-style string.
    char*
    i had troube reading an example in further lesson.
    when i learned this syntax, examples using it were no longer unreadable.

  • Bogdan

    Alex, you have an error in your article, the parameters for strcpy are reversed. Instead of strcpy(source, destination) you should have strcpy(destination, source).

  • Aymen

    Made a nice little Name program that takes in your name and if the first letter of your name isnt capitalized it will do it for you

  • Elpidius

    Hey Alex, just letting you know there’s a typo in the second example (line 6):
    << ‘characters.\n’;
    Should be written as:
    << "characters.\n";

  • Jim

    Alex,
    At the end of this lesson you said to avoid c style strings unless you actually have to use them.  My question is, can you actually use some functions from c style strings in std strings and visa versa?   For instance (std::getline(std::cin, name);   std::cin.getline(name, 255);) the first getline is from std string and the second is from c style, although the name in the c style could have up to 255 characters.  Can we use either one?

    This brings up another point.  We have seen a lot of functions like .length () added to lessons so far,  although this one is pretty self explanatory can you or will you please give a lesson on how, when, and where to use them and what they all do and where they come from. Thank for the great tuts.

    • Alex

      Both of those functions are essentially the same, so you can use either one.

      Yes, we’ve been showing examples of functions like .length(), but we haven’t explained them yet. This is because they are a special type of function called a member function. We talk about these a lot in chapter 8, and all will become clear then. 🙂

  • Jim

    Alex,
    I’m a bit confused about the string headers and which one to use where.  Are there two headers <string> and <cstring>?  I have a book that says to us #include <cstring>  with C++ strings.   Do we need to use both of them?  What gives?

    • Alex

      Yeah, there are two headers, and they serve different purposes.

      <cstring> includes a bunch of functions for working with C-style strings -- functions like strlen() (to get the length of a C-style string) and strcpy() (to copy a C-style string from one array to another). You’ll only need this header if you’re working directly with C-style strings (which you generally shouldn’t do).

      <string> includes the std::string class that makes working with strings easy and less error-prone.

  • I want to return a string from a function.. but I am getting null pointer error.

    char *myFunction(){
      char str[100];
       // doing something
      return str;
    }

    • Alex

      Yes, str is a local variable that will be destroyed when myFunction() exits. If you return a pointer to the caller, the caller will be left with a pointer to a variable that has been destroyed, which would be bad. Your compiler is giving you a warning of this.

  • Avencherus

    Small typo in the middle.  This should be "string" rather than "spring".  X)

    This program prints:

    spring

    • Alex

      No, it’s correct as written.

      This line:

      overwrite the ‘t’ with a ‘p’, changing “string” to “spring”.

  • Luat

    If I’m not wrong, at line 8 and 9 of the last piece of code (which counts the number of space character in string entered by user), it should be "std::cout" (line 8) and "std::cin" (line 9) instead of "cout" and "cin".

  • Michael

    Hello.
    You said: "In the above program, we’ve allocated an array of 255 characters to name, guessing that the user will not enter this many characters. Although this is commonly seen in C/C++ programming, it is poor programming practice, because nothing is stopping the user from entering more than 255 characters (either unintentionally, or maliciously)."

    So we’ve found a solution not to overflow and to force the user to insert a string with MAX LENGHT = 255

    My question is: is there a way to give our user no-characters limit? I mean, how many he wants!

    Thanks in advance!

    • Alex

      There are ways to do this, but most of the ways to do this are a pain. Much easier is to use std::string, which will handle this kind of thing for you (and resize themselves to hold whatever the user enters).

      • Michael

        Thanks for the reply.
        I know I can do it with std::string, but I need to be addressed to a way to do it from ‘scratch’ since I’m making my own string class and I’m struggling with the operator>> overload!

        • Alex

          One way: Start with a small dynamically allocated char array of size 255. If the user fills the array, then allocate a larger array and copy the data from the smaller array into the larger array. Do this as many times as necessary. Then allocate a string of exactly the correct length, and copy the string into that.

          There may be a smarter way to do this via the C++ streams, but C++ I/O isn’t my specialty.

Leave a Comment

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