Wednesday, January 26, 2011

IT IS MY FIRST VISUAL C++ BOOK     PUBLISHING IN NETWORK.......
   IT DEDICATED FOR MY LOVELY      FRIENDS.... 



MODERN VISUAL


   
                                                                              WRITTEN BY SUNIL SAMAL

Monday, January 24, 2011

APPENDIX-5 Debugging your program (watching variables and the call stack)

In the previous lesson on stepping and breakpoints, you learned how to use the debugger to watch the path of execution through your program. However, stepping through a program is only half of what makes the debugger useful. The debugger also lets you examine the value of variables as you step through your code.
Note: If you are not familiar with the concept of stepping, please review the previous lesson first, as this lesson builds on top of it. Our examples here will be using the Visual Studio 2005 Express debugger — if you are using a different IDE/debugger, the commands may have slightly different names or be located in slightly different locations.
Watching variables
Watching a variable is the process of inspecting the value of a variable while the program is executing in debug mode. Most debuggers provide several ways to do this. Let’s take a look at a sample program:
01#include <iostream>
02 
03int main()
04{
05    using namespace std;
06    const int nInterations = 10;
07 
08    for (int nValue=1; nValue<nInterations; nValue++)
09        cout << nValue << " ";
10    cout << endl;
11 
12    return 0;
13}
This is a pretty straightforward sample program — it prints all the numbers between 1 and 10.
First, step into your program until the next line to be executed is the cout << nValue << " "; line:

At this point, the variable nValue has already been created and initialized with the value 1, so when we examine the value of nValue, we should expect to see the value 1.
The easiest way to examine the value of a simple variable like nValue is to hover your mouse over the word nValue. Most modern debuggers support this method of inspecting simple variables, and it is the most straightforward way to do so.

The second way to examine the value of a variable is to highlight the variable name with your mouse, and then choose "Quickwatch" from the right-click menu.. This may have another name, such as "Inspect" or "Watch".

This will pull up a subwindow containing the value of the variable:

Now let's watch this variable change as we step through the program. First, choose "Step over" twice, so the next line to be executed is the cout << nValue << " "; line:

Since we are on the second iteration of the loop, nValue has been incremented once and should have value 2. Inspect it and make sure that it does!
The watch window
Using the mouse hover or quickwatch methods to inspect variables is fine if you want to know the value of a variable at a particular point in this, but it's not particularly well suited to watching the value of a variable change as you run the code because you continually have to rehover/reselect the variable.
In order to address this issue, all modern compilers provide another feature, called a watch window. The watch window is a window where you can add variables you would like to continually inspect, and these variables will be updated as you step through your program. The watch window may already be on your screen when you enter debug mode, but if it is not, you can bring it up through your IDEs window commands (these are typically found in the view or debug menus).
In Visual Studio 2005 Express, you can bring up a watch menu by going to Debug Menu->Windows->Watch->Watch 1 (note: you have to be in debug mode, so step into your program first).
You should now see this:

There is nothing in this window because we have not set any watches yet. There are typically two different ways to set watches:
1) Type in the name of the variable you would like to watch in the "Name" column of the watch window.
2) Highlight the variable you would like to watch, right click, and choose "Add Watch".
Go ahead and add the variable "nValue" to your watch list. You should now see this:

Now chose the "Step over" command a few times and watch the value of your variable change!
Note that variables that go out of scope will stay in your watch window. If the variable returns to scope, the watch will pick it up and begin showing it's value again.
Using watches is the best way to watch the value of a variable change over time as you step through your program.
The call stack window
Modern debuggers contain one more debugging information window that can be very useful in debugging your program. The call stack window shows you the state of the current call stack. If you need a refresher on what the call stack is, see the lesson on the stack and the heap.
If you don't see the call stack window, you will need to tell the IDE to show it. In Visual Studio 2005 Express, you can do that by going to Debug Menu->Windows->Call Stack (note: you have to be in debug mode, so step into your program first).
Let's take a look at the call stack using a sample program:
01void CallC()
02{
03    std::cout << "C called" << std::endl;
04}
05void CallB()
06{
07    std::cout << "B called" << std::endl;
08    CallC();
09}
10 
11void CallA()
12{
13    CallB();
14    CallC();
15}
16 
17int main()
18{
19    CallA();
20 
21    return 0;
22}
Put a breakpoint in the CallC() function and then start debugging mode (via "Continue"). The program will execute until it gets to the line you breakpointed.
Although you now know the program is executing CallC(), there are actually two calls to CallC() in this program (one in CallB(), and one in CallA()). Which function was responsible for calling CallC() this time? The Call stack will show us:

