FAQs : Frequently Asked Questions

Steven J. Zeil

Last modified: Dec 27, 2022
Contents:

This is a collection of questions (and answers!) that have arisen repeatedly in some of my past classes.

1 I can’t log in to…

1.1 I can’t log in to… Canvas

You’ll need to take that up with the ITS Help Desk.

1.2 I can’t log in to… the CS VPN

  1. Make sure that you are using the correct VPN client.

    • The VPN is not something that you connect to using a web browser!
    • If the VPN client suggests that you need to enter a license or invitation code, you have downloaded and installed the wrong software. Uninstall it and then get the right software.
  2. Make sure that you are connecting to the right VPN.

    Some ITS-supplied documentation discusses connecting to the ODU VPN used only by ODU staff.

    The portal for the CS VPN is 128.82.11.11.

  3. Are you able to log in to other CS resources that are not behind the VPN such as this page?

    • If so, then you know that your login name and password are working and can skip to step 6.
  4. Make sure that you are using the correct login name. All CS student login names consist of “cs_” followed by your ODU MIDAS ID. For example, if your MIDAS ID is jdoe001, your CS login name is cs_jdoe001.
  5. Make sure that you are using the correct password. If you have forgotten your password, you can reset it.
  6. Check your cell phone to see if you have pending requests to identify yourself from the two-factor authentication system.
  7. If none of that helps, contact root@cs.odu.edu. Let them know that you have checked the above steps. Also be sure to tell them what operating system you are running on your PC. (Don’t just say “Windows”. They need to know whether it’s Windows 10 or Windows 11.)

1.3 I can’t log in to… the CS Linux servers

  1. Make sure that you are using an appropriate SSH client. You cannot connect to the Linux servers using a web browser!
  2. You must connect to the CS VPN before connecting to the Linux servers.
  3. Are you getting a message warning about possible Spoofing? If so, see this discussion.
  4. Are you getting a message saying that the authenticity ofthe host can’t be established? If so, see this discussion.
  5. Are you getting a message saying that linux.cs.odu.edu does not exist or is not on the network? Then you are not connected to the VPN.
  6. Make sure that you are using the correct login name. All CS student login names consist of “cs_” followed by your ODU MIDAS ID. For example, if your MIDAS ID is jdoe001, your CS login name is cs_jdoe001.
  7. Make sure that you are using the correct password. If you have forgotten your password, you can reset it.
  8. If none of that helps, contact root@cs.odu.edu. Let them know that you have checked the above steps.

