4.3 C STRINGS


4.3 C++ STRINGS

C++ has a built-in type string that avoids the pitfalls of C-style strings.[5] Since many aspects of this type cannot be fully explained until we discuss concepts such as operator overloading, our goal in this section is limited to familiarizing the reader with some rudimentary aspects of this type to the extent that we can use it in some of the examples in this and later chapters. To use the C++ string type, you must include its associated header file:

     #include <string> 

4.3.1 Constructing a C++ String Object

To declare a string with initialization, we can say

     string str( "hi there"); 

which is a call to the constructor of the string class with "hi there" as its const char* argument. An alternative way to initialize a string is

     string str = "hi there"; 

We can also use the following syntax:

     string str = string( "hi there" ); 

We can think of the right-hand side here as constructing an anonymous string object that is then assigned to the variable str through what's known as the copy constructor for the string class.[6]. We also have the option of invoking the new operator to obtain a pointer to a string object:

     string* p = new string( "hi there" ); 

An empty string can be declared in the following manner[7]

     string str; 

or as

     string str = ""; 

These declarations create an object of class string whose name is str.[8] A principal feature of this object is that it stores inside it the string of characters specified by the initialization syntax. The stored string may or may not be null terminated. If in a particular implementation of C++, the string is not null terminated, that does not create a problem because also stored in the object is the exact length of the string. So there is never any question about how many memory locations would need to be accessed in order to read an entire string.

While the string constructor invocations illustrated above show us how to convert a const char* string into a string object, what about the opposite? How does one convert a C++ string object back into a C-style null-terminated string? This is done by invoking the c_str () member function for the string class:

     string str( "hello" );     const char* c_string = str.c_str(); 

4.3.2 Accessing Individual Characters

The individual characters of a C++ string can be accessed for reading and writing by either using the subscript operator'[]' or the member function at (). The former is not range checked, while the latter is. What that means is that suppose you try to access a character position that does not really exist, what you get with the subscript operator is unpredictable, meaning implementation dependent. On the other hand, if you try to access a nonexistent position with the at () function, the program is guaranteed to abort. This is illustrated by the following program where we have commented out the line in which we invoke the at () function with an argument that is clearly outside the range valid for the “hello” string. If you uncomment this line, the program will abort at run time when the flow of control reaches that line. On the other hand, when we try to reach the same index with the subscript operator, we may see some garbage character displayed on the screen.

 
// StringCharIndexing. #include <string> using namespace std; int main() { string str( "hello" ); 0char ch = str[0]; // ch initialized to 'h' str[0] = 'j'; // str now equals "jello" ch = str. at( 0 ); // ch's value is now 'j' str.at(0) = 'h'; // str agains equals "hello" ch = str[ 1000 ]; // garbage value for ch // ch = str.at( 1000 ); // program aborts if uncommented return 0 ; }

4.3.3 String Comparison

Two strings can be compared for equality (or inequality) on the basis of the ASCII codes associated with the characters using the binary operators ‘==’, ‘! =’, ‘>’, ‘>=’, ‘<’, and ‘<=’. Two strings are equal if and only if they are composed of identical character sequences. A string is less than another string if the former occurs earlier in a lexicographic ordering of the strings on the basis of the ASCII codes associated with the characters.

While the operators listed above are all binary, in the sense that they return either true or false, sometimes it is more useful to employ a 3–valued comparison function, compare (), that is defined for the string class. Given two string objects str1 and str2, the invocation

     str1.compare( str2 ); 

returns one of three possible values:

a positive value if str1 is greater than str2

0 if str1 is equal to str2

a negative value if str1 is less than str2

For example,

     string str1( "abc" );     string str2( "abc123" );     if ( str1.compare( str2 ) == 0 )                // test returns false        .....     if ( str1.compare( str2 ) < 0 )                               // test returns true        .....     if ( str1.compare( str2 ) > 0 )                               // test rturns false        .... 