The program started by calling main(). main() called CallA(), which called CallB(), which called CallC(). You can double-click on the various lines in the Call Stack window to see more information about the calling functions. Some IDEs take you directly to the function call. Visual Studio 2005 Express takes you to the next line after the function call. Go ahead and try this functionality out. When you are ready to resume stepping through your code, double-click the top line of the call stack window and you will return to your point of execution.
Putting it together
There are three primary types of problems that occur in programs. The first is due to variables being assigned the wrong values. By use of variable inspection, you can watch your variables get calculated and compare what you expected to what you got.
For example, if you saw this code:
1int nNumerator = 10;
2int nDivisor = 4;
3double dValue = nNumerator / nDivisor;
You would expect dValue to have the value 2.5 after it was executed. But if you run this in the debugger, you would see that dValue is assigned the value of 2. Why? Because you did an integer division, not a floating point division. Errors like this are very hard to detect without a debugger, but very easy with one.
The second type of problem is caused by an incorrect loop condition (causing the program to loop too few or too many times). For example, you might have written the following code expecting it to print the values 1 to 10:
1// Print all the values between 1 and 10
2for (int nValue=1; nValue < 10; nValue++)
3    std::cout << nValue << " ";
But when you run it, it only prints 1 to 9. Using stepping and variable inspection, you can watch nValue as it gets incremented. When nValue is 10, the comparsion nValue < 10 is false, and the loop terminates without having printed the value 10.
The third type of problem that new programmers often struggle with is related to the scope/lifetime of variables. This can manifest in many way, but some of the more common ones include:
  1. Accidentally passing function parameters by value instead of by reference, or vice-versa.
  2. Declaring a new variable with the same name as a function parameter, hiding the function parameter.
  3. Deleting some allocated memory that is referenced later (causing your program to crash).
Congratulations, you now know the basics of debugging your code! Using stepping, breakpoints, watches, and the call stack window, you now have the fundamentals to be able to debug almost any problem. Like many things, becoming good at using a debugger takes some practice and some trial and error. However, the larger your programs get, the more valuable you will find the debugger to be, so it is definitely worth your time investment!

APPENDIX-4 Debugging your program (stepping and breakpoints)

An introduction to debugging
Programming is difficult, and there are a lot of ways to make mistakes. As you learned in the section on handling errors, there are two primary types of errors: syntax errors and semantic errors.
A syntax error occurs when you write a statement that is not valid according to the grammar of the C++ language. This happens a lot through typos or accidental omission of keywords or symbols that C++ is expecting. Fortunately, the compiler will generally catch syntax errors and generate warnings or errors so you know what the problem is.
Once your program is compiling correctly, getting it to actually produce the result(s) you want can be tricky. A semantic error occurs when a statement is syntactically valid, but does not do what the programmer intended. Unfortunately, the compiler will not be able to catch these types of problems, because it only knows what you wrote, not what you intended.
Fortunately, that’s where the debugger comes in. A debugger is a computer program that allows the programmer to control how a program executes and watch what happens as it runs. For example, the programmer can use a debugger to execute a program line by line, examining the value of variables along the way. By comparing the actual value of variables to what is expected, or watching the path of execution through the code, the debugger can help immensely in tracking down semantic errors.
Early debuggers, such as gdb, had command-line interfaces, where the programmer had to type arcane commands to make them work. Later debuggers (such as Borland’s turbo debugger) came with their own “graphical” front ends to make working with them easier. Almost all modern IDEs available these days have integrated debuggers — that is, the debugger is built-in to the editor, so you can debug using the same environment that you use to write your code (rather than having to switch programs).
Nearly all modern debuggers contain the same standard set of basic features — however, there is little consistency in terms of how the menus to access these features are arranged, and even less consistency in the keyboard shortcuts. Although our examples will be from Microsoft Visual Studio 2005 Express, you should have little trouble figuring out how to access each feature we discuss no matter which development environment you are using.
Stepping
Stepping is a debugger feature that lets you execute (step through) your code line by line. This allows you to examine each line of code in isolation to determine whether it is behaving as intended.
There are actually 3 different stepping commands: step into, step over, and step out. We will cover each one in turn.
Step into
The step into command executes the next line of code. If this line is a function call, step into enters the function and returns control at the top of the function.
Let’s take a look at a very simple program:
01#include <iostream>
02 
03void PrintValue(int nValue)
04{
05    std::cout << nValue;
06}
07 
08int main()
09{
10    PrintValue(5);
11    return 0;
12}
As you know, when running a program, execution begins with a call to main(). Because we want to debug main(), let’s begin by using the “step into” command.
In Visual Studio 2005 Express, go to the debug menu and choose “Step Into”, or press F11.
If you are using a different IDE, find the “Step Into” command in the menus and choose it.
When you do this, two things should happen. First, a console output window should open. It will be empty because we haven’t output anything to it yet. Second, you should see some kind of marker appear to the left of the opening brace of main. In Visual Studio 2005 Express, this marker is a yellow arrow. If you are using a different IDE, you should see something that serves the same purpose.

