Worksheet Java and C

This worksheet covers a few elements of Java and C that will be used in this course, along with some background information on the console / terminal environment for different operating systems. With the exception of Command Prompt / terminal information, you should have seen this material in the introductory classes (or from the classes that were used to waive the introductory classes).

Questions and Completion

To receive credit for completing the worksheet, you must complete the corresponding quiz (it is just a checkbox) on D2L when you have finished the worksheet.

If you have questions as you go through this worksheet, please feel free to post them on the discussion forum.

Prerequisite: Basics

Text Editor

If you do not already have one, get a text editor for your computer and try it out. If you are comfortable with using an Integrated Development Environment (IDE) such as Eclipse or IntelliJ IDEA, that will do, but you may want to look at a standalone text editor also, since they tend to be much more lightweight.

No matter what, do not use a word processor such as Microsoft Word to edit code. Yes, this does happen sometimes.

Suggested text editors to try:

Old school text editors with a longer learning curve:

If you have another good text editor, feel free to share on the forum.

Console / Terminal

Open a console / terminal on your computer.

Verify that you can change directories (with cd), create directories (with mkdir), list directories (with ls or dir), etc.

Terminology: Windows uses the term “console”.
Linux, OS X, and others more typically use “terminal”; moreover, a shell program such as bash reads commands from the terminal, so we might say “open a shell” or “get a shell window” rather than “open a terminal”.

Press TAB to Autocomplete

In the Command Prompt and terminal, you can often press TAB to autocomplete.

There are different behaviors when autocompletion is used with multiple entries, e.g., multiple files/directories with the same prefix

Using TAB liberally will make your command-line interactions significantly faster.

Environmental Variables

Environmental variables (“env var” for short) are supported on Windows, Linux, and OS X.

Each process has a collection of environmental variables that you can think of as a map from variable name (a string) to a variable value (also a string).

Examine the environmental variables on your system by running one of the following commands.

Setting an Environmental Variable

Show that the environmental variable FOO is initially not set, then set it to have value bar, show that it is set, update its value to baz, then unset it.

Now (for all operating systems) repeat this, but do not unset FOO at the end. Close the Command Prompt / terminal and then open a new one. Is FOO set in the new terminal?

Home Directory

On Linux and OS X, your home directory probably has the form /home/bob or /Users/bob; this is stored in the HOME environmental variable. The home directory has some special support:

Spaces in Environmental Variables

Spaces in environmental variable values can cause problems if they are not surrounded by quotes properly. A single value hello world with a space in it can end up being treated as two distinct values hello and world.

This often arises with paths that contain spaces. For this reason, try to avoid spaces in path names.

Try these illustrative examples:

PATH environmental variable

Some environmental variables contain a single path, e.g., C:\Users\bob or /home/bob.

Other environmental variables contain a sequence of paths, e.g., C:\Users\alice;C:\Users\bob;C:\Users\charlie or /home/alice:/home/bob:/home/charlie. The character between paths is called the path delimiter. The path delimiter character for Windows is the semicolon ;. The path delimiter character for Linux and OS X is the colon :.

The PATH environmental variable contains a sequence of paths. This sequence is used to determine which executable is invoked when you enter a command. When you enter a command, the Command Prompt / shell looks for an executable with that name in the directory specified by the first path in PATH. If no such executable is found, it continues to the second path in PATH, etc. If no executable is found, and all of the paths in PATH have been tried, the Command Prompt / shell reports that the command cannot be found.

Aside: there are also builtin commands that do not rely on searching for an executable in PATH.

Check the contents of your PATH environmental variable.

When installing new development software, it may be necessary to add an entry to your PATH environmental variable. You can add a new entry before the other paths using:

If there are executables in the software directory with the same name as others in PATH, the ones in software will take precedence.

IMPORTANT: making changes to PATH in the Command Prompt / terminal will not persist, i.e., they do not affect other Command Prompt / terminal windows that you open in the future. This is useful because any mistakes are forgotten when you close the window.

There are a number of ways to make the changes persistent, but we will instead describe how to record the changes in a file, and then apply them quickly.

Java SDK

Check that you have the Java Standard Edition (SE) Development Kit (SDK) by opening a console / terminal and running the following command. You should see something beginning with “21.0”. The minor version is not important for this class, although it is advisable to use a recent version for security reasons.

$ javac -version
javac 21.0.1
$ javac -version
javac 21.0.1

You can download java from Amazon.

Java 21 is best for the purpose of this course. If you have multiple versions of Java installed, you can switch between them using the Java console. On MacOS, this is found in the System Preferences.