It is also possible to invoke compare with additional arguments that designate at what character position to start the comparison in the invoking string and how many characters to use from the argument string. In the following example, "hello" is the string that invokes compare on the argument string "ellolotion" in line (A). The second argument to compare in line (A)—in this case 1—designates the index at which the start the character comparisons in the string "hello". This means that the string comparison will begin at the letter ‘e’ of "hello". The third argument to compare in line (A) is 4; this is the number of characters from the string "ellolotion" that will be used for string comparison.

     string str1("hello");     string str2("ellolotion");     if ( str1.compare( str2, 1, 4 ) == 0 )                             //(A)     cout << "\nThe substring starting at index 1 "                           "of 'hello' is the same as the first "                           "four chars of 'ellolotion'."          << endl;                                        //(B)   else     cout << "The compare test failed" << endl; 

For the example code shown, the comparison test in line (A) returns true and the message in the statement leading up to line (B) is printed out.

In the three-argument version of compare shown in line (A) above, the second argument is of type string:: size_type,[9] which for all practical purposes can be considered to be int, and the third argument of type unsigned int. There is also a two-argument version of compare in which the second argument plays the same role as in the example shown. Now the comparison is with the entire argument string. We should also mention that the compare function works just the same if its first argument is a C-style const char* string.[10]