This arrow marker indicates that the line being pointed to will be executed next. In this case, the debugger is telling us that the next line that will be executed is the opening brace of main(). Choose “step into” again to execute the opening brace, and the arrow will move to the function call to PrintValue().

This means the next line that will be executed is the call to PrintValue(). Choose “step into” again. Because PrintValue() was a function call, we “stepped into” the function, and the arrow should be at the top of the PrintValue() code.

Choose “step into” to execute the opening brace of PrintValue().
At this point, the arrow should be pointing to std::cout << nValue;.
Choose "step into" again, and you should see that the value 5 appears in the output window.
Choose "step into" again to execute the closing brace of PrintValue(). At this point, PrintValue() has finished executing and control is returned to main().
You will note that the arrow is again pointing to PrintValue()!

While you might think that the debugger intends to call PrintValue() again, in actuality the debugger is just letting you know that it is returning from the function call.
Choose "step into" twice more. At this point, we have executed all the lines in our program, so we are done. Some debuggers will terminate the debugging session automatically. Visual Studio 2005 Express does not, so choose "Stop Debugging" from the debug menu. This will terminate your debugging session (and can be used at any point in the debugging process to do so).
Step over
Like "step into", The step over command executes the next line of code. If this line is a function call, step over silently executes the function and returns control after the function has been executed.
Let's take a look at an example of this using the same program as above:
01#include <iostream>
02 
03void PrintValue(int nValue)
04{
05    std::cout << nValue;
06}
07 
08int main()
09{
10    PrintValue(5);
11    return 0;
12}
Step into the program until the next statement to be executed is the call to PrintValue().

Instead of stepping into PrintValue(), choose "step over" instead. The debugger will execute the function (which prints the value 5 in the output window) and then return control to you when it is finished.
Step over provides a convenient way to skip functions when you are sure they already work or do not need to be debugged.
Step out
Unlike the other two stepping commands, step out does not execute the next line of code. Instead, it executes the rest of the function you are currently in, and returns control to you when the function has finished executing.
Let's take a look at an example of this using the same program as above:
01#include <iostream>
02 
03void PrintValue(int nValue)
04{
05    std::cout << nValue;
06}
07 
08int main()
09{
10    PrintValue(5);
11    return 0;
12}
Step into the program until you are inside PrintValue().

Then choose "step out". You will notice the value 5 appears in the output window, and the debugger returns control to you after the function has terminated.
Run to cursor
While stepping is useful for examining each individual line of your code in isolation, in a large program, it can take a long time to step through your code just to get to the point where you want to examine in more detail.
Fortunately, modern debuggers provide a few more tools to help us efficiently debug our programs.
The first useful command is commonly called run to cursor. This command executes the program like normal until it gets to the line of code selected by your cursor. Then it returns control to you so you can debug starting at that point. Let's try it using the same program we've been using:
01#include <iostream>
02 
03void PrintValue(int nValue)
04{
05    std::cout << nValue;
06}
07 
08int main()
09{
10    PrintValue(5);
11    return 0;
12}
First, choose "step into" to enter debugging mode. Second, put your cursor on the std::cout << nValue; line inside of PrintValue(). Third, choose the "run to cursor" debug command. In Visual Studio 2005 Express,, you can do this by right clicking and choosing "run to cursor".
You will notice the arrow indicating the line that will be executed next moves to the line you just selected. Your program executed up to this point and is now waiting for your further debugging commands.
Run
It is also possible to tell the debugger to run until it hits the end of the program. In Visual Studio 2005 Express, this command is called "Continue". In other debuggers, it may be called "Run" or "Go".
If you have been following along with the examples, you should now be inside the PrintValue() function. Choose the run command, and your program will finish executing and then terminate.
Breakpoints
The last topic we are going to talk in this section is breakpoints. A breakpoint is a special marker that tells the debugger to stop execution of the program at the breakpoint when running in debug mode.
To set a breakpoint in Visual Studio 2005 Express, go to the Debug menu and choose "Toggle Breakpoint". You will see a new type of icon appear:

