I l@ve RuBoard |
![]() ![]() |
5.4 Initializing VariablesC++ allows variables to be initialized in the declaration statement. For example, the following statement declares the integer counter and initializes it to 0. int counter(0); // number cases counted so far The older C-style syntax is also supported: int counter = 0; // number cases counted so far Arrays can be initialized in a similar manner. The element list must be enclosed in curly braces ({}). For example: // Product numbers for the parts we are making int product_codes[3] = {10, 972, 45}; This is equivalent to: product_codes[0] = 10; product_codes[1] = 972; product_codes[2] = 45; The number of elements in the curly braces ({}) does not have to match the array size. If too many numbers are present, a warning will be issued. If there are not enough numbers, the extra elements will be initialized to 0. If no dimension is given, C++ will determine the dimension from the number of elements in the initialization list. For example, we could have initialized our variable product_codes with the statement: // Product numbers for the parts we are making int product_codes[] = {10, 972, 45}; 5.4.1 Bounds ErrorsIn Example 5-2 the data array has five elements. So what happens if we accidently use an illegal index? For example: int data[5]; // ... result = data[99]; // Bad The results are undefined. Most of the time you'll get a random number. Other times, your program may abort with an error. Things get worse if you use the bad index on the left side of an assignment: int data[5]; // ... data[99] = 55; // Very bad In this case, if you're lucky, the program will abort. If you're not so lucky, the program will change a random memory location. This location could hold another variable, vital system data, or something else important. The result is that your program fails in a strange and hard to debug manner. Therefore it is extremely important to make sure that any time you use an array index that it's within bounds. Example 5-6 illustrates a program that contains an array bounds error. Example 5-6. bounds/bound_err.cpp#include <iostream> const int N_PRIMES = 7; // Number of primes // The first few prime numbers int primes[N_PRIMES] = {2, 3, 5, 7, 11, 13, 17}; int main( ) { int index = 10; std::cout << "The tenth prime is " << primes[index] << '\n'; return (0); } When this program executes on some machines it outputs: Segmentation violation Core dumped On others it just gives us funny information: The tenth prime is 0 Bounds errors are ugly, nasty things that should be stamped out whenever possible. One solution to this problem is to use the assert statement. The assert statement tells C++, "This can never happen, but if it does, abort the program in a nice way." One thing you find out as you gain programming experience is that things that can "never happen" happen with alarming frequency. So just to make sure that things work as they are supposed to, it's a good idea to put lots of self checks in your program. The assert statement is one form of self check. When we add it to Example 5-6 we get Example 5-7. Example 5-7. bounds/bound_c1.cpp#include <iostream> #include <assert.h> const int N_PRIMES = 7; // Number of primes // The first few prime numbers int primes[N_PRIMES] = {2, 3, 5, 7, 11, 13, 17}; int main( ) { int index = 10; assert(index < N_PRIMES); assert(index >= 0); std::cout << "The tenth prime is " << primes[index] << '\n'; return (0); } The statement: #include <assert.h> tells C++ that we want to use the assert module. Now we know that the index must be in range. After all, our program could never contain an error that might generate a bad index. But just to make sure, we check to see if it's in range using the statement: assert(index < N_PRIMES); assert(index >= 0); Now when the program hits the assert statement, the assertion fails and an error message is issued: bound_c1: bound_c1.cpp:11: int main( ): Assertion `index < 7' failed. Abort (core dumped) The program then aborts. Aborting is a nasty way of handling an error, but it's better than doing nothing at all. (This is not true in every case; see sidebar.)
There is a problem with our code. The programmer must remember that the array data has a limit of N_PRIMES. This means that he has to count and to keep track of two things: the number of items in data and the value of N_PRIMES. It would be better to do things automatically. The C++ operation sizeof returns the size of a variable in bytes. So sizeof(data) is 28 (7 elements of 4 bytes each). This assumes that integers are 4 bytes long. (This is system-dependent.) But we want the number of elements in data, not the number of bytes. The size of the first element is sizeof(data[0]), and since each element is the same size, this is the size of every element. So we have the total number of bytes in the array and the number of bytes in an element. From this we can compute the number of elements in the array: sizeof(data) / sizeof(data[0]) Now we can rewrite the code and eliminate the need to count elements. The results are in Example 5-8. Example 5-8. bounds/bound_c2.cpp#include <iostream> #include <assert.h> // The first few prime numbers int primes[] = {2, 3, 5, 7, 11, 13, 17}; int main( ) { int index = 10; assert(index < (sizeof(primes)/sizeof(primes[0]))); assert(index >= 0); std::cout << "The tenth prime is " << primes[index] << '\n'; return (0); } |
I l@ve RuBoard |
![]() ![]() |