Thoughts on Project 9

Here are a few points relevant to the grading of Project 9.

Showstoppers

The flag variable

Often a variable is set within a loop to indicate that an operation should be performed once the loop has completed.

int doSomethingExciting = 0 ;
while (need to keep going ) {
  perform complicated operation
  if the mood is right: doSomethingExciting = 1
}
if (doSomethingExciting) {
  perform magic
}

The flag variable is used to make sure the magic happens only once and after the hard work is over.

Recursive functions are not an easy substitute for a flag variable.

Functions need header comments

Clearly document what your function does. Clearly state its preconditions, the constraints placed on the variables passed to a function.

/* This function finds an element within an array
 *   values:  The array to be searched
 *   size:    The number of elements in values
 *   element: The element searched for
 * Conditions:
 *   values must be sorted
 */

Non-trivial loops need similar header comments.

Complicated expressions

Sometime conditional expressions are just complicated.

  if ((distance < 70 || speed > 10) && cost <= budget+10) {

Replacing this condition with nested if statements only replaces parentheses with braces.

  if (distance < 70 || speed > 10) {
    if (cost <= budget+10) {

In this case, it also leaves the reader wondering what is so special about the case when cost is greater than budget+10.

Break the expression up to reflect its structure.

  if ((distance < 70
       || speed > 10)          /* OK this goes too far... */
      && cost <= budget+10) {

Embrace anonymity

If you are giving a variable a silly name because you only use it once, think about eliminating the variable.

  int ferd = (hi+lo)/2 ;
  strncpy(address, street, ferd) ;

When the for loop doesn't need an initialization

Sometimes you will write a for loop that doesn't need an initialization. In these cases, you should omit that which isn't needed.

  for (j=0; isspace(line[j]); ++j) {
    spacecount++ ;
  }
  for ( ; ispunct(line[j]); ++j) {
    punctcount++ ;
  }

Strings end with null characters

Strings are terminated with null characters. Loops searching strings should stop when null characters are reached.

  for (j=0; line[j] != '\0; ++j) {
    if (isspace(line[j]) {
      spacecount++ ;
    }
  }

Also, when you fill a string in a loop, be sure to tack a null character onto the end.

  for (i=0; i<26; ++i) {
    bigLetter[i] = i + 'A' ;
  }
  bigLetter[26] = '\0' ;

String copy is restricted to non-overlapping strings

The following code is not legal C and may fail when heavily optimized compilers or libraries are used.

  strcpy(&line[11], &line[13]) ;

Characters routines accept almost anything

The following code is perfectly legal in C.

  for (j=0; isspace(j); ++j) {
    spacecount++ ;
  }

Mixing declarations and initialization

Often it is best to avoid declaring and initializing a complex variable in one statement. The following two sections of code are not the same.

    char *startAsheville = strstr(line, "Asheville");
    char *startAsheville ;
    *startAsheville = strstr(line, "Asheville");

Pay attention to the warnings

That preceding section of C code will give a warning. You should compile your code with one of the options -std=c89 or -std=c99 and both of the options -pedantic and -Wall.

Rewrite your code to remove all warnings even if you think they are silly. (I do.)

Debugging

You ought to learn how to use the NetBeans debugger. It would be worth your time to read the Debugging C/C++ Projects Tutorial.

If you don't use the NetBeans debugger and are completely lost about what your program is doing, try adding some printf calls near the beginning of your loops.

  while ((nextMetro = substr(inBuff, "Waynesville")) != NULL) {
    printf("nextMetro = %s\n", nextMetro) ;