Start a new debugging session and let's see what the breakpoint does.
First, choose "Step into" to start your debugging session. Then choose the run command (may be called "Continue" or "Go").
You will notice that instead of running all the way to the end of the program, the debugger stopped at the breakpoint!

Breakpoints are extremely useful if you want to examine a particular section of code. Simply set a breakpoint at the top of that section of code, tell the debugger to run, and the debugger will automatically stop every time it hits that breakpoint. Then you can use the stepping commands from there to watch your program run line by line.
One last note: Up until now, we've been using "step into" to start debugging sessions. However, it is possible to tell the debugger to just start running to the end of the program immediately. In Visual Studio 2005 Express, this is done by picking "Start debugging" from the Debug menu. Other debuggers will have similar commands. This, when used in conjunction with breakpoints, can reduce the number of commands you need to use to get to the spot you want to debug in more detail using the stepping commands.
Conclusion
Congratulations, you now know all of the major ways to make the debugger move through your code. However, this is only half of what makes debuggers useful. The next lesson will talk about how to examine the value of variables while we are debugging, as well as a couple of additional windows of information we can make use of to help debug our code.
Return to the C++ tutorial index page

APPENDIX-3 Using libraries with Code::Blocks

To recap the process needed to use a library:
Once per library:
1) Acquire the library. Download it from the website or via a package manager.
2) Install the library. Unzip it to a directory or install it via a package manager.
3) Tell the compiler where to look for the header file(s) for the library.
4) Tell the linker where to look for the library file(s) for the library.
Once per project:
5) Tell the linker which static or import library files to link.
6) #include the library̢۪s header file(s) in your program.
7) Make sure the program know where to find any dynamic libraries being used.
Steps 1 and 2 — Acquire and install library
Download and install the library to your hard disk. See the tutorial on static and dynamic libraries for more information about this step.
Steps 3 and 4 — Tell the compiler where to find headers and library files
We are going to do this on a global basis so the library will be available to all of our projects. Consequently, the following steps only need to be done once per library.
A) Go to the “Settings menu” and pick “Compiler”.

B) Click the “Directories” tab. The compiler tab will already be selected for you.
C) Press the “Add” button, and add the path to the .h files for the library. If you are running Linux and installed the library via a package manager, make sure /usr/include is listed here.

D) Click the “Linker” tab. Press the “Add” button, and add the path to the .lib files for the library. If you are running Linux and installed the library via a package manager, make sure /usr/lib is listed here.

E) Press the “OK” button.
Step 5 — Tell the linker which libraries your program is using
For step 5, we need to add the library files from the library to our project. We do this on an individual project basis.
A) Right click on the bolded project name under the default workspace (probably “Console application”, unless you changed it). Choose “Build options” from the menu.

B) Click the linker tab. Under the “Link libraries” window, press the “Add” button and add the library you wish your project to use.

C) Press the “OK” button
Steps 6 and 7 — #include header files and make sure project can find DLLs
Simply #include the header file(s) from the library in your project.
See the tutorial on static and dynamic libraries for more information step 7.

APPENDIX-2Using libraries with Visual Studio 2005 Express

To recap the process needed to use a library:
Once per library:
1) Acquire the library. Download it from the website or via a package manager.
2) Install the library. Unzip it to a directory or install it via a package manager.
3) Tell the compiler where to look for the header file(s) for the library.
4) Tell the linker where to look for the library file(s) for the library.
Once per project:
5) Tell the linker which static or import library files to link.
6) #include the library̢۪s header file(s) in your program.
7) Make sure the program know where to find any dynamic libraries being used.
Steps 1 and 2 — Acquire and install library
Download and install the library to your hard disk. See the tutorial on static and dynamic libraries for more information about this step.
Steps 3 and 4 — Tell the compiler where to find headers and library files
We are going to do this on a global basis so the library will be available to all of our projects. Consequently, the following steps only need to be done once per library.
A) Go to the “Tools menu” and pick “Options”.

B) Open the “Projects and Solutions” node, and click on “VC++ Directories”.
C) In the upper right under “Show directories for:”, pick “Include Files”. Add the path to the .h files for the library.

D) In the upper right under “Show directories for:”, pick “Library Files”. Add the path to the .lib files for the library.

E) Click “OK”.
Step 5 — Tell the linker which libraries your program is using
For step 5, we need to add .lib files from the library to our project. We do this on an individual project basis. Visual Studio offers us 3 different methods for adding .lib files to our project.
A) Use a #pragma preprocessor directive to your primary .cpp file. This solution only works with Visual Studio and is non-portable. Other compilers will ignore this line.