1.4 I can’t log in to… an assignment submit page (https://www.cs.odu.edu/~zeil/submit/...)

  1. Are you able to log in to other CS resources such as the CS VPN?
    • If so, then you know that your login name and password are working and can skip to step 4.
  2. Make sure that you are using the correct login name. All CS student login names consist of “cs_” followed by your ODU MIDAS ID. For example, if your MIDAS ID is jdoe001, your CS login name is cs_jdoe001.
  3. Make sure that you are using the correct password. If you have forgotten your password, you can reset it.
  4. If you are absolutely sure that your login name and password are correct, contact root@cs.odu.edu. Let them know that which of the systems in step 1 you were and were not able to connect with.

1.5 I can’t log in to… a password-protected course page hosted at (https://www.cs.odu.edu/...)

  1. Make sure that you are trying to access the correct course, and not a website for a different semester or a section taught by someone else.
    • If your course website has an Outline or landing page, look there and check the semester and instructor name listed at the top.
  2. Make sure that you are using the correct login name. All CS student login names consist of “cs_” followed by your ODU MIDAS ID. For example, if your MIDAS ID is jdoe001, your CS login name is cs_jdoe001.
  3. Are you able to log in to this page?
    • If so, your login name and password are working fine, but you might not be on the access list for the course website. Contact the course instructor. Be sure to include the exact URL of the page that you are trying to access.

  4. Are you able to log in to other CS resources such as the CS VPN or the CS Virtual PC lab?
    • If so, then you know that your login name and password are working and can skip to step 5.
  5. Make sure that you are using the correct password. If you have forgotten your password, you can reset it.
  6. If you are absolutely sure that your login name and password are correct, contact root@cs.odu.edu. Let them know that which of the systems in steps 3 and 4 you were and were not able to connect with and the URL of the page that you are unable to reach.

2 Problems Connecting to CS Linux servers

2.1 “This site can’t be reached”

You need to use an appropriate SSH client.

You cannot connect to the Linux servers using a web browser!

2.2 “unable to connect, host does not exist”

You need to run the VPN before making your SSH connection.

2.3 “The authenticity of host … can’t be established.”

This is a normal and expected message whenever you connect to a new machine for the first time.

Just answer “yes” the to question about whether to continue connecting.

2.4 “POSSIBLE DNS SPOOFING DETECTED” or “REMOTE HOST IDENTIFICATION HAS CHANGED”

This message arises whenever the “hardware” that responds to connections to a particular machine name (e.g., linux.cs.odu.edu) has changed. Your SSH client remembers the hardware IDs of your past connections and objects when the hardware appears to have changed.

This check was added to SSH a long time ago and made sense at the time as protection against “DNS spoofing” (a.k.a.“man-in-the-middle”) attacks where someone on the network would insert their machine as a kind of wire-tap between you and your intended destination in order to spy out your login name and password.

It’s now pretty much just an annoyance because

  1. DNS spoofing is almost impossible if you are connecting via the VPN.
  2. In the modern world of cloud computing, the servers that respond to your connection attempts probably aren’t hardware at all, but “virtual machines” simulating the hardware, and those virtual machines may change at any time, far more frequently than anyone would ever purchase new hardware.

So what do you do?

3 General Programming Questions

3.1 What’s all this “foo” and “bar” stuff?

There is a long-standing tradition in computer science of using certain words as sample variable/function/whatever names. Just as a mathematician might use “x” or “y” whenever an arbitrary variable name is needed, computer scientists tend to use “foo”, “bar”, and “baz”, in that order. Check out this entry in the Hacker’s Dictionary for a discussion of the origin of these terms.

3.2 I’m not sure I have a correct algorithm to solve this problem. How do I check before writing and debugging the code?

The worst thing you can do is to simply start throwing C++ statements around at random trying to guess at an algorithm design.

  1. Research - is there a known algorithm for addressing this kind of problem? Check your text and the lecture notes. Check the web.

    Even if you find something, you will likely have to adapt it to the details of the problem at hand, but this can get you started.

  2. Draw pictures of the input and output data structures Take note of all the differences between the input and output pictures. Think about the programming steps that would be required to change the input pictures into the output pictures.

  3. Work at least a few examples by hand so that you have some simple examples of possible inputs and expected outputs at hand.

    Begin by drawing a “picture” on a possible input value. Then go step-by-step through your proposed algorithm, updating the picture at each step.

    This is called desk checking, a.k.a. walkthroughs. You’ve probably seen this done by your instructors and in your textbooks many times.

  4. Use a systematic procedure for design, such as stepwise refinement, a.k.a. top-down design, to derive a new algorithm that solves your problem.

    As you work, update your desk checking pictures to make sure that your algorithm steps are moving you in the right direction.

3.3 My program crashed. How do I find out why?

There’s no easy answer to that. Here’s what I do, though, when faced with a crash that I just don’t understand:

  1. Look at the output produced before the crash. That can give you a clue as to where in the program you were when the crash occurred.

  2. Run the program from within a debugger (or here and here ).

    Don’t worry about breakpoints or single-stepping or any of that stuff at first. Just run it.

    When the crash occurs, the debugger should tell you what line of code in what file eas being executed at the moment of the crash.

    Actually, it’s not quite that simple. There’s a good chance that the crash will occur on some line of code you didn’t actually write yourself, deep inside some system library function that was called by some other system library function that was called by some other … until we finally get back to your own code. That crash occurred because you are using a function but passed it some data that was incorrect or corrupt in some way.

    Your debugger should let you view the entire runtime stack of calls that were in effect at the moment of the crash. So you should be able to determine where the crash occurred. That’s not as good as determining why, but it’s a start.

  3. Take a good look at the data being manipulated at the location of the crash. Are you using pointers? Could some of them be null? Are you indexing into an array? Could your index value be too large or negative? Are you reading from a file? Could the file be at the end already, or might the data be in a different format than you expected?

    If you used a debugger to find the crash locations, you can probably move up and down the stack and to view the values of variables within each active call. This may give a clue about what was happening.

  4. Form some hypotheses (take a guess) as to what was going on at the time of the crash. Then test your hypothesis!

3.4 Why do compilers’ error messages often give the wrong line number, or even the wrong file?

A compiler can only report where it detected a problem. Where you actually committed a mistake may be someplace entirely different.

Many error messages list more than one location where the problem may actually lie, but your IDE may abbreviate that to a single line, losing all of that extra information. You often need to look at a “Console” window panel to see the full text of an error message.

The full error message may be quite long and might appear a little scarey, but you can learn to read error messages to extract out the key information.

The vast majority of error messages that C++ programmers will see are

Let’s look at these from the point of view of the compiler.

3.4.1 Syntax errors

Assume that the compiler has read part, but not all, of your program. The part that has just been read contains a syntax error. For the sake of example, let’s say you wrote:

x = y + 2 * x // missing semi-colon

Now, when the compiler has read only the first line, it can’t tell that anything is wrong. That’s because it is still possible, as far as the compiler knows, that the next line of source code will start with a “;” or some other valid expression. So the compiler will never complain about this line.

If the compiler reads another line, and discovers that you had written:

x = y + 2 * x // missing semi-colon
++i;

it still won’t conclude that there’s a missing semi-colon. For all it knows, the “real” mistake might be that you meant to type “+” instead of “++”.

Now, things can be much worse. Suppose that inside a file foo.h you write

class Foo {
    ⋮
   Foo();
   int f();
   // missing };

and inside another file, bar.cpp, you write

#include "foo.h"

int g() { ... }

void h(Foo) { ... }

int main()  { ... }

Where will the error be reported? Probably on the very last line of bar.cpp! Why? Because until then, it’s still possible, as far as the compiler knows, for the missing “};” to come, in which case g, h, and main would just be additional member functions of the class Foo.

So, with syntax errors, you know only that the real mistake occurred on the line reported or earlier, possibly even in an earlier-\#include’d file.

3.4.2 undeclared and undefined symbols

See this discussion.

3.4.3 type errors

When you use the wrong object in an expression or try to apply the wrong operator/function to an object, the compiler may detect this as a type mismatch between the function and the expression supplied as the parameter to that function. These messages seem to cause students the most grief, and yet the compiler is usually able to give very precise descriptions of what is going wrong. The line numbers are usually correct, and the compiler will often tell you exactly what is going wrong. That explanation, however, may be quite lengthy, for three reasons:

  1. Type names, especially when templates are involved, can be very long and messy-looking.

  2. Because C++ allows function overloading (multiple functions with the same name, as long as they take different kinds of parameters), there may be many functions with the same name. The compiler will have to look at each of these to see if any one matches the parameter types you supplied. Some compilers report on each function tried, explaining why it didn’t match the parameters in the faulty call.

  3. If the function call was itself produced by a template instantiation or an inline function, then the problem is detected at the function call (often inside a C++ standard library routine) but the actual problem lies at the place where the template was used/instantiated. So most compilers will list both the line where the error was detected and all the lines where templates were instantiated that led to the creation of the faulty call.

So, to deal with these, look at the error message on the faulty function call. Note what function/operator name is being complained about. Then look at the line where the faulty call occurred. If it’s inside a template or inline function that is not your own code, look back through the “instantiated from” or “called from” lines until you get back into your own code. That’s probably where the problem lies.

Here’s an example taken from a student’s code:

g++ -g -MMD -c testapq.cpp
/usr/local/lib/gcc-lib/sparc-sun-solaris2.7/2.95.2/../../../../include/g++-3/
stl_relops.h: In function `bool operator ><_Rb_tree_iterator<pair<const 
 PrioritizedNames,int>,pair<const PrioritizedNames,int> &,pair<const 
 PrioritizedNames,int> *> >(const _Rb_tree_iterator<pair<const 
 PrioritizedNames,int>,pair<const PrioritizedNames,int> &,pair<const 
 PrioritizedNames,int> *> &, const _Rb_tree_iterator<pair<const 
 PrioritizedNames,int>,pair<const PrioritizedNames,int> &,pair<const 
 PrioritizedNames,int> *> &)':
adjpq.h:234:   instantiated from `adjustable_priority_queue<
 PrioritizedNames,map<PrioritizedNames,int,CompareNames,allocator<int> >,
 ComparePriorities>::percolateDown(unsigned int)'
adjpq.h:177:   instantiated from `adjustable_priority_queue<PrioritizedNames,
 map<PrioritizedNames,int,CompareNames,allocator<int> >,
 ComparePriorities>::makeHeap()'
adjpq.h:84:   instantiated from here
 /usr/local/lib/gcc-lib/sparc-sun-solaris2.7/2.95.2/../../../../include/
 g++-3/stl_relops.h:43: no match for `const _Rb_tree_iterator<pair<const 
 PrioritizedNames,int>,pair<const PrioritizedNames,int> &,pair<const 
 PrioritizedNames,int> *> & < const _Rb_tree_iterator<pair<const 
 PrioritizedNames,int>,pair<const PrioritizedNames,int> &,pair<const 
 PrioritizedNames,int> *> &'

Now, that may look intimidating, but that’s mainly because of the long type names (due to template use) and the long path names to files from the C++ standard library. Let’s strip that down to the essentials:

g++ -g -MMD -c testapq.cpp
stl_relops.h: In function `bool operator >:
adjpq.h:234:   instantiated from `percolateDown(unsigned int)'
adjpq.h:177:   instantiated from `makeHeap()'
adjpq.h:84:   instantiated from here
stl_relops.h:43 no match for ... < ...

This one is actually worse than most error messages, because it’s easy to miss the “<” operator amidst all the < ... > template markers.

The problem is a “no match for” a less-than operator call in line 43 of a template within the standard library file stl_relops.h. But that template is instantiated from the student’s own code (adjpq.h) and so the thing to do is to look at those three lines (234, 177, and 84) for a data type that is supposed to support a less-than operator, but doesn’t.

3.4.4 const errors

Technically, “const”-ness is part of a type, so while sometimes these get special messages of their own, often they masquerade as ordinary type errors and must be interpreted in the same way.

3.5 Why are some error messages so long?

Usually because the compiler is trying to give you as much useful information as it can.

A lot of the error message may be concerned with possible locations of the mistake. This is particularly true if the compiler detects the error in code that you yourself did not write. Here’s an example:

In file included from ../library.h:5,
                 from ../foo.cpp:9:
../book.h:11:17: error: 'string' has not been declared
   11 |  void setTitle (string& s);

Notice how much of this error message is concerned not with what was wrong, but _where_ it went wrong and why the compiler was even looking there in the first place. In this case it tells us the error was detected in line 11, column 17 of book.h (i.e., “book.h:11:17”) and that the compiler got there because book.h was #included by library.h which in turn was #included by foo.cpp.

Here’s another example:

../foo.cpp: In function 'int main(int, char**)':
../foo.cpp:17:13: error: cannot convert 'int' to 'std::string&' {aka 'std::basic_string<char>&'}
   17 |  b.setTitle(23);
      |             ^~
      |             |
      |             int
In file included from ../library.h:5,
                 from ../foo.cpp:9:
../book.h:11:30: note:   initializing argument 1 of 'void Book::setTitle(std::string&)'
   11 |  void setTitle (std::string& s);
      |                 ~~~~~~~~~~~~~^

Again we see lots of information about the location where the error was detected, then we see the core error message, and this time we also get additional helpful info about other locations in the code that might be related to this error.

A more daunting example:

stl_relops.h: In function `bool operator ><_Rb_tree_iterator<pair<const 
 PrioritizedNames,int>,pair<const PrioritizedNames,int> &,pair<const 
 PrioritizedNames,int> *> >(const _Rb_tree_iterator<pair<const 
 PrioritizedNames,int>,pair<const PrioritizedNames,int> &,pair<const 
 PrioritizedNames,int> *> &, const _Rb_tree_iterator<pair<const 
 PrioritizedNames,int>,pair<const PrioritizedNames,int> &,pair<const 
 PrioritizedNames,int> *> &)':
adjpq.h:234:   instantiated from `adjustable_priority_queue<
 PrioritizedNames,map<PrioritizedNames,int,CompareNames,allocator<int> >,
 ComparePriorities>::percolateDown(unsigned int)'
adjpq.h:177:   instantiated from `adjustable_priority_queue<PrioritizedNames,
 map<PrioritizedNames,int,CompareNames,allocator<int> >,
 ComparePriorities>::makeHeap()'
adjpq.h:84:   instantiated from here
 /usr/local/lib/gcc-lib/sparc-sun-solaris2.7/2.95.2/../../../../include/
 g++-3/stl_relops.h:43: no match for `const _Rb_tree_iterator<pair<const 
 PrioritizedNames,int>,pair<const PrioritizedNames,int> &,pair<const 
 PrioritizedNames,int> *> & < const _Rb_tree_iterator<pair<const 
 PrioritizedNames,int>,pair<const PrioritizedNames,int> &,pair<const 
 PrioritizedNames,int> *> &'

Here again, the bulk of this message is location info. Several locations are named, and the compiler really has no way of knowing which of them is responsible for actual mistake. You might need to look at all of them, but you should probably start by focusing on the locations inside your code, not inside the C++ std library code.

The actual core error message is comparatively short and is a very common message, although the details that follow are rather messy because of the sheer length of the data type names involved. details

As you read long error messages, try to separate out

  1. the core error message, from the
  2. location info, generally introduced by the phrases
    • “included from”
    • “required by”, or
    • “instantiated from”
  3. and auxiliary “helpful” information, often introduced by
    • “Note”, or
    • “Candidates are”

3.6 What are formal and actual parameters?

The formal parameters of a function are the parameter names that are declared in the function header and that are used when we write the function body. For example, in the code

int sequentialInsert (T a[], unsigned& n, const T& x)
// insert x into sorted position within a,
//   with a already containing n items.
//   Return the position where inserted.
{
  int i = n;
  while ((i > 0) && (x < a[i-1]))
      {
       a[i] = a[i-1];
       i = i - 1;
      }
  a[i] = x;
  ++n;
  return i;
}   

the formal parameters are named a, n, and x. The actual parameters of a call to a function are the values passed by the caller. So, in the call

k =  sequentialInsert (myArray, size-1, value);

the actual parameters are myArray, size-1, and value. Note that formal parameters are always just names. Actual parameters can be simple names or arbitrarily complicated expressions.

4 The C++ Programming Language

4.1 What’s the odd expression with the ‘?’ and ‘:’ ?

You’re probably looking at a conditional expression. It’s a convenient shorthand for an if-then-else structure inside an ordinary expression. A typical example would be

x = (x < 0.0) ? -x : x;

The part before the ‘?’ is the condition and is evaluated first. If the condition is true, then the then-part expression (between the ‘?’ and the ‘:’) is evaluated and the result used as the value of the entire expression. If, however, the condition is false, then the else-part (after the ‘:’) is evaluated and that result is used as the value of the entire expression. This assignment, then, replaces x by its own absolute value. The whole thing, then, is equivalent to

double temp;
if (x < 0.0)
  temp = -x;
else
  temp = x;
x = temp;

A conditional expression can apear inside other expressions, anywhere a value of the same type as its then-part and else-part might appear:

x = sqrt((x < 0.0) ? -x : x);

4.2 How do I convert a string to a character array (or a character array to string)?

To get a character array from a std::string, use the string’s c_str() function:

std::string str;
   ⋮
char* cstr = str.c_str();

You will often see this done with older library functions that were originally designed to work with character arrays and not yet updated to work with strings:

copyFile.cpp
void copyFile (string fileName)
{
   ifstream input (fileName.c_str()); // open an input file;
   ofstream output ("output.txt"); // No c_str() required - "output.txt" is a
                                   //    character array, not a string.
   string line;
   getline (input, line);
   while (input) 
   {
      output << line << endl;
      getline (input, line);
   }   
}

Going in the opposite direction is even simpler. The string class has a constructor for building strings from character arrays, so this takes palce automatically most of the time:

void copyFile (string fileName);
   ⋮
copyFile ("input.dat");  // automatically converted to std::string

4.3 How do I convert a string to a number (or a number to a string)?

There are some quick-and-dirty functions for doing this in <cstdlib> for converting to numbers:

#include <cstdlib>
using namespace std;
   ⋮
int i = atoi("123");
double f = atof("3.14159");

Now, these functions actually convert from character arrays, not strings, so if you have a string you need to convert to a character array:

#include <cstdio>
#include <string>
using namespace std;
   ⋮
string s1 = "123";
string s2 = "3.14159";
   ⋮
int i = atoi(s1.c_str());
double f = atof(s2.c_str());

If you need to go in the other direction, or if you need to deal with strings with unusual formatting, then there is a more general technique. In fact, you can convert any datatype that has << and >> I/O operators to and from strings by reading from and writing into a string. The istringstream is an input stream that reads from a string:

#include <sstream> // provides istringstream and ostringstream
#include <string>
using namespace std;
   ⋮
string s1 = "123 3.14159";
   ⋮
istringstream in (s1); // create a stream reading from s1
int i;
double f;
in >> i >> f;  // i will contain 123 and f will contain 3.14159

The ostringstream is an output stream that writes into a string:

#include <sstream> // provides istringstream and ostringstream
#include <string>
using namespace std;
   ⋮
string s1;
ostringstream out (); // create a stream writing into a string
int i = 245;
double f = 1.2;
out << i << ":" << f;
string s = out.str();  // Retrieve the string we have written
cout << s << endl;     // Prints "245:1.2"

Again, let me point out that this stringstream approach can be used to convert between string and any data type that you can read and write.

4.4 What is the difference between a declaration and a definition?

Pretty much everything that has a “name” in C++ must be declared before you can use it. Many of these things must also be defined, but that can generally be done at a much later time. You declare a name by saying what kind of thing it is:

 const int MaxSize;          // declares a constant
 extern int v;               // declares a variable
 void foo (int formalParam); // declares a function (and a formal parameter)
 typedef Bar* BarPointer;    // declares a type name
 using BarPointer = Bar*;    // declares a type name (same as previous example)

 class Bar{ ... };               // declares a class
 {
    ⋮
    void bar (int formalParam);  // declares a member function within a class
    ⋮
    int z;                       // declares a data member within a class
 };    

In most cases, once you have declared a name, you can write code that uses it. Furthermore, a program may declare the same thing any number of times, as long as it does so consistently. That’s why a single .h file can be included by several different .cpp files that make up a program — most .h files contain only declarations. You define constants, variables, and functions as follows:

 const int MaxSize = 1000;                   // defines a constant
 int v;                                      // defines a variable
 void foo (int formalParam) {++formalParam;} // defines a function
 
 void Bar::bar(int formalParam);  // defines a member function within a class

A definition must be seen by the compiler once and only once in all the compilations that get linked together to form the final program.

A definition is itself also a declaration (exception: member functions within classes).

4.5 What goes in a .h file? What goes in a .cpp file?

The short answer is that a .h file contains shared declarations, a .cpp file contains definitions and declarations that you don’t want to share..

It’s important that you understand difference between declarations and definitions.

Never, ever, ever name a .cpp file in an #include.

That defeats the whole purpose of a C++ program structure.

4.6 What is an inline function?

When we define a function, it is usually compiled into a self-contained unit of code. For example, a function

int foo(int a, int b)
{
  return a+b-1;
}

would compile into a block of code equivalent to

stack[1] = stack[3] + stack[2] - 1; 
jump to address in stack[0]

where the “stack” is the runtime stack a.k.a. the activation stack used to track function calls at the system level, stack[0] is the top value on the stack, stack[1] the value just under that one, and so on. A function call like

  x = foo(y,z+1);

would be compiled into a code sequence along the lines of

push y onto the runtime stack; 
evaluate z+1; 
push the result onto the runtime stack
push (space for the return value) onto the runtime stack 
save all CPU registers
push address RET onto the runtime stack 
jump to start of foo's body 
RET: x = stack[1] 
pop runtime stack 4 times 
restore all CPU registers

As you can see, there’s a fair amount of overhead involved in passing parameters and return address information to a function when making a call. The amount of time spent on this overhead is really all that large. If the function body contains several statements in any kind of loop, then the overhead is probably a negligable fraction of the total time spent on the call.

class Foo {
private:
   int bar;
public:
   int getBar ();
   void setBar (int);
};

int Foo::getBar ()  {return bar;}

void Foo::setBar (int b) {bar = b;}

But many ADTs have member functions that are only one or two lines long, and often trivial lines at that. For these functions, the overhead associated with each call may exceed the time required to do the function body itself. Furthermore, because these functions are often the primary means of accessing the ADT’s contents, sometimes these functions get called thousands of times or more inside the application’s loops.

For these kinds of trivial functions, C++ offers the option of declaring them as inline.

class Foo {
private:
   int bar;
public:
   int getBar () {return bar;}  
   void setBar (int);
};

inline
void Foo::setBar (int b) {bar = b;}

An inline function can be written one of two ways. First, it can be written inside the class declaration. Second, we can place the reserved word inline in front of the function definition written in its usual place outside the class declaration. When we make a call to an inline function, the compiler simply replaces the call by a compiled copy of the function body (with some appropriate renaming of variables to avoid conflicts). So, if we have

inline int foo(int a, int b)
{
  return a+b-1;
}

and we later make a call

  x = foo(y,z+1);

This would be compiled into a code sequence along the lines of

evaluate z+1, storing result in tempB 
evaluate y + tempB - 1, storing result in x

Most of the overhead of making a function call hs been eliminated.

Inline functions can reduce the run time of a program by removing unnecessary function calls, but, used unwisely, may also cause the size of the program to explode. Consequently, they should be used only by frequently-called functions with bodies that take only 1 or 2 lines of code. For larger functions, the times savings would be negligible (as a fraction of the total time) while the memory penalty is more severe, and for infrequently used functions, who cares?

Inlining is only a recommendation from the programmer to the compiler. The compiler may ignore an inline declaration and continue treating it as a conventional function if it prefers. In particular, note that inlining of functions with recursive calls is impossible, as is inlining of most virtual function calls. Many compilers will refuse to inline any function whose body contains a loop. Others may have their own peculiar limitations.

4.7 Why is operator++ sometimes declared with an int parameter?

The ++ and -- operators are unusual in that they can be written in either prefix (++x, --x) or postfix (x++, x--) form. Whether you write ++x or x++, the value of x is increased by 1. But when you write a ++ expression inside another expression, its return value depends on whether you used the prefix or postfix form.

So, for example, the code

int i = 0; 
int j = 0;
cout << ++i << ' ' << j++ << endl;
cout << i << ' ' << j << endl;

would print

1 0
1 1

Now that’s all very well for the builtin ++ for int, but what happens when we write ++ for our own classes? Like most operators, ++ can be thought of as a shorthand for a function named operator++, so it’s not too hard to see that we can say:

class SomethingWeCanIncrement
{
  ⋮
  SomethingWeCanIncrement& operator++ (); 
  ⋮
};

but, somewhat late in the game, the designers of C++ realized that they had neglected to provide a syntax for indicating whether a unary operator was prefix or postfix. This is only a problem for ++ and --, because these are the only operators that can be written in both forms. The solution they came up with is a complete kludge. If you declare

const MyIncrementableClass operator++();
const MyIncrementableClass operator--();

you are declaring the prefix operators. If you declare

MyIncrementableClass operator++(int);
MyIncrementableClass operator--(int);

you are declaring the postfix operators.

What do you do with the int parameter for the postfix operators?

Absolutely nothing! It’s just a dummy parameter used to distinguish the prefix and postfix forms. Finally, note that the prefix forms return a reference. The postfix forms return a non-reference value. That’s because the prefix forms are returning the value that has been incremented/decremented. That value exists, so it’s easy to return:

class MyIncrementableClass {
   ⋮
  const MyIncrementableClass operator++() {
        ⋮
     // do what you need to do to increment it
        ⋮
     return *this;
  }
   ⋮

On the other hand, the postfix form returns the value before the increment/decrement takes place. Usually the only way to do that is to make a copy of that value first, then do the increment, then return the copied value.

class MyIncrementableClass {
   ⋮
  const MyIncrementableClass operator++(int) {
        MyIncrementableClass clone = *this; // save old value
        operator++();                       // increment this
        return clone;                       // return the old value
  }
   ⋮

4.8 What is the Rule of the Big 3?

The Big 3 in C++ class design are the copy constructor, destructor, and assignment operator.

The Rule of the Big 3 states that, if you ever find yourself needing to provide your own version of any one of the Big 3, you should provide your own version of all three.

The C++ compiler will provide its own version of these if the programmer does not do so. However, the compiler-generated versions for a class are usually inappropriate if

  1. The class has data members that are pointers, and
  2. The pointers denote data that should not logically be shared.

Like most such rules, there can be exceptions, but programmers should only violate this rule knowingly and after full consideration of the possible consequences.

4.9 What is an “invalid” iterator?

Iterators can become invalid if the container that they point inside is changed. Operations on invalid iterators are illegal and can have unpredictable results, much like operating on a dangling or uninitialized pointer.

For example, the following code to remove all even numbers in a list…

list<int> myList;
    ⋮
for (list<int>::iterator it = myList.begin(); it != muList.end(); ++it)
{
  if (*it % 2 == 0)
     myList.erase(it);
}

is illegal, because after any erase, it is invalid. That means that the next ++it will have unpredictable results. This can be fixed fairly easily.

list<int> myList;
   ⋮
for (list<int>::iterator it = myList.begin(); it != muList.end(); )
{
  list<int>::iterator next = it;
  ++next;
  if (*it % 2 == 0)
     myList.erase(it);
  it = next;
}

as this avoids using the position stored in it after the erase call.

However, this fix does not work if we are using a vector or deque, because for those containers, erase invalidates not only iterators to the erased position but iterators to all following positions.

General rules:

4.10 I have other C++ questions.

5 C++ Compilers and IDEs

5.1 What is an IDE?

IDE stands for Integrated Development Environment. An IDE provides a convenient way to access and work with compilers and debuggers.

Many people confuse IDEs with compilers. They may talk about using the “Code::Blocks” compiler, for example. But compilers and debuggers are command-line tools – they don’t pop up windows with menus, toolbars, and convenient editors. All that convenient interface stuff is the province of an IDE.

A typical IDE provides

Some IDEs go much further, with support for external build managers, unit testing, code transformation or refactoring, issue tracking and task management, etc.

IDEs commonly in use in ODU CS classes include:

All of the above except xcode can be run on Windows, Linux, and MacOs PCs.

Some IDEs are tied to specific programming languages and, sometimes, specific compilers. Others will work with multiple programming languages and with whatever compilers and debuggers you have already installed on your PC.

5.2 How can I install a compiler and IDE on my own PC?

See Installing a C++/Java IDE on Your Own PC

5.3 How do I use a make file in my IDE?

A make file contains instructions on how to compile the code of a project. These instructions are interpreted by a program called make, which is covered in CS252. make is what we call a build manager, a program designed to automate the steps in building a software project.

If you have a complicated project, creating a make file can allow you to avoid typing long sequence of commands to compile all of your code.

Alternatively, some instructors provide make files with their assignments. You will recognize these because they are titled makefile or Makefile. Using an instructor-supplied make file can help guarantee that you are compiling your code using the same settings the instructor will use when grading your code.

But most IDEs have their own build managers “built in”. In many cases that will be good enough, particularly if you take the time to set your compiler options to the appropriate values.

But sometimes you will really need to or want to use that make file.

5.3.1 Using make files from the command line.

Assuming that you are on a machine with the make program installed, just type

make

to build your project. If that does not work, try

make all

Type

make clean

to clean up (remove anything produced automatically, leaving the source code unchanged).

“all” and “clean” above are examples of make file targets, options written in to the make file to trigger a series of commands. Actually, there aren’t hard and fast rules on the target names. But most people who write make files set them up so that, by default, make and/or make all builds the project and make clean clean up after it. If those don’t work for you, you’ll have to ask the author of the make file or read it yourself.

5.3.2 Using make files from Eclipse

  1. Set up a project directory with your source code and the make file. Remember where you put this directory!

  2. In Eclipse, from the File menu, select Import..., then C/C++, then Existing code as makefile project. Click “Next”.

  3. On the next screen, use the Browse button to select the directory where you set up your project.

    Fill in a project name, select the appropriate programming language, and make sure the “Toolchain” selects a compiler on that machine.

    Click “Finish”.

If you have already created your project as an “Executable” (which means that you requested that Eclipse use its own built-in build manager), this is easily remedied.

  1. Take note of what directory the project is stored in. If you aren’t sure, use Project -> Properties to find out.

  2. Clean the project (available via the Project menu).

  3. In the Project Explorer list on the left, right-click on your existing C++ project and select “Delete”.

    Now, we only want to delete the project settings from Eclipse, not your source code. So when the box pops up to confirm the deletion, make sure that the “Delete project contents on disk” is not checked.

  4. In your operating system, go to the directory where your project was stored. Delete the .project and .cproject files.

  5. Now go back into Eclipse and import that directory as a new C++ “Existing code as makefile project”, as described earlier.

5.3.3 Using make files in VSCode

  1. In your project directory, create a subdirectory named .vscode, if you do not already have one.

  2. Put this file into that .vscode directory, naming it tasks.json.

    tasks.json.listing
    {
        "version": "2.0.0",
        "tasks": [
            {
                "label": "make -k",
                "type": "cppbuild",
                "command": "/usr/bin/make",
                "args": ["-k"],
                "problemMatcher": ["$gcc"],
                "group": {
                    "kind": "build",
                    "isDefault": true
                }
            }
        ]
    }
    
  3. Press Ctrl-Shift-B to Build your project using make.

5.3.4 Using make files in Code::Blocks

(If you need to do this frequently, it’s probably time to move up to a more professional IDE.)

  1. Create your C++ project as usual.

  2. Then go to Project -> Properties -> Project settings, and by “Makefile:”, make sure that the file listed is the appropriate location and spelling of of your make file, then put a check in the “This is a custom Makefile” box.

  3. Now go to the “Build targets” tab.

    By default, Code::Blocks uses make file targets “Debug” and “Release”, but those are rarely seen in typical makefiles.

    Use the Add button to add the “real” targets of your makefile. (As noted earlier, “all” and “clean” are among the most common, but you may have to read the make file to be sure.)

    Optionally, you can use the “Delete” button to remove the “Debug” and “Release” targets.

  4. Under “Output filename”, enter the name (and location) of the executable produced by the makefile.

    • If you don’t know how to read make files, you may have to run it once to find out.

  5. Click OK to save the setting changes.

To compile your code, go to the Build menu and then Select target to select “all”. Then click the usual build button.

To clean up your project directory, go to the Build menu and then Select target to select “clean”. Then click the same build button.

5.4 How do I activate C++17 features when compiling?

By now, much of the C++ code you are likely to encounter will make use of features introduced in the C++ 2014 or 2017 standard. Most compilers default to the 1998 language definition. You will need to be sure that you are compiling with the appropriate options set.

In the GNU g++ and Clang compiler suites, the relevant compiler option to activate C++17 features is

-std=c++17

If you are typing your compiler commands directly at the command line, just add this.

But, more likely, you are using some sort of builder, either make or an IDE (Code::Blocks or Eclipse) or a makefile invoked from an IDE.

5.4.1 make Files

If you are using make, your makefile will generally have a list of options provided explicitly for your uses of g++. Just add -std=c++17 to that list.

5.4.2 CodeBlocks

  1. From the Settings menu, select “Compiler…”

  2. You should be on the “Global compiler settings” tab. If not, select it.

  3. Put a checkmark by the option:

      Have g++ follow ... C++17 ISO ...
    
  4. Click OK to accept the changes. Then from the “Project” menu select “Project Clean”, then rebuild your project.

5.4.3 Eclipse (default C++ builder)

If you are using Eclipse and specified “C++ project”, you have requested that Eclipse use its default builder. You set your compilation options from the project settings menu.

  1. Right-click on your project and select “Properties” or select “Properties” from the “Project” menu.

  2. Click on “C/C++ Build” then “Settings”. Select the “…C++ Compiler” that you are using.

  3. Select “Dialect”, and choose “ISO C++17”.

  4. Click OK to accept the changes. Then from the “Project” menu select “Project Clean”, then rebuild your project.

5.4.4 Eclipse (makefile project)

If you are using Eclipse and specified “Makefile project with existing code”, you have requested that Eclipse run “make” to build your code. Edit your makefile as described above.

You may find, however, that the Eclipse editor reports errors as you are editing your code that do not actually arise when you compile/build. That may be because the Eclipse editor is using pre-2017 rules. To fix,

  1. Right-click on your project and select “Properties” or select “Properties” from the “Project” menu.

  2. Select “C/C++ General” => “Preprocessor Include Paths…”. Look at the “Providers” tab. Look for the entry that seems to most directly describe your compiler (e.g., “CDT GCC Built-in Compiler Settings CygWin” or “CDT GCC Built-in Compiler Settings MinGW”) and use the “MoveUp” button to position this at the top of the list

  3. Click OK to accept the changes. Then from the “Project” menu select “C/C++ Index” => “Rebuild”. Repeat the rebuild if necessary.

  4. From the “Project” menu select “Project Clean”, then rebuild your project.

5.5 How do I set compiler flags and options?

For most assignments, I recommend the following options:

-g -std=c++17 -Wall -D_GLIBCXX_DEBUG -fsanitize=address

If you are typing your compiler commands directly at the command line, just add this.

But, more likely, you are using some sort of builder, either make or an IDE (Code::Blocks or Eclipse) or a makefile invoked from an IDE.

5.5.1 make Files

If you are using make, your makefile will generally have a list of options provided explicitly for your uses of g++. Edit them to match the above.

5.5.2 CodeBlocks

  1. From the Settings menu, select “Compiler…”

  2. You should be on the Global compiler settings tab. If not, select it. Within that, look for a “Compiler Flags” tab. Again, you are probably already on it. If not, select it.

  3. Put a checkmark by each of the following:

       Have g++ follow ... C++17 ISO ...
    
       Enable all common compiler warnings
    
       Enable extra compiler warnings
    
       Enable Effective-C++ warnings
    
  4. Now go to the #defines tab. In the text box enter, on a line by itself,

       _GLIBCXX_DEBUG
    

    Be sure to get both of the underscore (_) characters in there.

  5. Click OK to accept the changes. Then from the “Project” menu select “Project Clean”, then rebuild your project.

5.5.3 Eclipse (default C++ builder)

If you are using Eclipse and specified “C++ project”, you have requested that Eclipse use its default builder. You set your compilation options from the project settings menu.

  1. Right-click on your project and select “Properties” or select “Properties” from the “Project” menu.

  2. Click to open the “C/C++ Build” list, then click on “Settings”. Select the “…C++ Compiler” that you are using.

  3. Select “Dialect”, and choose “ISO C++17”.

  4. Select “Warnings” annd check the options for -Wall and -Wextra.

  5. Select “Miscellaneous” and add -Weffc++ to the “Other flags”.

  6. Select “Preprocessor” and, on the “Defined symbols” box, use the icon with the green plus sign to add

        _GLIBCXX_DEBUG
    

    Be sure to get both of the underscore (_) characters in there.

  7. Click OK to accept the changes. Then from the “Project” menu select “Project Clean”, then rebuild your project.

5.5.4 Eclipse (makefile project)

If you are using Eclipse and specified “Makefile project with existing code”, you have requested that Eclipse run “make” to build your code. Edit your makefile accordingly.

You may find, however, that the Eclipse editor reports errors as you are editing your code that do not actually arise when you compile/build. That may be because the Eclipse editor is using pre-2014 rules. To fix,

  1. Right-click on your project and select “Properties” or select “Properties” from the “Project” menu.

  2. Select “C/C++ General” => “Preprocessor Include Paths…”. Look at the “Providers” tab. Look for the entry that seems to most directly describe your compiler (e.g., “CDT GCC Built-in Compiler Settings CygWin” or “CDT GCC Built-in Compiler Settings MinGW”) and use the “MoveUp” button to position this at the top of the list

  3. Click OK to accept the changes. Then from the “Project” menu select “C/C++ Index” => “Rebuild”. Repeat the rebuild if necessary.

  4. From the “Project” menu select “Project Clean”, then rebuild your project.

5.5.5 VSCode (non-makefile project)

If you have not already done so, set up a build task:

  1. Click on any .cpp file in the file listing to bring it up in the menu. VSCode will recognize this as C++ code, however it does not yet know how to compile your project. Our next few steps will set that up.

  2. With the editor still showing the C++ file, select the Terminal -> Configure Default Build Task menu item.

    A number of choices will drop down.

    Select “C/C++ g++ build active file”.

    This will create a new file in your project folder, .vscode/tasks.json.

Now change the default build as follows:

  1. Click on .vscode/tasks.json in the file listing to open it in the editor.

    The default build task is designed to compile and link whatever .cpp file you currently have open in the editor.

    That’s OK if you only have a single compilation unit (.cpp file). But if you are going to have more than one, you’ll need to change this.

  2. Edit the “label” to rename this task to “C/C++: compile all”

  3. In the args list, replace "${file}" by "*.cpp"
  4. Replace the final argument, "${fileDirname}/${fileBasenameNoExtension}", by whatever you would like the compiled program to be named, inside quotes.
  5. After the "-g", add the compilation arguments that you desire. Add these one at a time, inside quotation marks, separated by commas.

    For example, I generally recommend the options -std=c++17, -Wall, and -D_GLIBCXX_DEBUG.

    An example of a revised task definition would be:

    ```
    {
        "type": "cppbuild",
        "label": "C/C++: compile all",
        "command": "/usr/bin/g++",
        "args": [
           "-g",
           "-std=c++17",
           "-Wall",
           "-D_GLIBCXX_DEBUG",
           "*.cpp",
           "-o",
           "myProgram"
        ],
        "options": {
           "cwd": "${workspaceFolder}"
        },
        "problemMatcher": [
           "$gcc"
        ],
        "group": {
           "kind": "build",
           "isDefault": true
        },
        "detail": "compiler: /usr/bin/g++"
    }
    ```
    

    Save your changes to that file.

  6. You should now be able to compile your code with the key sequence Ctrl+Shift+B or by selecting the menu item `Terminal -> Run Build Task…"

5.6 How do I supply command line parameters when executing my programs?

Often you will be writing programs that take “command line parameters” as part of their inputs.

Of course, if you are executing a program from the command line, you just type the parameter values on the command line (hence the name!), e.g.,

./myProgram ../testData/myTestData.txt 23

But what if you are launching your program from an IDE?

5.6.1 Eclipse

  1. After you have successfully compiled your code, click on your executable binary in the Project Explorer). Then, from the Run menu, select Run configurations...

    You’ll see a list of different project types, one of which should be “C/C++ Application”.

    • Underneath that, you might already have a configuration for this program (Clicking on a configuration will show you what project and what executable file it is associated with.

    • If not, select “C/C++ Application”, then at the cop of the columm click on "_New launch configuration`".

  2. On the “Arguments” tab, enter your command line parameters into the “Program Arguments” box.

  3. Click Run to save these arguments and launch your program.

Video of this procedure (for Java, but the procedure is similar)

5.6.2 VSCode

Normal execution (no debugger)

For C++ programs, the preferred way to run your compiled program is to use the command line from the built-in terminal. (There is an option to “Run without Debugging” in the Run menu, but as of this writing it does not work. Specifically, it actually launches the debugger despite its name.)

  1. Look at the bottom pane in the central/main column (the one with the editor). If you do not see a Terminal tab, use the menu item Terminal => New Terminal to create one.

  2. To run your program type the path to the executable file, followed by any command parameters you need. For example,

    ./assignment1 "hello" 42    
    

Running the Debugger

Running in the debugger, with or without command line parameters, requires some preparation.

  1. Be sure that you have set up the debugger in your project directory by following these directions.

  2. You will now have a file .vscode/launch.json that will allow you to launch your program in a debugger by pressing F5 or using the menu entry.

    Open that file in the editor and look for the line

        "args": [],  
    

    Inside the brackets, you can add your desired command line parameters as a comma-separated list of quoted strings. For example,

        "args": ["hello", "42"],
    

    Save your changes.

  3. To launch the debugger, you need a file with the same base name as your executable, but with a different file extension, one that is associated with an editable file type.

    For example, if your executable file is named assignment1.exe, select a file named assignment1.h or assignment1.cpp or even assignment1.txt. If you don’t have a file with the appropriate base name, create and empty file with that base name and the “.txt” extension.

    Select that file (opening it in the editor), and then type the F5 key or use the menu item Run => Start Debugging.

5.7 How do I get my program to read from a file instead of from the keyboard?

At the command line, this is called input redirection and is done by appending

< location_of_input_file 

to the end of the command launching the program. You can read more about this in CS252, and it works the exact same way in a Windows command-line session.

What if you are launching your program from an IDE?

5.7.1 Code::Blocks

Can’t really be done.

What you can, do, however, is to

  1. Open your file of input text in the Code::Blocks editor.

  2. Run the program.

  3. Then, when it pauses for input, instead of typing the input directly, copy-and-paste lines of text from the input file in the editor into the running program.

    • You can usually copy-and-paste many lines of input at once, because the underlying run-time system will simply buffer up unused input until later input statements are reached.

  4. Indicate the end of input, if necessary, by typing the appropriate character depending on your operating system: Ctrl-Z for Windows, Ctrl-D (at the start of a new line) for Linux and MacOs,

5.7.2 Eclipse

After you have successfully compiled your code, click on your executable binary in the Project Explorer). Then, from the Run menu, select Run configurations...

You’ll see a list of different project types, one of which should be “C/C++ Application”.

On the “Common” tab, under “Standard input and output”, click to select the “Input” box, then use one of the three buttons on the line below to selectthe file of input data you want supplied as the standard input.

Click Run to save these arguments and launch your program.

5.8 Eclipse does not recognize common names from the std library.

If Eclipse does not seem to recognize things like “string”, “vector”, “cout”, and other common named from the C++ standard library, …

Eclipse tries to be helpful by diagnosing errors while you are typing. Sometimes, however, its errors (marked with ) don’t quite match up with what the compiler will tell you when you build (compiler messages are marked with ).

If the compiler agrees with Eclipse, then the problem is likely in your code.

If the compiler says that your code is OK, but Eclipse flags some of it anyway, sometimes, you can just ignore this there are only a few instances. But if you see a lot of these mismatches, it can indicate that your project is configured improperly.

  1. Try building the code (i.e., running the actual compiler). Eclipse may correct its own recommendations
  2. Rebuild the index (Eclipse’s list of header files used by your code): From the Project menu, select C/C++ Index..., then Rebuild.

5.9 Eclipse does not recognize names of variables and types from your own code.

Eclipse tries to be helpful by diagnosing errors while you are typing. Sometimes, however, its errors (marked with ) don’t quite match up with what the compiler will tell you when you build (compiler messages are marked with ).

If the compiler agrees with Eclipse, then the problem is likely in your code.

If you declare types and variables in your code and Eclipse flags them as unknown, but the compiler says they are fine, …

  1. Make sure that you have saved all of your files, then build the code (i.e., run the actual compiler). Eclipse may correct its own recommendations
  2. Rebuild the index (Eclipse’s list of header files used by your code): From the Project menu, select C/C++ Index..., then Rebuild.

5.10 Eclipse does not recognize ranged-based for loops or other newer C++ features.

  1. Did your code come with a makefile? If so, then make sure that your Eclipse project is set up to use it.

  2. If you are using the automatic Eclipse builder, check the dialect setting for your project.

    From the Project menu, select Properties.

    On the left, select C/C++ Build, then Settings.

    On the right, select your C++ compiler, then Dialect.

    Use the Language standard drop-down list to select the appropriate version of C++. (When in doubt, go for C++14 or C++1x.)

    Click Apply and Close and rebuild the project.

5.11 Eclipse says that your workspace is currently in use.

If you drop your connection to an X2Go session either accidentally (e.g., the network failed) or deliberately (you closed the connection without shutting down your running programs first), X2Go preserves your session. When you reconnect to that same server, X2Go will bring up the windows that you had open when you left.

If you get this message from Eclipse, you probably have an Eclipse session still running on a different server. Select “Choose” and then “Cancel” to get out of this. Then reconnect X2Go via the server you used earlier. If you don’t remember which server that was, you may need to try all of them until you find the one that pops up your old Eclipse window.

This is, by the way, one reason why I recommend configuring your X2Go client to go to specific servers instead of to the switcher linux.cs.odu.edu.

5.12 Eclipse “New Project” does not show an option to create C++ projects

There is a bug in the current installation of Eclipse on our Linux servers that can cause this problem if you switch from one Linux server to another between Eclipse sessions.

  1. One fix is to simply reconnect to the same server that you used before, and to consistently use that server for working in Eclipse.
  2. Alternatively, close down eclipse, do
    rm -r ~/.eclipse
    

    and then restart Eclipse. If you have customized your Eclipse settings, you may lose your customizations by doing this.

5.13 Eclipse will not reopen C++ files, complains about missing cdt components.

There is a bug in the current installation of Eclipse on our Linux servers that can cause this problem if you switch from one Linux server to another between Eclipse sessions.

  1. One fix is to simply reconnect to the same server that you used before, and to consistently use that server for working in Eclipse.
  2. Alternatively, close down eclipse, do
    rm -r ~/.eclipse
    

    and then restart Eclipse. If you have customized your Eclipse settings, you may lose your customizations by doing this.

5.14 Why do compilers’ error messages often give the wrong line number, or even the wrong file?

A compiler can only report where it detected a problem. Where you actually committed a mistake may be someplace entirely different.

Let’s look at a simple example:

5.14.1 Example 1

Assume that the compiler has read part, but not all, of your program. The part that has just been read contains a syntax error. For the sake of example, let’s say you wrote:

x = y + 2 * x // missing semi-colon

Now, when the compiler has read only the first line, it can’t tell that anything is wrong. That’s because it is still possible, as far as the compiler knows, that the next line of source code will start with a “;” or some other valid expression. So the compiler will never complain about this line.

If the compiler reads another line, and discovers that you had written:

x = y + 2 * x // missing semi-colon
++i;

The compiler knows that you did something wrong. But it still won’t conclude that there’s a missing semi-colon. For all it knows, the “real” mistake might be that you meant to type “+” instead of “++”.

5.14.2 Example 2

Now, things can be much worse. Suppose that inside a file foo.h you write

class Foo {
    ⋮
   Foo();
   int f();
   // missing };

and inside another file, bar.cpp, you write

#include "foo.h"

int g() { ... }

void h(Foo) { ... }

int main()  { ... }

Where will the error be reported? Probably on the very last line of bar.cpp! Why? Because until then, it’s still possible, as far as the compiler knows, for the missing “};” to come, in which case g, h, and main would just be additional member functions of the class Foo.

So, with most error messages, you know only that the real mistake occurred on the line reported or earlier, possibly even in an earlier-\#include’d file.

6 C++ Compile-Time Error Messages

6.1 attempt to subscript container with out-of-bounds index

Indicates that one of the std: library container functions has detected an attempt to access or store data that is out of range (e.g., trying to get the N’th item from a vector that only holds N-1 items).

The remainder of the error message will list files and line numbers that may help you trace the point at which the problem was detected.

6.2 attempt to dereference a singular iterator.

Indicates that one of the std: library container functions has detected an attempt to access or store data via an unitialized iterator or an iterator that does not denote a valid position within a container.

6.3 attempt to dereference a past-the-end iterator.

Indicates that one of the std: library container functions has detected an attempt to access or store data via an unitialized iterator or an iterator that does not denote a valid position within a container.

6.4 …discards qualifiers…

The message

In some-function-name, passing const some-type-name … discards qualifiers

occurs when you try to pass a const object to a function that might try to change the object’s value. For example, if you have a class C:

class C {
public:
   C();
   int foo ();
   void bar (std::string& s);
   ⋮  
}

and you try to compile the following code:

void baz (const C& c1, C& c2, const std::string& str)
{
  int i = c1.foo();   // error!
  int j = c2.foo();
  c2.bar(str);        // error!
    ⋮

then a C++ compiler should flag the 1st and 3rd line indicated above. The g++ compiler will say something along the lines of

In function 'void baz(const C&, C&, const std::string&)': 
   passing 'const C' as 'this' argument of 'int C::foo()' discards qualifiers 

In function 'void baz(const C&, C&, const std::string&)':
  passing 'const std::string' as argument 1 of 
  'void C::bar(std::string&)' discards qualifiers

The first message complains that you have passed a const object as the left-hand parameter (implicitly named this) to the function foo, which has not promised to leave that parameter unchanged. You have, in effect, tried to discard the “qualifier” (the word “const”) in the const C& datatype. The second message makes a similar complaint about the string parameter being passed to bar. Again, the object being passed is marked as const, but the declaration of bar suggests that bar is allowed to change the string it receives as a parameter. To get rid of this message, you must examine what it is you are trying to do and determine whether:

6.5 need typename before…, also “warning: … is implicitly a typename” or “warning: implicit typename is deprecated”?

This error arises in certain uses of template parameters (or of names that are typedef’d in terms of a template parameter. For example,

template <class Container, class T>
void fillContainer (Container& c, T value)
{
   Container::iterator b = c.begin();
   Container::iterator e = c.end();
   fill (b, e, value);
}

will probably get one of these messages from g++ complaining about the mentions of “Container::iterator”. The fix is

template <class Container, class T>
void fillContainer (Container& c, T value)
{
   typename Container::iterator b = c.begin();
   typename Container::iterator e = c.end();
   fill (b, e, value);
}

6.6 No matching function …, No match for…

This is a variation on the messages saying a symbol is undeclared. In particular, you will get this message when you call a function, and there are one or more functions with that name, but your set of actual parameters’ data types do not match up with the formal parameter list of any of the declared functions.

Either you are correctly calling a function that you have not declared, or you are trying to call a declared function with the wrong kind of parameters.

This can be one of the longer error messages you will ever get, as g++ tries to list out all the functions with the same name that it knows, with the data types of all their parameters, as a way of showing you all your existing options. Although the list can be a bit daunting, if you are running in a support environment (e.g., emacs) that let’s you step from message to message while displaying the relevant line of code, this list can actually be quite helpful.

6.7 ‘nullptr’ was not identified in this scope

You are compiling a program that uses C++ 2014 features with compiler settings for the 1998 C++ standard.

Change your compiler settings to use the C++14 standard.

6.8 Undeclared/undefined names and symbols

First, look very closely at the error messages. Does it say “undeclared” or “undefined”? These are two very different things, and understanding the difference is the key to fixing the problem.

So, if the compiler says that a function is undeclared, it means that you tried to use it before presenting its declaration, or forgot to declare it at all.

The compiler never complains about definitions, because an apparently missing definition might just be in some other file you are going to compile as part of the program.

But when you try to produce the executable program by linking all the compiled .o or .obj files produced by the compiler, the linker may complain that a symbol is undefined (none of the compiled files provided a definition) or is multiply defined (you provided two definitions for one name, or somehow compiled the same definition into more than one .o or .obj file).

For example, if you forget a function body, the linker will eventually complain that the function is undefined. If you put a variable or function definition in a .h file and include that file from more than one place, the linker will complain that the name is multiply defined.

Undefined symbol messages seem to happen most often with functions. The most likely causes are:

  1. You have forgotten to supply a body for a function.
  2. You misspelled the name of the function in the body, so the compiler thinks you are supplying a body for a completely different function.
  3. You hid the body of a function template in a .cpp file instead of in the .h file where it was declared. (Templates are not like regular functions. Their bodies must be fully visible to any code that uses them.)
  4. You forgot to compile the .cpp file that has the function body, or forgot to include the resulting .o file when you linked the rest of the program together.
    • If you are working in an IDE, you may have forgotten to add that .cpp file to your project.
  5. You gave the wrong compilation command, and told g++ to treat a single .cpp file as the entire program even though there are multiple .cpp files making up the program.

6.9 relocation truncated to fit

Ignore these – they really aren’t helpful.

But these are always, in my experience, accompanied by “undefined reference to” errors, which you definitely need to pay attention to.

7 Runtime Errors

7.1 Segmentation error? Segmentation fault? Bus error? Null reference error?

These are all various errors signaled by the underlying operating system when your program tries to retrieve from, store into, or execute instructions from an address that either doesn’t exist or is reserved for another program. In practical terms, these kinds of messages almost always arise because of

To debug these problems, concentrate on your pointers, arrays, and iterators. Add debugging output or use a debugger to find out which one is being used when the crash occurs. Then work backwards to figure out why that pointer/index/iterator has an invalid value. Keep in mind that you might not be using a pointer, array, or iterator directly, but might be using (abusing?) a function or class that does.

7.2 … “singular iterator” …

A singular iterator is an iterator that does not point to a position in some container. It is the iterator equivalent of an uninitialized pointer. For example,

vector<int>::iterator it;   // it is singular

it above is singular. It does not point to an actual position in a container and will not until it is assigned one, e.g.,

it = myVector.begin();

Most operations on singular iterators are illegal with unpredictable results, much like operating on an uninitialized pointer.

Singular iterators are related to invalid iterators.

7.3 terminate called after throwing an instance of ‘std::out_of_range’

Indicates that one of the std: library container functions has detected an attempt to access or store data that is out of range (e.g., trying to get the N’th item from a vector that only holds N-1 items).

The remainder of the error message will list files and line numbers that may help you trace the point at which the problem was detected.

7.4 LeakSanitizer: detected memory leaks

The LeakSanitizer (activated when compiling with a -fsanitize=... option) has detected that the program allocated blocks of memory that were never properly deleted.

Examine the message details for the source code files and locations at which the memory was allocated. (Of course the messages can’t tell you where you are missing a delete statment, because they can’t point to code that you haven’t written!)

7.5 AddressSanitizer: attempting free on address which was not malloc()-ed

The Address Sanitizer (activated when compiling with a -fsanitize=... option) has detected that the program attempted to delete a block of memory that

Examine the message details for the source code files and locations at which the problem was detected.

7.6 AddressSanitizer: heap-buffer-overflow

The Address Sanitizer (activated when compiling with a -fsanitize=... option) has detected that the program attempted to access data in a block of memory that has been properly allocated. This can be caused by any of

This error is often detected well after the offending action has taken place, making it fairly difficult to debug.

7.7 AddressSanitizer: heap-use-after-free

The Address Sanitizer (activated when compiling with a -fsanitize=... option) has detected that the program attempted to access data in a block of memory that has been deleted.

7.8 AddressSanitizer: NullPointerAccess

The Address Sanitizer (activated when compiling with a -fsanitize=... option) has detected that the program attempted to retrieve or store data via a null pointer.

Examine the message details for the source code files and locations at which the problem was detected.

7.9 AddressSanitizer: SEGV

SEGV stands for segmentation error.

8 Java Programming

8.1 How do I determine the starting class of a Java program?

A starting class for a program must contain a function of the form

static int main (String[] args) {
   ⋮
}

This is quite similar to the main() function used in C++, though because Java does not allow stand-alone functions, the main() function in Java must be a class member. If a project is supposed to provide more than one program, then there may be many different starting classes within the project. A good way to list them quickly (on a Unix/Linux system) is

find yourProjectDirectory -name '*.java' | xargs grep main

8.2 error: the declared package “…” does not match the expected

package “…”

The source code files of Java programs must be arranged in a way that reflects the package and class style of their contents.

  • If you have a Java class MyClass, it must be stored in a file named MyClass.java.

  • If your Java class is inside a package myPackage, then the Java source code must be stored inside a directory named myPackage.

For example, on one of my projects, I have a class edu.odu.cs.AlgAE.Client.Layout.Anchors. That means that the source code for this class starts with:

package edu.odu.cs.AlgAE.Client.Layout;
   ⋮
public class Anchors {
   ⋮

and I would find the file containing that source code file in edu/odu/cs/AlgAE/Client/Layout/Anchors.java. (If you are on Windows, the same rule applies, but you use \ instead of / in the path.)

So, when you get the “package does not match” error, the possible causes are:

That last possibility is often the one that trips people up, so let’s talk about it.

8.2.1 Compiling from the Command Line

Suppose you have a class named MyPackage.SubPackage.MyClass. That should be in a file MyPackage/SubPackage/MyClass.java.

The command to compile this is

javac compiler-options MyPackage/SubPackage/MyClass.java

So it makes sense that this will only work if you are cd’d into the directory where MyPackage/ resides. If you list the contents of your current directory (e.g., with a Linux ls or Windows dir command) and don’t see MyPackage, then you are probably in the wrong place.

For example, if the absolute path to your source code were /home/yourName/projects/project1/MyPackage/SubPackage/MyClass.java, then you would want to

cd /home/yourName/projects/project1

before trying to compile your code.

8.2.2 Compiling from Eclipse

Part of the project settings for any Java project is a list of one or more “Source” directories. The Source directories are the places where Eclipse believes that you are keeping your packages of source code. These need to follow the same rule about packages and directories.

For example, if the absolute path to your source code were /home/yourName/projects/project1/MyPackage/SubPackage/MyClass.java, then you should have /home/yourName/projects/project1 as one of (possibly the only one of) your Source directories.

To view and change your project’s source directories, go to the Eclipse Project menu and select Properties -> Build Path, or right-click on any file or directory of the project in the Package Explorer and select Build Path -> Configure Build Path... Look at the Source tab to see your Source directories and make changes as necessary.

8.3 How do I import a new library into my code?

8.3.1 This has nothing to do with import statements!

If, by that question, you meant “What import statements do I write at the beginning of my Java code?”, you are thinking about it incorrectly.

Java import statements are not like C++ #include statements. They don’t load new libraries into your code. Java doesn’t have an equivalent to the C++ #include statement. It doesn’t need one, because Java has its rules that say each public class must be in a Java file of the same name, and each Java package must be in a directory of the same name. C++ #include statements tell the compiler where to find other code. Java’s rules about files and directory names means that the compiler already knows where to find other code, just as soon as you give the full name of class that you want.

Java import statements are like C++ using statements. They allow you to refer to things by abbreviated names.

Neither Java import statements nor C++ using statements are ever really necessary. You can always refer to things by their fully-qualified names, giving all the packages (Java) or namespaces (C++) that uniquely identify the symbol:

C++

#include <iostream>
   ⋮
std::cout << "Hello" << std::endl;

Java

java.io.File input = new java.io.File("input.dat");

Or, you could authorize shortcuts for the specific symbols that you are using:

C++

#include <iostream>
   ⋮
   using std::cout;
   using std::endl;
   ⋮
cout << "Hello" << endl;

Java

import java.io.File;
   ⋮
File input = new File("input.dat");

Or you can authorize shortcuts for all of the names in a namespace/package:

C++

#include <iostream>
   ⋮
using namespace std;
   ⋮
cout << "Hello" << endl;

Java

import java.io.*;
   ⋮
File input = new File("input.dat");

import and using statements really aren’t necessary. They are just awfully convenient.

8.3.2 OK, so how do I include a new library in Java?

That’s handled by the compiler settings (specifically the CLASSPATH ), which is usually set by your IDE.

8.4 How do I get my program to read from a file instead of from the keyboard?

At the command line, this is called input redirection and is done by appending

< location_of_input_file 

to the end of the command launching the program. You can read more about this in CS252, and it works the exact same way in a Windows command-line session.

What if you are launching your program from an IDE?

8.4.1 Eclipse

After you have successfully compiled your code, right-click on the Java class that contains your main function. Then, from the Run menu, select Run configurations...

You’ll see a list of different project types, one of which should be “Java Application”.

On the “Common” tab, under “Standard input and output”, click to select the “Input” box, then use one of the three buttons on the line below to select the file of input data you want supplied as the standard input.

Click Run to save these arguments and launch your program.

8.5 Error Message: Unsupported class file major version …

If you are doing local development and getting error messages about “Unsupported class file major version …” or other messages that appear to complain about Java versions, check your versions:

java --version
javac --version

You should get the same version number for both commands, and it should be 17.x or 21.x

9 Java IDE Issues

9.1 I created a Java project with the wrong settings. How do I re-do it?

A lot depends on just how much is wrong. Minor problems can be fixed by right-clicking on the project name, selecting “Build path”, then “Configure Build Path” and adjusting your settings from there.

For major issues, it is often easier to to ask Eclipse to re-examine your project and deduce your settings, though you may still need to make minor tweaks to the build path afterwards.

To do this:

  1. In Eclipse, delete your project. Do not check the box to delete the project contents. You just want Eclipse to stop tracking the project.

  2. In your operating system, go to the project directory and locate and delete the .project and .classpath files. These are where Eclipse stored your old project settings.

    Take note that these file names start with ‘.’, which means that in Linux and MacOS these files are “hidden” by default. You can spot them by adding the “-a” to your “ls” commands.

  3. Back in Eclipse, create or import your project again.

9.2 How do I install a Java compiler & IDE on my PC?

Refer to Installing a C++/Java IDE on Your Own PC. Simply skip over the parts about installing C++ if you want a Java-only solution.

9.3 How do I set compiler flags and options?

From the command line. of course, you just type the option into the command.

9.3.1 Eclipse: changing the settings for one project

If you are using Eclipse, use the Project menu, select Properties. Go to Java Compiler. You can make changes here or in any of the sub-pages you reach by expanding the Java Compiler tree.

You will probably need to check the box “Enable project specific settings” on any page where you actually want to change the settings.

9.3.2 Eclipse: changing the default settings for all Java projects

From the Window menu, select Preferences, then Java, then Compiler. From here , and on the sub-pages you reach by expanding the Compiler tree, you can change settigns that will become the default for all Java projects in this Eclipse workspace.

9.4 How do I supply command line parameters when executing my programs?

Often you will be writing programs that take “command line parameters” as part of their inputs.

Of course, if you are executing a program from the command line, you just type the parameter values on the command line (hence the name!), e.g.,

Java MyPackage.MyProgram ../testData/myTestData.txt 23

But what if you are launching your program from an IDE?

9.4.1 Eclipse

  1. After you have successfully compiled your code, right-click on the Java class that contains your main function. Then, from the Run menu, select Run configurations...

    You’ll see a list of different project types, one of which should be “Java Application”.

    • Underneath that, you might already have a configuration for this program (Clicking on a configuration will show you what project and what Java class it is associated with.

    • If not, select “Java Application”, then at the top of the columm click on "_New launch configuration`".

  2. On the “Arguments” tab, enter your command line parameters into the “Program Arguments” box.

  3. Click Run to save these arguments and launch your program.

Video of this procedure

9.4.2 VSCode

Running the Debugger

Running in the debugger, with or without command line parameters, requires some preparation.

  1. Be sure that you have set up the debugger in your project directory by following these directions.

  2. You will now have a file .vscode/launch.json that will allow you to launch your program in a debugger by pressing F5 or using the menu entry.

    Open that file in the editor and look for the line

        "args": [],  
    

    (If you don’t have one, create it, just underneath the mainClass entry.)

    Inside the brackets, you can add your desired command line parameters as a comma-separated list of quoted strings. For example,

        "args": ["hello", "42"],
    

    Save your changes.

9.5 I think my IDE project settings are incorrect. How do I reset them?

This is very common if you change the arrangement of your code or switch or reconfigure build managers after having created a project in your IDE.

9.5.1 Eclipse

In some cases, you can fix the problems by right-clicking on the project name and selecting “Properties”.

But it can be easier to force Eclipse to re-evaluate your project settings and let it see what you have done. To do this:

  1. Right-click on the project name in Eclipse and delete the project. (Do not tell Eclipse to delete the source code - just delete the project, removing it from Eclipse.)

  2. In your machine’s operating system, search the project for files named .project and .classpath and remove them. Remember that in Linux and in MacOs, all files with names starting with “.” are hidden. You will need to use “ls -a” to see them.

  3. Back in Eclipse, import the Java project at that same directory. Eclipse will scan your directory structure and deduce most of the important project settings.

9.5.2 VSCode

  1. In many cases, closing the folder and re-opening it will cause VSCode to re-evaluate your project settings.

  2. In the left (Explorer) column, look for the “JavaProjects” section and expand it.

    Click the ... menu, and select “Clean the Workspace”.

10 Git and SSH key issues

10.1 ssh complains about an “UNPROTECTED PRIVATE KEY FILE!”

Your private key file should be readable (and writable) by you alone.

10.2 Git prompts me for a password when I try to clone, push, or pull.

These three actions (clone, push, & pull) are the ones that communicate directly with GitHub. Other actions (e.g., add, commit) work on your local copy of the repository only.

You need to provide an SSH key to log into GitHub for those three actions. If you are prompted for a password, it’s a sign that your SSH key was not seen or was rejected.

Refer to the next question for troubleshooting tips.

10.3 Git tells me “Permission denied (publickey).”

If you also get the line

Either

  1. You are trying to clone a private repository belonging to someone else, or
  2. GitHub is not able to log in with your SSH key.

10.3.1 Troubleshooting

The most likely reasons for this are

  1. You have not properly registered the public half of your key with GitHub, or the key that you updated was garbled or incomplete.
  2. You aren’t running an SSH agent on your own PC.
  3. You have not added the private half of your key to the agent.
  4. If developing remotely, you did not use the “ssh -A” option to connect to the remote Linux machine, or you are in X2Go, which does not support that option.

To see which of these might be relevant:

  1. Try to access the GitHub page for the repository that you are trying to clone. If you get a 404 error, the repository is private and your account is not among those who have been granted access.

  2. On your local PC, give the command

    ssh-add -l
    
    • If it complains that it can’t contact a server, then your problem is #2 above. Refer to Starting an Agent….

    • If it does not complain, but does not list your GitHub SSH key (or any key at all), then your problem is #3 above. refer to Adding Keys to the Agent.

    • If it lists your keys, then move on to the next step.

  3. If you are doing remote development, in your SSH session to the remote Linux machine, give the same command

    ssh-add -l
    

    (If you are doing remote development with VSCode, do this inside the VSCode terminal.)

    • If it complains that it can’t contact a server or fails to list your key, then the problem is #4 above. Refer to Cloning an Existing Project.

    If that command on the remote machine does list your key, then your problem is likely #1 above. Refer to Logging in to GitHub.

  4. Look at the output of that last ssh-add -l command. Each key is described using an SHA-256 code, e.g.

    521 SHA256:PnWdYEB3QxlZxwJzaVozOj+femwq42JDvrkt6PlH+YE MyKey (ECDSA)
    

    Now go to GitHub, click on the icon or picture in the upper right corner, select Settings, and then select SSH and GPG keys. In the list of keys, look for a key with the same SHA256 code.

    • If you don’t see any keys at all, or if you don’t see an SHA256 code matching the ones from your ssh-add -l command, then you either have not uploaded the public half of your key to GitHub, or the uploaded key was garbled somehow.
    • Delete the old key(s) from GitHub if necessary.
    • Then try re-uploading the public half of your key.

      If you are on Windows, try to avoid including the end-of-line terminator characters when you copy-and-paste the key into the text box on GitHub.

10.3.2 More Unusual Problems

10.3.3 A Final Workaround

If none of this resolves the problem, it is possible to work with ssh keys stored on the remote machine.

10.4 I cannot use a key agent on my local PC with a remote git

If you are absolutely unable to get a key agent working on your local PC that transfers to a remote machine, or if you find yourself sometimes working from a library or work machine on which the necessary SSH key support is missing, you can run git on a remote machine using a private key stored there.

This has two disadvantages:

  1. It is somewhat less secure, because you need to keep a private key on a machine that you do not control physical access to.
  2. You will need to type your SSH key passphrase each time you do a git clone, git push, or git pull operation.

So consider this a means of last resort.

  1. Transfer the private half of your GitHub SSH key to the remote Linux machine, storing it in your ~/.ssh/ directory.
  2. Make sure that only you can read that key file:
    chmod 600 ~/.ssh/name-of-your-key-file
    

    (replacing the highlighted portion with your own file name).

  3. Look in your home directory with

    ls -a ~
    

    You should have a file named .bashrc or .zshrc. This file contains commands that are run when you log in to your account.

  4. Edit that file, adding the following line at the end:

    alias github="GIT_SSH_COMMAND='ssh -i /home/yourLoginName/.ssh/name-of-your-key-file -o IdentitiesOnly=yes'"
    

    (again, replacing the highlighted portions with your own names). Pay close attention to the single and double quotes in that command.

  5. Log out of the remote Linux machine and then log back in again.

    You should now be able to issue git commands to clone, push, or pull by preceding the command with “github”, e.g.,

    github git push
    

    Most git commands other than clone, push and pull do not access the remote repository on GitHub and therefore do not need the “github” prefix.

10.5 What kinds of things should I commit with git?

We only track source files in git – things that we as programmers supply and edit.

We do not track generated files, the things that we produce by running compilers or other non-interactive programs on the source files.

The vast majority of source files are text files, which git handles very well. On occasion, we may have source files that are binary (e.g., a graphic or picture that will be part of a website or a background image in our user interface).

Most generated files are binary, e.g., .o .class, .zip or .jar files. git really does not handle those as well as text file, though it does well enough with small numbers of binary files.

The main rule, however, is that if you edit it with an interactive program (e.g., a text or code editor or, for graphics, a drawing tool), then you should track it with git.

If you generate a file with a non-interactive command (e.g., a compiler or most shell commands), then do not track it with git.


git, however, won’t know which of your files are source files and which are generated. It will suggest (when you run git status) that you stage and commit everything.

You can tell git to stop nagging you about certain files and reduce the risks that you will make a mistake by supplying a .gitignore file. This is a text file that contains a list of files that you don’t want git to look at. An example would be

bin/
**/build/
**/*.class
**/*.jar
**/*.o
**/*.jar

The first line indicates that anything in the bin/ directory (relative to the directory containing this .gitignore file) should not be suggested for staging.

The second line uses **/ which matches any number of directories and indicates that anything in any build/ directory should be ignored. The remaining lines use the same pattern to suggest that common binary files should be ignored no matter what directory they are found in.

These rules apply to the directory in which the .gitignore file resides, and to any subdirectories of that directory.

10.6 I committed a binary or generated file by mistake. How do I convince git to stop tracking it?

We all make this mistake from time to time. We should only use git to track source files, not the generated files that are produced by compiling or processing those sources. But, particularly when using IDEs, we are often prompted by default to commit generated files.

Adding a new entry to the .gitignore file won’t help, because .gitignore only applies to files that are not already being tracked in git.

To remove a file from a directory and tell git that you don’t want it to track changes to that file, use the command

git rm path-to-file --cache

or, for an entire directory:

git rm -r path-to-directory --cache

Then add that path to your .gitignore file so that you aren’t prompted to commit that file again.

11 Gradle issues

11.1 I get a “Command ‘gradle’ not found” error

Look to see if you have been provided with (or should have provided) a gradle wrapper, which consists of the files

The wrapper allows you to run gradle on a machine where it has not been installed, so long as that machine has a working Java VM (the java command).

Replace the “gradle …” command that you were trying to run by “./gradlew …”.

11.2 I get an error “./gradlew: Permission denied”

You do not have execute permission on the gradlew script. Correct that with

chmod +x ./gradlew

11.3 I get an error “Timeout waiting to lock…”

Another gradle process has locked a file that you need.

Things to try:

  1. Make sure that you aren’t running gradle in two different windows, either on the same machine or on another that shares the same file system (e.g., two of our Linux servers).

  2. Kill any gradle daemons. On each machine where you have been running gradle over the last 3 hours or so, give the command

    ./gradlew --stop
    
  3. If neither of the above resolves the problem, there is a good chance that a gradle process crashed while holding one or more locks. Try to force release of the locks. Look for such locks:

    find ~/.gradle/caches -name "*.lock"
    

    If you find any,

    find ~/.gradle/caches -name "*.lock" -print -exec rm -f {} \;
    

11.4 I get an error “currently in use by another gradle instance”

See this answer.

11.5 My imported libraries are not being recognized.

First, we need to determine whether this is a problem with your gradle setup or your IDE.

  1. Run gradle from the command line. Does the problem still occur?

    If so, the problem is likely in your build.gradle. Make sure that your dependencies are correct and complete.

    Rerun gradle, forcing a reload of all dependencies. E.g.,

    ./gradlew --refresh-dependencies build
    

    Pay close attention to the messages about attempts and failures to find your chosen libraries.

  2. If the problem goes away when running gradle from the command line, the issue is in your IDE setup. It’s not unusual for IDE settings to get out of sync after you edit your settings.gradle and build.gradle files.

    • In Eclipse, right-click on your build.gradle file and select “Gradle”, then “Refresh Gradle Project”. You should see an indicator in the lower-right corner of the window that Eclipse is working through the reload of your gradle settings.

    If this does not take care of the problem, you may need to re-import your project.

    • In VSCode, closing your project folder and then re-opening it will cause a re-evaluation of your gradle settings.

12 Mathematics and Notation

12.1 \( \forall \) ? \( \exists \) ?

Some of the notation used in logical expressions:

\( \forall \)
“for all”
\( \exists \)
“there exists”
\( \ni | \)
“such that”
\( \Rightarrow \)
“implies” (Alternatively, you can read \(A \Rightarrow B \) as “if A, then B”)

So, for example, the formula

\[ \exists c_1, n_0 \; | \; n > n_0 \Rightarrow t(n) \leq c_1 * \left(c \, f(n)\right) \]

reads as “there exists some values for \( c_{1} \) and \( n_{0} \) such that, whenever \(n > n_0\), then \(t_n\) is less than or equal to \(c_1*c*f(n)\).”

12.2 Basic Probability (probably just what you wanted)

A probability is a number between $0$ and $1$ that expresses the chances of something happening. For example, in rolling an ordinary 6-sided die, the probability of getting a ‘5’ is $1/6$. The probability of getting an even number is $3/6$ or $0.5$. The probability of getting a ‘9’ is $0.0$ — it can’t possibly happen with a single roll of an ordinary die. The probability of getting some number between 1 and 6 is 1.0.1

Some key ideas about probabilities:

12.3 Yucch! Nobody told me I needed to know about logarithms.

Suppose that $a^b = c$ . Then we say that b is the logarithm to the base $a$ of $c$, written as $\log_a c$ . In other words, $\log_a c$ is the power that $a$ must be raised to, in order to produce $c$.

Most uses of logarithms outside of Computer Science focus on $log_{10}$ , often abbreviated as $\log$ , and on $log_e$ (where $e$ is the irrational number $2.71828\ldots$), often abbreviated as $\ln$ .

In Computer Science, however, most uses of logarithms arise from considering a situation where we start with $N$ objects, divide that set of objects in half, divide that half in half, divide that fourth in half, and so on:

\[ N, N/2, N/4, \ldots , 2, 1\]

The question is: how many divisions in half can we perform until we get down to a single object? The answer to this question comes from considering the sequence of numbers in reverse:

\[ 1, 2, 4, \ldots , N/2, N\]

and realizing that at each step, we are moving to a progressively higher power of 2: $2^0, 2^1, 2^2, \ldots , N/2, N$ . How many such doublings can we do before reaching $N$ ? This question is the same as asking “to what power can we raise 2 until we reach $N$?”. And the answer, by definition, is $\log_2 N$.

Logarithms to the base 2 are so common in Computer Science that we use the abbreviation $\log$ to stand for $\log_{2}$ , unlike the rest of the scientific world where that stands for $log_{10}$ .

But when we are doing a big-O analysis, the base of the logarithm does not matter, because of the conversion formula between logarithms of different bases:

\[\log_a x = \frac{\log_b x}{\log_b a}\]

So if we have, for example, $\log_{10} N$ , we can convert this to a base $2$ logarithm

\[ \log_2 N = \frac{\log_{10} N}{\log_{10} 2}\]

But $log_{10} 2$ is a constant, and we can drop constant multipliers within $O( … )$ . So $O(\log_{10} N) = O(\log_{2} N)$ . We can generalize this argument to cover any two bases, and so we just write $O(log N)$ without even worrying about the base.

Some useful formulae:

\[ \log_a x = \frac{\log_b x}{\log_b a}\]

\[\log (x*y) = \log x + \log y\]

\[\log (x^y) = y \log x\]

12.4 Simplifying Summations

Some useful formulae:

\[ \sum_{i=0}^{n} 2^i = 2^{n+1} - 1 \]

\[ \sum_{i=0}^{n} a^i = \frac{a^{n+1} - 1}{a-1} \]

\[ \sum_{i=0}^{n} i = \frac{n(n+1)}{2} \]

\[ \sum_{i=0}^{n} i^2 = \frac{n(n+1)(2n+1)}{6} \]

\[ \sum_{i=0}^{n} (1/i) = O(\log n) \]

\[ \sum_{i=0}^{\infty} \frac{1}{2^i} = 2 \]

\[ \sum_{i=0}^{\infty} \frac{i}{2^i} = 3 \]


1: Well, I suppose the die could come to rest on an edge, or a black hole could suddenly open up and swallow the die, so make that probability $0.9999\ldots$.

2: OK, that’s a bit of an over-simplification. Technically, the events that we’re talking about have to be “independent” of one another. That’s why we add up the probability of the die coming up $1, 2, … , 6$ but do not also add in the probability of the die coming up with an even number. The “coming up even” event is not independent of the event “coming up ‘2’”: when a die comes up ‘2’ it is also coming up even.)

13 Miscellaneous

Left-clicking on the link will often show you the file in the browser, but not provide an easy way to download the file itself.

Instead, right-click on the link and in the pop-up menu, look for something along the lines of “Save link as” (exact phrase depends on what browser you are using). Selecting that should allow you to download the file.

13.2 I can’t save makefiles (or other files with no extension or unusual extensions) without adding an extension.

This is a Windows-specific problem. Windows used to be stupid about file extensions (the ‘.’ followed by 1-3 letters at the end of a file name), requiring all non-folder files to have one. Although Windows itself has gotten better about this, a lot of Windows software (including popular browsers) remains stupid.

The workaround is simple:

  1. Go ahead and add a .txt or other extension to the file name when you save it.
  2. Then immediately rename the saved file back to its intended name.