Example: .
#include <iostream>
//#define NDEBUG
#include <cassert>
using namespace std;
/* GCD, the greatest common divisor */
/* assuming the arguments are positive */
int gcd(int x, int y);
int main() {
int a = 0, b = 0;
cout << "a = "; cin >> a;
cout << "b = "; cin >> b;
cout << "The GCD is " << gcd(a, b) << endl;
return 0;
}
int gcd(int x, int y) {
// precondition:
// the arguments are positive
assert( x > 0 && y > 0 );
int div = 1;
int largest = 1;
while ( div <= x ) {
if (x % div == 0 && y % div == 0) {
largest = div;
}
div++;
}
// postcondition:
// the number returned is a divisor of both arguments
assert ( x % largest == 0 && y % largest == 0 );
return largest;
}
$ ./a.out
a = 10
b = 2
The GCD is 2
$ ./a.out
a = 126
b = 26
The GCD is 2
$ ./a.out
a = 134
b = -24
a.out: p2gcdassert.cpp:27: int gcd(int, int): Assertion `x > 0 && y > 0' failed.
Aborted (core dumped)
g++ -Wall
Consider an example program:
#include <iostream>
using namespace std;
int thousand(int x);
int main() {
int x;
cout << thousand(x) << endl;
return 0;
}
int thousand(int x) {
if (x = 0) {
return 1000;
}
}
Compiling as follows:
g++ -o prog prog.cpp
The compiler would not complain about at least three obvious errors in the program. (Can you find them yourself?)
In fact, they are not even considered to be errors, it’s a legal C++ code.
However, fortunately, we can ask the compiler to checks some common mistakes in our code,
if we compile our program with the option -Wall
(which stands for “all warnings”):
$ g++ -Wall -o prog prog.cpp
prog.cpp: In function 'int thousand(int)':
prog.cpp:16:12: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
if (x = 0) {
^
prog.cpp:19:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
prog.cpp: In function 'int main()':
prog.cpp:10:21: warning: 'x' is used uninitialized in this function [-Wuninitialized]
cout << thousand(x) << endl;
^
Valgrind is a very useful tool to check that your code is correct. It’s particularly great for detecting errors with dynamic memory allocation, but it shows many other bugs as well, which cannot be detected at compile time.
For example, let’s compile the buggy code we’ve seen before (with the -g
option to add the debugging information)
$ g++ -g -o prog prog.cpp
And run it with Valgrind:
$ valgrind ./prog
==26298== Memcheck, a memory error detector
==26298== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==26298== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==26298== Command: ./prog
==26298==
==26298== Use of uninitialised value of size 8
< ... 5 more lines ... >
==26298==
==26298== Conditional jump or move depends on uninitialised value(s)
< ... 5 more lines ... >
==26298==
==26298== Conditional jump or move depends on uninitialised value(s)
< ... 4 more lines ... >
==26298==
0
==26298==
==26298== HEAP SUMMARY:
==26298== in use at exit: 0 bytes in 0 blocks
==26298== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==26298==
==26298== All heap blocks were freed -- no leaks are possible
==26298==
==26298== For counts of detected and suppressed errors, rerun with: -v
==26298== Use --track-origins=yes to see where uninitialised values come from
==26298== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
// Driver program for the function unitPrice.
#include <iostream>
using namespace std;
double unitPrice(int diameter, double price);
// Returns the price per square inch of a pizza.
// Precondition: The diameter parameter is the diameter of the pizza
// in inches. The price parameter is the price of the pizza.
int main( )
{
double diameter, price;
char ans;
do {
cout << "Enter diameter and price:\n";
cin >> diameter >> price;
cout << "unit Price is $"
<< unitPrice(diameter, price) << endl;
cout << "Test again? (y/n)";
cin >> ans;
cout << endl;
} while (ans == 'y' || ans == 'Y');
return 0;
}
double unitPrice(int diameter, double price)
{
const double PI = 3.14159;
double radius, area;
radius = diameter/ static_cast<double>(2);
area = PI * radius * radius;
return (price/area);
}