B) Add the .lib file to your project as if it were a .cpp or .h file. This solution works with Visual Studio, but not with many other compilers. This is the solution we recommend.

C) Add the library to the linker input. This is the most “portable” solution in the sense that every IDE will provide a similar mechanism. If you ever move to another compiler or IDE, this is the solution you will have to use. This solution requires 5 steps:
C-1) In the Solution Explorer, right click on the bolded project name and choose “Properties” from the menu.

C-2) Under the “Configuration:” dropdown, select “All Configurations”.
C-3) Open the “Configuration Properties” node, the “Linker” node, and click on “Input”.
C-4) Under “Additional Dependencies”, add the name of your library.

C-5) Click “OK”.
Steps 6 and 7 — #include header files and make sure project can find DLLs
Simply #include the header file(s) from the library in your project.
See the tutorial on static and dynamic libraries for more information step 7.

APPENDIX-1Static and dynamic libraries

A library is a package of code that is meant to be reused by many programs. Typically, a C++ library comes in two pieces:
1) A header file that defines the functionality the library is exposing (offering) to the programs using it.
2) A precompiled binary that contains the implementation of that functionality pre-compiled into machine language.
Some libraries may be split into multiple files and/or have multiple header files.
Libraries are precompiled for several reasons. First, since libraries rarely change, they do not need to be recompiled often. It would be a waste of time to recompile the library every time you wrote a program that used them. Second, because precompiled objects are in machine language, it prevents people from accessing or changing the source code, which is important to businesses or people who don’t want to make their source code available for intellectual property reasons.
There are two types of libraries: static libraries and dynamic libraries.
A static library (also known as an archive) consists of routines that are compiled and linked directly into your program. When you compile a program that uses a static library, all the functionality of the static library becomes part of your executable. On Windows, static libraries typically have a .lib extension, whereas on linux, static libraries typically have an .a (archive) extension. One advantage of static libraries is that you only have to distribute the executable in order for users to run your program. Because the library becomes part of your program, this ensures that the right version of the library is always used with your program. Also, because static libraries become part of your program, you can use them just like functionality you’ve written for your own program. On the downside, because a copy of the library becomes part of every executable that uses it, this can cause a lot of wasted space. Static libraries also can not be upgraded easy — to update the library, the entire executable needs to be replaced.
A dynamic library (also called a shared library) consists of routines that are loaded into your application at run time. When you compile a program that uses a dynamic library, the library does not become part of your executable — it remains as a separate unit. On Windows, dynamic libraries typically have a .dll (dynamic link library) extension, whereas on Linux, dynamic libraries typically have a .so (shared object) extension. One advantage of dynamic libraries is that many programs can share one copy, which saves space. Perhaps a bigger advantage is that the dynamic library can be upgraded to a newer version without replacing all of the executables that use it.
Because dynamic libraries are not linked into your program, programs using dynamic libraries must explicitly load and interface with the dynamic library. This mechanisms can be confusing, and makes interfacing with a dynamic library awkward. To make dynamic libraries easier to use, an import library can be used.
An import library is a library that automates the process of loading and using a dynamic library. On Windows, this is typically done via a small static library (.lib) of the same name as the dynamic library (.dll). The static library is linked into the program at compile time, and then the functionality of the dynamic library can effectively be used as if it were a static library. On Linux, the shared object (.so) file doubles as both a dynamic library and an import library.
Installing and using libraries
Now that you know about the different kinds of libraries, let’s talk about how to actually use libraries in your program. Installing a library in C++ typically involves 4 steps:
1) Acquire the library. The best option is to download a precompiled package for your operating system (if it exists) so you do not have to compile the library yourself. If there is not one provided for your operating system, you will have to download a source-code-only package and compile it yourself (which is outside of the scope of this lesson). On Windows, libraries are typically distributed as .zip files. On Linux, libraries are typically distributed as packages (eg. .RPM). Your package manager may have some of the more popular libraries (eg. SDL) listed already for easy installation, so check there first.
2) Install the library. On Linux, this typically involves invoking the package manager and letting it do all the work. On Windows, this typically involves unzipping the library to a directory of your choice. We recommend keeping all your libraries in one location for easy access. For example, use a directory called C:\Libs, and put each library in it’s own subdirectory.
3) Make sure the compiler knows where to look for the header file(s) for the library. On Windows, typically this is the \include subdirectory of the directory you installed the library files to (eg. if you installed your library to C:\libs\SDL-1.2.11, the header files are probably in C:\libs\SDL-1.2.11\include). On Linux, libraries are typically installed to /usr/include, which should already be part of your include file search path. However, if the files are installed elsewhere, you will have to tell the compiler where to find them.
4) Tell the linker where to look for the library file(s) for the library. As with step 3, this typically involves adding a directory to the list of places the linker looks for libraries. On Windows, this is typically the /lib subdirectory of the directory you installed the library files to. On Linux, libraries are typically installed to /usr/lib, which should already be a part of your library search path.
Once the library is installed and the IDE knows where to look for it, the following 3 steps typically need to be performed for each project that wants to uses the library:
5) If using static libraries or import libraries, tell the linker which library files to link.
6) #include the library’s header file(s) in your program. This tells the compiler about all of the functionality the library is offering so that your program will compile properly.
7) If using dynamic libraries, make sure the program know where to find them. Under Linux, libraries are typically installed to /usr/lib, which is in the default search path. On Windows, the default search path includes the directory the program is run from, directories set by calling SetDllDirectory(), the Windows, System, and System32 directories, and directories in the PATH environment variable. The easiest way to use a .dll to copy the .dll to the location of the executable. Since you’ll typically distribute the .dll with your executable, it makes sense to keep them together anyway.
Steps 3-5 involve configuring your IDE — fortunately, almost all IDEs work the same way when it comes to doing these things. Unfortunately, because each IDE has a different interface, the most difficult part of this process is simply locating where the proper place to perform each of these steps is. Consequently, in the next few lessons in this section, we’ll cover how to do all of these steps for both Visual Studio Express 2005 and Code::Blocks. If you are using another IDE, read both — by the time you’re done, you should have enough information to do the same with your own IDE with a little searching.