A 3–valued string comparison function, such as the compare function, is what you'd need for certain kinds of string sorting functions. Let's say we wish to sort an array of string literals as shown below:

     string wordList[] = {"hello", "halo", "jello", "yellow",            //(C)                                "mellow", "Hello", "JELLO", "Yello",                                "MELLOW"}; 

Although later the reader will be introduced to the sorting functions designed expressly for C++, we can sort this array by using the venerated qsort function defined originally in the stdlib.h header file of the C standard library, but also made available through the header file string of C++. The function qsort, frequently an implementation of quick-sort, is capable of sorting an array of any data type as long as you are able to specify a comparison function for the elements of the array.[11] The prototype of qsort is

     void qsort( void* base,                                             //(D)                 size_t nmemb,                 size_t size,                 int (* compar) ( const void*, const void* ) ); 

where base is a pointer to the first element of the array to be sorted, nmemb the number of elements to be sorted, [12] size the size of each element in bytes, [13] and, finally, compar a pointer to a user-defined function for comparing any two elements of the array. The user defined comparison function that will be bound to the parameter compar must return an int and must take exactly two arguments, both of type void*. Furthermore, for qsort() to work correctly, the int returned by the comparison function must be positive when the entity pointed to by the first argument is greater than the entity pointed to by the second argument; must be negative when the opposite is the case; and must be zero when the two entities are equal.

Here is a possible comparison function for the fourth argument of qsort for sorting the elements of the array wordList of line (C) above:[14]

     int compareStrings( const void* arg1, const void* arg2 ) {         //(E)          return ( *( static_cast<const string*>( arg1 ) ) ). compare (                                       *( static_cast<const string*>( arg2) ) ); } 

In terms of the return type and the parameter structure, this comparison function corresponds exactly to what is specified for the fourth argument of qsort () in line (D). The actual comparison is carried out by invoking the compare function of the string class.

Shown below is a simple program that pulls together the code fragments shown above into a complete program:

 
//Qsort.cc #include <string> using namespace std; int compareStrings( const void* arg1, const void* arg2 ); int checkUpperCase( string buffer ); int main() { string wordList[] = {"hello", "halo", "jello", "yellow", "mellow", "Hello", "JELLO", "Yello", "MELLOW"}; cout << sizeof( wordList[] << endl; // 36 int sizeArray = sizeof( wordList ) / sizeof( wordList[ 0 ] ); cout << sizeArray << endl; // 9 qsort( wordList, sizeArray , sizeof(string), compareStrings); int j = 0; while ( j < sizeArray ) cout << wordList[j++] << " "; //Hello JELLO MELLOW Yello halo hello jello mellow yellow cout << endl; return 0; } int compareStrings( const void* arg1, const void* arg2 ) { return ( *( static_cast<const string*>( arg1 ) ) ).compare( *( static_cast<const string*>( arg2) ) ); }

4.3.4 Joining Strings Together

Through the overloading of the ‘+’ operator, the string class makes it very easy to join strings together without having to worry whether or not you allocated sufficient memory for the result string.[15] For example, we can say

     string str1( "hello" );     string str2( "there" );     string str3 = str1 + " " + str2;     // "hello there"     str2 += str1;                        // "therehello" 

which would result in the object str3 storing the string "hello there" and the object str2 storing the string "therehello". The operator ‘+’ works the same if the second operand is of type const char* or just char as long as the first operand is an object of type string.[16] So while the following will not work

     string s = "hello" + " there";    // Wrong 

the following does:

     string s = string( "hello" ) + " there"; 

It is also possible to use the append member function for joining two strings, or one string with a part of another string, as the following example illustrates:

     string string1( "hello" );     string string2( " the world at large" );     string string3 = string1;     string3.append( string2 );                                          //(A)     cout << string3;     // "hello the world at large"     string1.append( string2, 3, 6 );                                    //(B)     cout << string1;     // "hello world" 

In the one-argument invocation of append in line (A), the entire argument string is appended to the invoking string. In the three-argument version of append, shown in line (B), a substring from the argument string is appended to the invoking string. The substring begins at the index specified by the second argument, with the third argument specifying its length. The second and the third arguments in the three-argument version are both of type string:: size_type, which as mentioned before can be taken to be the same as int for the purpose of program design.

There is also a two-argument version of append in which the second argument is the same as the second argument of the three-argument version. In this case, the entire argument string starting at the specified index is appended to the invoking string.

As is true of all string class member functions, the argument string can also be a C-style const char* string.

4.3.5 Searching for Substrings and Characters

A frequent problem in string processing is that we want to know if a given string has particular substrings or particular characters in it. Consider, for example, the problem of isolating words in a text file. Of the many different ways of solving this problem, one would be to read the file one line at a time and to then look for whitespace characters in each line. If not excessively large, we could even read the entire file as a single string and then look for whitespace characters (which include line-feeds and carriage returns) to break the string into individual words.

The C++ string library provides a number of functions for searching for substrings and individual characters in a string. These functions are named find, rfind, find_first_of, find_last_of, find_first_not_of, and find_last_not_of. In all there are 24 functions with these six names, the various versions of the functions catering to different types of arguments. In this section, we will explain how one can invoke find and find_first_of on string type objects with string or char type arguments. (Their usage on const char* type arguments is parallel to the usage on string arguments.) The functions rfind do the same thing as find, except that they start the search from the end of a string towards its beginning. The functions find_last_of again do the same thing as find_first_of, except that they start their search at the end of a string toward its beginning.

Here is an example that illustrates how one can invoke find to search for a substring in a string:

     string::size_type pos = 0;     string quote( "Some cause happiness wherever they go,"     " others whenever they go - Oscar Wilde" );     if ( ( pos = quote.find( "happiness" ) ) != string::npos )          //(A)        cout << "The quote contains the word 'happiness'" << endl; 

The function find returns the index of the character in the invoking string where it scores a match with the argument string. This index, although officially of type string:: size_type, can be taken to be an int for all practical purposes. If no match is found, find returns a symbolic constant string:: npos, a static data member of the string class also of type size_t. The actual value of npos is such that no actual character index in any valid string would ever correspond to it. In the above program fragment, note how we compare the value returned by find with the symbolic constant npos to establish the presence or the absence of the substring.

The following program shows a simple demonstration of the use of find. It also shows how replace, another member function of the string class, can be used together with find to search for each occurrence of a substring in a string and, when found, how the substring can be replaced with another string. The program produces the output

     4     32     one armadillo is like any other armadillo 

where the numbers 4 and 32 are the position indices where the substring "hello" occurs in the larger string "one hello is like any other hello". Here is the program:[17]

 
//StringFind.cc #include <string> using namespace std; int main() { string str( "one hello is like any other hello" ); string searchString( "hello" ); string replaceString( "armadillo" ); assert( searchString != replaceString ); string::size_type pos = 0; while ( (pos = str.find(searchString, pos)) != string::npos ) { str.replace( pos, searchString.size(), replaceString ); pos++; } cout << str << endl; //one armadillo is like any other armadillo return 0; }

Note the use of the 2-argument version of find in the above program. The second argument tells find where to begin the search for the substring. When you are searching for a character or a substring with find, after you have obtained the first match, you need to increment the index represented by pos so that the search can continue on for the next occurrence. If you don't do that, find will keep on returning the same index ad infinitum.

The above example code also illustrates the use of the 3–argument replace. This function can take up to five arguments. The two additional arguments, both of type string:: size_type, specify the position in the argument string and the number of characters to be taken starting at that position for the purpose of replacement.

Shown below is an example of how one can use the string library function find_first_of to locate and count some of the more frequently used punctuation marks in a string. We place all the punctuation marks we are looking for in a string called marks, with the original string stored in quote. We invoke find_first_of on quote and supply it with marks as its first argument, the second argument consisting of the position index in quote where we want the search to begin. Note how we increment pos after each hit. If we did not do so, the function find_first_of will keep on returning the same location where it found the first punctuation mark. For the example shown, the program returns a count of five.

     string quote( "Ah, Why, ye Gods, should two and two "                   "make four? - Alexander Pope" );     string marks( ",.?:;-" );     string::size_type pos = 0;     int count = 0;     while ( ( pos = quote.find_first_of( marks, pos ) )                   != string::npos ) {               ++pos;               ++count;     }     cout << count << endl;       // 5 

4.3.6 Extracting Substrings

The string library offers the function substr for extracting a substring from a source string on which the function is invoked. This function can be invoked with one argument, of type size_type, that designates the index of the character that marks the start of the substring desired from the source string. The extracted substring will extend all the way to the end of the source string. This use is illustrated by the following code fragment. Here the string returned by substr will start at the position indexed 44 and go to the end of the quote. As a result, the output produced by line (B) is "Fiction has to make sense.—Tom Clancy".

     string quote( "The difference between reality and fiction? "                      "Fiction has to make sense. - Tom Clancy" );     string str = quote.substr( 44 );     cout << str << endl;                    //(A) 

There is also a two-argument version of substr in which the first argument works the same as in the example shown above. The second argument, also of type size_type, now designates the number of characters to be extracted from the source string. If the number of characters requested exceeds the number remaining in the source string, the extracted substring will stop at the end of the source string. The following code fragment, which will output "Fiction," illustrates this usage.

     string quote( "The difference between reality and fiction?"                   "Fiction has to make sense. - Tom Clancy" );     string str = quote.substr( 44, 7 );     cout << str << endl;          // Fiction 

It is also possible to invoke the substr function with no arguments, in which case it simply returns a copy of the string object on which it is invoked.

Substrings can also be extracted by invoking the string constructor with a string argument and with additional optional arguments to specify the starting index for substring extraction and the number of characters to be extracted from the first argument string. In the invocations of the string constructor below that construct the objects str_1 and str_2, the first yields the substring "Fiction has to make sense. - Tom Clancy", and the second just the word "Fiction".

     string quote( "The difference between reality and fiction?"                   "Fiction has to make sense. - Tom Clancy" );     string str_1( quote, 44 );     string str_2( quote, 44, 7 ); 

4.3.7 Erasing and Inserting Substrings

The string class member function erase can be used to erase a certain number of characters in the string on which the function is invoked. The function can be invoked with zero arguments, with one argument, and with two arguments. When invoked with no arguments, the function erases the string stored in the invoking object and replaces it with the empty string "". When invoked with one argument, which must be of type string: :size_type, the string stored in the invoking object is erased from the position indexed by the second argument to the end. When invoked with two arguments, both of typestring:: size_type, the second argument designates the number of characters to be erased starting at the position specified by the first argument.

The following code fragment illustrates the two-argument erase. It also illustrates the insert member function which can be used to insert a new substring into a string object. The function insert can be invoked with either two arguments, or three arguments, or four arguments. When invoked with two arguments, the first argument, of type string: :size_type, designates the index of the position at which the new insertion is to begin, and the second argument the string to be inserted. In the three-argument version, the additional argument specifies a position in the argument string that designates the start of the substring to be inserted; the substring continues to the end. In the four-argument invocation, the last argument specifies the number of characters to be taken from the argument string for the purpose of insertion.

The example below shows two-argument and four-argument versions of insert.

     string: :size_type pos = 0;     string quote = "Some cause happiness wherever they go, "                    "others whenever they go - Oscar Wilde";     if ( ( pos = quote.find( "happiness" ) ) != string: :npos ) {         quote.erase( pos, 9 );         quote.insert( pos, "excitement" ); }     cout << quote << endl;                  //(A)     quote.erase( pos, 10 );     cout << quote << endl;                  //(B)     quote. insert( pos, "infinite happiness in the air", 9, 9 );     cout << quote << endl;                  //(C) 

The code produces the following output:

     FROM LINE (A):     Some cause excitement wherever they go, others whenever they go - Oscar Wilde     FOME LINE (B):     Some cause wherever they go, others whenever they go - Oscar Wilde     FROM LINE (C):     Some cause happiness wherever they go, others whenever they go - Oscar Wilde 

4.3.8 Size and Capacity

The size() (or length(), which does the same thing) member function when invoked on a string object will ordinarily return the number of characters in the string stored in the object. This will also ordinarily be the amount of memory allocated to a string object for the storage of the characters of the string.

     string str( "0123456789" );     cout << str.size() << endl;    // returns 10 

When you extend the length of a string by using, say, the ‘+=’ operator, the size of the allocated memory is automatically increased to accommodate the longer length. But if a string is going to be extended in bits and pieces frequently, you can reduce the background memory-allocation work by preallocating additional memory for the string through the resize() member function. If we refer to the total amount of memory currently available to a string for the storage of its characters as the string object's capacity, we can use resize to endow a string with any desired capacity. In the code fragment shown below, we initially create a string object of size 10 characters. At this moment the capacity of the string object is also 10. But then we increase the capacity to 20 characters by invoking resize, although the number of actual characters in the string is still 10.

 
//StringSize.cc #include <iostream> #include <string> int main() { string str = "0123456789"; cout << "The current capacity of the string is:" << str.size() << endl; // 10 str.resize( 20 ); cout << "The new capacity of the string is:" << str.size() << endl; // 20 cout << "The actual length of the string is: " // 10 << strlen( str.c_str() ) << endl; cout << "The string object after resizing " << "to 20 a 10 character string: " << str << endl; // "0123456789" str += "hello"; cout << str << endl; // "0123456789hello" return 0; }

This code shows a one-argument version of resize. When supplied with an optional second argument, which must be of type char, the designated character is used to initialize the spaces not occupied by the characters in the string, the default being the null character.

While on the subject of size, we also want to clarify the relationship between the size of a string object and the size of the string held by a string object. The size of a string object can be ascertained by invoking sizeof( string ), which for g++ returns 4 for all strings (but could return 8 on some systems). Before we go into why sizeof( string ) returns the same number for all strings on any given system, let's quickly review the nature of sizeof.

Remember from C that, despite its appearance, sizeof is not a function, but an operator. It is not a function in the sense that it does not evaluate its argument; it only looks at the type of its argument. To illustrate the nature of this operator, all of the following invocations of sizeof[18]

     int x = 4;     int y = 5;     sizeof(x);      sizeof(x + y);     sizeof x;     sizeof( int );     sizeof int; 

eturn on the author's machine the same value, which is 4 for the 4 bytes that it takes to store an int.[19] So if we say

     string s1 = "hello";     string s2 = "hello there"; 

and then invoke the sizeof operator by

     sizeof( s1 );                           // returns 4 for g++     sizeof( s2 );                           // returns 4 for g++ 

we'd get exactly the same answer in both cases, the number 4 (or 8 for some compilers). Compare this with the following case of applying sizeof to the string literals directly:

     sizeof( "hello" );                       // returns 6     sizeof( "hello there" );                 // returns 12 

We get 6 for the string literal "hello" because it is NOT stored as a string object and because its internal representation is a null-terminated array of characters. Similarly for the string literal "hello there".

The constant value of 4 returned by sizeof( string ) is easy to understand if we think of the string class as having been provided with a single non-static data member of type char* for holding a character pointer to a null-terminated array of characters.

     class string {       char* ptr;       // static data members if needed     public:       // string functions }; 

Then the memory occupied by a string object would be what's needed by its sole nonstatic data member shown—4 bytes for the pointer. On the other hand, if a compiler returned 8 bytes for sizeof ( string ), that's because the string class used by that compiler comes with an additional data member—of possibly an unsigned integer type—for holding the size of the string pointed to by the first data member. In this case, it would not be absolutely necessary for the char* string to be null terminated since the second data member would tell us directly how many characters belonged to the string.

Note that if we applied the sizeof operator to any pointer type, we'd get 4 for the four bytes to hold a memory address. For example,

     sizeof ( string* ) -> 4     sizeof ( int* ) -> 4     sizeof ( char* ) -> 4 

We have brought the above statements together in the following program:

 
//StringSizeOf.cc #include <iostream> #include <string> int main() { cout << sizeof( "hello" ) << endl; // 6 cout << sizeof( "hello there" ) << endl; // 12 string str1 = "hello"; string str2 = "hello there"; cout << sizeof( str1 ) << endl; // 4 cout << sizeof( str2 ) << endl; // 4 char* s1 = "hello"; char* s2 = "hello there"; cout << sizeof( s1 ) << endl; // 4 cout << sizeof( s2 ) << endl; // 4 char c_arr[] = "how are you?"; cout << sizeof( c_arr ) << endl; // 13 return 0; }

Before ending this subsection, we should remind the reader that sizeof () can sometimes show seemingly unexpected behavior. Consider the role of sizeof in the following program that attempts to find the size of the array in a called function by invoking sizeof:

 
//ArraySizeOf.cc #include <iostream> int sum( int [], int ); int main() { int data [100] = {2, 3}; int m = sizeof( data ) / sizeof ( data[0] ); // (A) cout << sum( data, 100 ) << endl; return 0; } int sum( int a[], int arr_size ) { //the following value of n is not very useful int n = sizeof( a ) / sizeof( a[0] ); // (B) int result = 0; int* p = a; while (p-a<arr_size) result += *p++; return result; }

While at (A) the number m will be set to 100, at (B) the number n will be set to 1. The reason for this is that when an array name is a function parameter, it is treated strictly as a pointer. So the numerator on the right-hand side at (B) is synonymous with sizeof( int* ) which yields 4.

4.3.9 Some Other String Functions

The string library offers a function swap that can be used to swap the actual strings stored inside two string objects. In the following code fragment, after the execution of the third statement, the object str1 will store the string "lemonade", whereas the object str2 will store the string "lemon".

     string str1 = "lemon";     string str2 = "lemonade";     str1.swap( str2 ); 

A different effect is achieved by the assign function. After the execution of the third statement below, both the objects str1 and str2 will contain the string "lemonade";

     string str1 = "lemon";     string str2 = "lemonade";     str1.assign( str2 ); 

[5]Actually, the built-in string type in C++ is the template class basic_string. The C++ string class is a typedef alias for basic_string<char>, which is the basic_string template with char as its template parameter. The concept of a template class, introduced briefly in Chapter 3, is presented more fully in Chapter 13.

[6]Copy constructors are discussed in Chapter 11.

[7]Depending on how the string type is implemented, a C++ string may not include a null terminator at the end. In that case, an empty C++ can be truly empty, as opposed to a "" string in C which consists of the null terminator.

[8]We could also have said: "This declaration creates an object of type string." For nonprimitive types, the characterizations type and class are used interchangeably in object-oriented programming.

[9]On the basis of the notation explained in Section 3.16.1 of Chapter 3, the syntax string:: size_type refers to inner type size_type defined for the string class.

[10]This is actually true of all string member functions. They work the same for both string and const char* arguments.

[11]In Chapter 5, we discuss the notion of stable sorting for class type objects and point out that qsort may not be the best sorting function to invoke in some cases.

[12]We can think of size_t as an unsigned integer.

[13]For the example array shown, each element of the array is a string object that is initialized by the corresponding string literal on the right hand side of the declaration for wordList. So we can use sizeof(string) for the third argument of qsort.

[14]Typical C syntax for the same function would be

     int compareStrings( const void* arg1, const void* arg2 ) {         return (*(const string*) arg1).compare(*(const string*) arg2); } 

The difference between the C way of writing this function and the C++ syntax shown in line (E) is with regard to casting. What is done by the cast operator (const string*) in the C version here is accomplished by static_cast<const string*>() in the C++ definition in line (E). The static_cast and other C++ cast operators are presented in Chapters 6 and 16.

[15]Obviously, there has to be sufficient free memory available to the memory allocator used by the string class for this to be the case. If the memory needed is not available, the memory allocator will throw an exception.

[16]As we will explain in Chapter 12, for class type operands the compiler translates the expression

     str1 + str2; into     str1.operator+( str2 ); 

where the function operator+ contains the overload definition for the ‘+’ operator. That makes str1 the operand on which the function operator+ is invoked and str2 the argument operand. We may loosely refer to str1 as the invoking operand.

[17]Note the use of the assert function in this program. The test stated in the argument to this function must evaluate to true for the thread of execution to proceed beyond the point of this function call.

[18]Although the parentheses are not really needed in sizeof(x), in the sense that we could also have said sizeof x, because of operator precedence the compiler would understand sizeof (x + y) and sizeof x + y differently. Since the operator sizeof is a unary operator and since unary operators have higher precedence than binary operators, sizeof x + y; would be interpreted as sizeof (x) + y.

[19]To be precise, the sizeof operator in C++ returns the size of a type-name in terms of the size of a char. However, in most implementations, the size of a char is 1 for the 1 byte that it takes to hold a character in C++. Also as a point of difference between C++ and C, in C sizeof ( 'x' ) returns 4, whereas sizeof ( char ) returns 1. On the other hand, in C++, both sizeof ( 'x' ) and sizeof ( char ) return 1. The reason for the discrepancy between the two sizeof values for C is that a char argument to the operator is read as an int, as is often the case with char arguments in C. Despite this discrepancy in C, the following idiom in C

     int size;     char arr[3] = {'*', 'y', 'z'};     size = sizeof ( arr ) / sizeof( arr[0] ); 

does exactly what the programmer wants it to do (the value of size is set to 3, the number of elements in the array) because the sizeof operator looks only at the type of arr[0] in the denominator. In other words, even though sizeof( 'x' ) returns 4 in C, sizeof( arr[0] ) will always return 1.




Programming With Objects[c] A Comparative Presentation of Object-Oriented Programming With C++ and Java
Programming with Objects: A Comparative Presentation of Object Oriented Programming with C++ and Java
ISBN: 0471268526
EAN: 2147483647
Year: 2005
Pages: 273
Authors: Avinash Kak

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net