In bash on MacOS and linux, you can change the version seen in the current shell by executing

$ export JAVA_HOME=`/usr/libexec/java_home -v 1.8` # java 8
$ export JAVA_HOME=`/usr/libexec/java_home -v 21` # java 21

Hello World

Write a hello world program in Java. Your program should print “Hello world!” to the console / terminal, and then exit.

Solution: Hello World in Java

Prerequisite: C

C or C++ Compiler

You can run code online using repl.it. You can see the assembly code produced by a compiler using godbolt.org.

Mac and linux will come with gcc or clang preinstalled.

On windows, you could try any of the following:

Hello World

Write a hello world program in C. Your program should print “Hello world!” to the console / terminal, and then exit.

Compile your program with a C compiler, then run it from the console / terminal.

Solution: Hello World in C

Pointers

Consider the following C program.
Replace the comments with code, so that the value of x is 10 when it is printed.

#include <stdio.h>
#include <stdlib.h>

void update (int* p) {
  /* TODO */
}

int main () {
  int x = 5;
  update (/* TODO */);
  printf ("%d\n", x);
}

Solution: Pointers

Allocation Location

Consider the following C program.

#include <stdio.h>
#include <stdlib.h>

int x = 5;

int main () {
  int y = 10;
  int* p = (int*) malloc (sizeof (int));
}

Answer the following questions:

  1. Where in memory is x allocated?

  2. Where in memory is y allocated?

  3. Where in memory is p allocated?

  4. Where in memory is p pointing to?

Solution: Allocation Location

Call-Stack Allocation

Consider the following C program.

#include <stdio.h>
#include <stdlib.h>

void countdown (int n) {
  if (n <= 0) {
    printf ("done\n");
  } else {
    printf ("counting down\n");
    countdown (n - 1);
  }
}

int main () {
  countdown (5);
}

When it is executed:

  1. What will be printed?

  2. What is the maximum number of activation records (also known as stack frames) on the call stack at one point during execution?

Solution: Call-Stack Allocation

Dangling Pointer

Consider the following two C programs. Which one of these programs is problematic and why?

#include <stdio.h>
#include <stdlib.h>

int foo (int n) {
  int result = 2 * n;
  return result;
}

int main () {
  int x = foo (5);
  int y = foo (7);
  printf ("%d\n", x);
  printf ("%d\n", y);
}
#include <stdio.h>
#include <stdlib.h>

int* foo (int n) {
  int result = 2 * n;
  return &result;
}

int main () {
  int* p = foo (5);
  int* q = foo (7);
  printf ("%p %d\n", p, *p);
  printf ("%p %d\n", q, *q);  
}

Solution: Dangling Pointer

Solutions

Solution: Hello World in Java

public class Hello {
  public static void main (String[] args) {
    System.out.println ("Hello world");
  }
}
$ javac Hello.java
$ java Hello
Hello world

Solution: Hello World in C

#include <stdio.h>
#include <stdlib.h>

int main () {
  printf ("Hello world!\n");
  return 0;
}
$ gcc -o hello hello.c
$ ./hello 
Hello world!

Solution: Pointers

#include <stdio.h>
#include <stdlib.h>

void update (int* p) {
  *p = 10;
}

int main () {
  int x = 5;
  update (&x);
  printf ("%d\n", x);
}
$ gcc -o pointers-01-solution pointers-01-solution.c
$ ./pointers-01-solution 
10

Solution: Allocation Location

  1. Global memory.

  2. In an /activation record/ for main (also known as /stack frame/) stored on the /call stack/.

  3. In an /activation record/ for main (also known as /stack frame/) stored on the /call stack/.

  4. On the heap.

Solution: Call-Stack Allocation

  1. This is printed.

    counting down
    counting down
    counting down
    counting down
    counting down
    done
  2. There are at least 8 activation records on the call stack when done is printed by printf. There may be more since we do not know the implementation of printf.

    • main
    • count with n = 5
    • count with n = 4
    • count with n = 3
    • count with n = 2
    • count with n = 1
    • count with n = 0
    • printf

Solution: Dangling Pointer

The first program is fine.

The second program is problematic because p is a /dangling pointer/ after foo returns. That is, p contains a pointer to an area of memory that is not defined, and when it is dereferenced (using *p) the behavior is not guaranteed: it might be 10, some other value, or crash the program. This happens because the result variable is allocated in the activation record for foo, and the address of result is returned from foo, but the activation record for foo is deallocated (hence the memory storing result is also deallocated) when foo returns.