std::string inserting

Inserting:-
Inserting characters into an existing string can be done via the insert() function.
string& string::insert (size_type index, const string& str)
string& string::insert (size_type index, const char* str)

  • Both functions insert the characters of str into the string at index
  • Both function return *this so they can be “chained”.
  • Both functions throw out_of_range if index is invalid
  • Both functions throw a length_error exception if the result exceeds the maximum number of characters.
  • In the C-style string version, str must not be NULL.
Sample code:
1string sString(&quot;aaaa&quot;);
2cout &lt;&lt; sString &lt;&lt; endl;
3
4sString.insert(2, string(&quot;bbbb&quot;));
5cout &lt;&lt; sString &lt;&lt; endl;
6
7sString.insert(4, &quot;cccc&quot;);
8cout &lt;&lt; sString &lt;&lt; endl;
Output:
aaaa
aabbbbaa
aabbccccbbaa
Here’s a crazy version of insert() that allows you to insert a substring into a string at an arbitrary index:

There is a flavor of insert() that inserts the first portion of a C-style string:
string& string::insert(size_type index, const char* str, size_type len)
  • Inserts len characters of str into the string at index
  • Returns *this so it can be “chained”.
  • Throws an out_of_range exception if the index is invalid
  • Throws a length_error exception if the result exceeds the maximum number of characters.
  • Ignores special characters (such as ‘\0′)
Sample code:
1string sString(&quot;aaaa&quot;);
2
3sString.insert(2, &quot;bcdef&quot;, 3);
4cout &lt;&lt; sString &lt;&lt; endl;
Output:
aabcdaa
There’s also a flavor of insert() that inserts the same character multiple times:
string& string::insert(size_type index, size_type num, char c)
  • Inserts num instances of char c into the string at index
  • Returns *this so it can be “chained”.
  • Throws an out_of_range exception if the index is invalid
  • Throws a length_error exception if the result exceeds the maximum number of characters.
Sample code:
1string sString(&quot;aaaa&quot;);
2
3sString.insert(2, 4, 'c');
4cout &lt;&lt; sString &lt;&lt; endl;
Output:
aaccccaa
And finally, the insert() function also has three different versions that use iterators:
void insert(iterator it, size_type num, char c)
iterator string::insert(iterator it, char c)
void string::insert(iterator it, InputIterator begin, InputIterator end)
  • The first function inserts num instances of the character c before the iterator it.
  • The second inserts a single character c before the iterator it, and returns an iterator to the position of the character inserted.
  • The third inserts all characters between [begin,end) before the iterator it.
  • All functions throw a length_error exception if the result exceeds the maximum number of characters.

std::string appending

Appending
Appending strings to the end of an existing string is easy using either operator+=, append(), or push_back() function.
string& string::operator+= (const string& str)
string& string::append (const string& str)
  • Both functions append the characters of str to the string.
  • Both function return *this so they can be “chained”.
  • Both functions throw a length_error exception if the result exceeds the maximum number of characters.
Sample code:
1string sString("one");
2 
3sString += string(" two");
4 
5string sThree(" three");
6sString.append(sThree);
7 
8cout << sString << endl;
Output:
one two three
There’s also a flavor of append() that can append a substring:
string& string::append (const string& str, size_type index, size_type num)
  • This function appends num characters from str, starting at index, to the string.
  • Returns *this so it can be “chained”.
  • Throws an out_of_range if index is out of bounds
  • Throws a length_error exception if the result exceeds the maximum number of characters.
Sample code:
1string sString("one ");
2 
3const string sTemp("twothreefour");
4sString.append(sTemp, 3, 5); // append substring of sTemp starting at index 3 of length 5
5cout << sString << endl;
Output:
one three
Operator+= and append() also have versions that work on C-style strings:
string& string::operator+= (const char* str)
string& string::append (const char* str)
  • Both functions append the characters of str to the string.
  • Both function return *this so they can be “chained”.
  • Both functions throw a length_error exception if the result exceeds the maximum number of characters.
  • str should not be NULL.
Sample code:
1string sString("one");
2 
3sString += " two";
4sString.append(" three");
5cout << sString << endl;
Output:
one two three
There is an additional flavor of append() that works on C-style strings:
string& string::append (const char* str, size_type len)
  • Appends the first len characters of str to the string.
  • Returns *this so they can be “chained”.
  • Throw a length_error exception if the result exceeds the maximum number of characters.
  • Ignores special characters (including ‘\0′)
Sample code:
1string sString("one");
2 
3sString.append("threefour", 5);
4cout << sString << endl;
Output:
one three
This function is dangerous and its use is not recommended.
There is also a set of functions that append characters. Note that the name of the non-operator function to append a character is push_back(), not append()!
string& string::operator+= (char c)
void string::push_back (char c)
  • Both functions append the the character c to the string.
  • Operator += returns *this so it can be “chained”.
  • Both functions throw a length_error exception if the result exceeds the maximum number of characters.
Sample code:
1string sString("one");
2 
3sString += ' ';
4sString.append('2');
5cout << sString << endl;
Output:
one 2
Now you might be wondering why the name of the function is push_back() and not append(). This follows a naming convention used for stacks, where push_back() is the function that adds a single item to the end of the stack. If you envision a string as a stack of characters, using push_back() to add a single character to the end makes sense. However, the lack of an append() function is inconsistent in my view!
It turns out there is an append() function for characters, that looks like this:
string& string::append (size_type num, char c)
  • Adds num occurrences of the character c to the string
  • Returns *this so it can be “chained”.
  • Throws a length_error exception if the result exceeds the maximum number of characters.
Sample code:
1string sString("aaa");
2 
3sString.append(4, 'b');
4cout << sString << endl;
Output:
aaabbbb
There’s one final flavor of append() that you won’t understand unless you know what iterators are. If you’re not familiar with iterators, you can ignore this function.
string& string::append (InputIterator start, InputIterator end)
  • Appends all characters from the range [start, end) (including start up to but not including end)
  • Returns *this so it can be “chained”.
  • Throws a length_error exception if the result exceeds the maximum number of characters.

std::string assignment and swapping

String assignment
The easiest way to assign a value to a string is to the use the overloaded operator= function. There is also an assign() member function that duplicates some of this functionality.
string& string::operator= (const string& str)
string& string::assign (const string& str)
string& string::operator= (const char* str)
string& string::assign (const char* str)
string& string::operator= (char c)
  • These functions assign values of various types to the string.
  • These functions return *this so they can be “chained”.
  • Note that there is no assign() function that takes a single char.
Sample code:
01string sString;
02 
03// Assign a string value
04sString = string("One");
05cout << sString << endl;
06 
07const string sTwo("Two");
08sString.assign(sTwo);
09cout << sString << endl;
10 
11// Assign a C-style string
12sString = "Three";
13cout << sString << endl;
14 
15sString.assign("Four");
16cout << sString << endl;
17 
18// Assign a char
19sString = '5';
20cout << sString << endl;
21 
22// Chain assignment
23string sOther;
24sString = sOther = "Six";
25cout << sString << " " << sOther << endl;
Output:
One
Two
Three
Four
5
Six Six
The assign() member function also comes in a few other flavors:
string& string::assign (const string& str, size_type index, size_type len)
  • Assigns a substring of str, starting from index, and of length len
  • Throws an out_of_range exception if the index is out of bounds
  • Returns *this so it can be “chained”.
Sample code:
1const string sSource("abcdefg");
2string sDest;
3 
4sDest.assign(sSource, 2, 4); // assign a substring of source from index 2 of length 4
5cout << sDest << endl;
Output:
cdef
string& string::assign (const char* chars, size_type len)
  • Assigns len characters from the C-style array chars
  • Ignores special characters (including ‘\0′)
  • Throws an length_error exception if the result exceeds the maximum number of characters
  • Returns *this so it can be “chained”.
Sample code:
1string sDest;
2 
3sDest.assign("abcdefg", 4);
4cout << sDest << endl;
Output:
abcd
This function is potentially dangerous and it’s use is not recommended.
string& string::assign (size_type len, char c)
  • Assigns len occurrences of the character c
  • Throws an length_error exception if the result exceeds the maximum number of characters
  • Returns *this so it can be “chained”.
Sample code:
1string sDest;
2 
3sDest.assign(4, 'g');
4cout << sDest << endl;
Output:
gggg
Swapping
If you have two strings and want to swap their values, there are two functions both named swap() that you can use.
void string::swap (string &str)
void swap (string &str1, string &str2)
  • Both functions swap the value of the two strings. The member function swaps *this and str, the global function swaps str1 and str2.
  • These functions are efficient and should be used instead of assignments to perform a string swap.
Sample code:
1string sStr1("red");
2string sStr2("blue);
3 
4cout << sStr1 << " " << sStr2 << endl;
5swap(sStr1, sStr2);
6cout << sStr1 << " " << sStr2 << endl;
7sStr1.swap(sStr2);
8cout << sStr1 << " " << sStr2 << endl;
Output:
red blue
blue red
red blue

std::string character access and conversion to C-style arrays

There are two almost identical ways to access characters in a string. The easier to use and faster version is the overloaded operator[]:
char& string::operator[] (size_type nIndex)
const char& string::operator[] (size_type nIndex) const
  • Both of these functions return the character with index nIndex
  • Passing an invalid index results in undefined behavior
  • Using length() as the index is valid for const strings only, and returns the value generated by the string’s default constructor. It is not recommended that you do this.
  • Because char& is the return type, you can use this to edit characters in the array
Sample code:
1string sSource("abcdefg");
2cout << sSource[5] << endl;
3sSource[5] = 'X';
4cout << sSource << endl;
Output:
f
abcdeXg
There is also a non-operator version. This version is slower since it uses exceptions to check if the nIndex is valid. If you are not sure whether nIndex is valid, you should use this version to access the array:
char& string::at (size_type nIndex)
const char& string::at (size_type nIndex) const
  • Both of these functions return the character with index nIndex
  • Passing an invalid index results in an out_of_range exception
  • Because char& is the return type, you can use this to edit characters in the array
Sample code:
1string sSource("abcdefg");
2cout << sSource.at(5) << endl;
3sSource.at(5) = 'X';
4cout << sSource << endl;
Output:
f
abcdeXg
Conversion to C-style arrays
Many functions (including all C functions) expect strings to be formatted as C-style strings rather than std::string. For this reason, std::string provides 3 different ways to convert std::string to C-style strings.
const char* string::c_str () const
  • Returns the contents of the string as a const C-style string
  • A null terminator is appended
  • The C-style string is owned by the std::string and should not be deleted
Sample code:
1string sSource("abcdefg");
2cout << strlen(sSource.c_str());
Output:
7
const char* string::data () const
  • Returns the contents of the string as a const C-style string
  • A null terminator is not appended
  • The C-style string is owned by the std::string and should not be deleted
Sample code:
?
1string sSource("abcdefg");
2char *szString = "abcdefg";
3// memcmp compares the first n characters of two C-style strings and returns 0 if they are equal
4if (memcmp(sSource.data(), szString, sSource.length()) == 0)
5    cout << "The strings are equal";
6else
7    cout << "The strings are not equal";
Output:
The strings are equal
size_type string::copy(char *szBuf, size_type nLength) const
size_type string::copy(char *szBuf, size_type nLength, size_type nIndex) const
  • Both flavors copy at most nLength characters of the string to szBuf, beginning with character nIndex
  • The number of characters copied is returned
  • No null is appended. It is up to the caller to ensure szBuf is initialized to NULL or terminate the string using the returned length
  • The caller is responsible for not overflowing szBuf
Sample code:
1string sSource("sphinx of black quartz, judge my vow");
2 
3char szBuf[20];
4int nLength = sSource.copy(szBuf, 5, 10);
5szBuf[nLength]='\0'// Make sure we terminate the string in the buffer
6 
7cout << szBuf << endl;
Output:
black
Unless you need every bit of efficiency, c_str() is the easiest and safest of the three functions to use.