CS 240 Summer 2024

Lab 2: Pointers, passing by value vs. reference, 1-D arrays, and run-time errors (240 pts)

Due: 06/26/2024 (Wed), 11:59 PM

Objective

The objective of this lab is to practice using pointers as they are commonly used in passing by reference and manipulation of 1-D arrays.


Reading

Read chapters 2 and 3 from K&R (textbook).


Lab 2 Code Base

The C code base for lab2 is available as a tarball at

/homes/park/pub/cs240/lab2.tar

on the Linux machines in one of our labs. If you are not able to access the tarball it implies that you are not logged onto a lab machine. Copy the tarball to your working directory of choice and unpack it using

% tar xvf lab2.tar

Under lab2, you will find subdirectories that contain versions of the example code discussed in class. As noted in class, always compile and run the final version on a Linux PC in our labs.


Problems [240 pts]

Problem 1 (20 pts)

Compile the program in v1/ to generate the executable file main.exe (the .exe suffix is used for executable files in Windows). Run main.exe three times. Specify what output you observe and explain why the output is the way it is. Write the bits correponding to the hexadecimal output of the address of variable of s with the least significant bit at the rightmost end (e.g., decimal value 3 for the first 8 bits is 00000011). How many bits were output in total by the hexadecimal encoding of the address of s? How does that match up with our lab machines having 64-bit CPUs which have address buses (i.e., communication line) of width 64 bits? What is the integer value of the address? How did you determine it?

Problem 2 (20 pts)

Explain why the four printf() calls in v2/main.c output the observed values to stdout. Modify main.c by declaring a local variable of main, int **z, and use z to output the value of x. Explain how your code achieves this goal. Can you output the value of x using a local variable of type, int ***h? Explain your reasoning.

Problem 3 (15 pts)

Compile v3/main.c and the name the executable main.bin (.bin is a common suffix for executable files in Linux). Run main.bin. Explain what you observe. Create a copy of main.c, v3/main1.c. Don't comment out the abc() in main1.c so that two calls to abc() are made. Compile main1.c and execute. Explain the output you observe. Create a copy of main.c, v3/main2.c. Modify main2.c by making the local variables of xyz(), int a, b, global. Compile main2.c and execute. Compare the output to that of main1.c and explain what you find.

Problem 4 (15 pts)

Compile and execute the C code main.c in v4/. Explain the output of the two calls to function printf() in main(). Modify main.c to introduce a global variable r of type int. Code a function, void changeling3(void), called by main() that assigns r the value 9. After calling changeling3() from main(), print the value of r to stdout. What do you observe? What are the pros/cons of modifying the value of a variable by calling a function where an argument is passed by reference as in changeling2() vs. by not passing an argument and, instead, using a global variable as in changeling3()?

Problem 5 (15 pts)

Make a copy of the modified main.c in v4/ and call it v4/main4.c. Remove the code of functions changeling1(), changeling2(), changeling3() from main4.c into separate files, changeling1.c, changeling2.c, changeling3.c under v4/, respectively. Specify in lab2.pdf how you compile and execute the code that is stored in four separate files main4.c, changeling1.c, changeling2.c, changeling3.c. Compile and test that the modified code works correctly.

Problem 6 (15 pts)

A continuation of Problem 5, utilize the method of creating separate .o object files for each of the four .c files. Describe in lab2.pdf the steps you followed to generate the object files, statically link the functions contained in the object files to generate executable file main44.bin. Test and verify that main44.bin executes correctly. Then modify changeling2.c only so that 4000, instead of 2000, is assigned *y. Recompile just changeling2.c into object file changeling2.o. Since the other files have not changed, there is no need to recompile their code. Reusing their object files when (statically) linking the object files to create an executable file will do. Test and verify that this method works correctly.

Problem 7 (15 pts)

In main() of v5/main.c the address of local variable s is passed to changevalue(). The function changevalue() prints the address of its argument x, &x, to stdout. Explain why this address is different from the address of local variable s. Why is the value of argument x equal to the address of s?

Problem 8 (20 pts)

The code in v6/ used conditional printf() calls with the help of CPP to locate where in main.c a statement causes segmentation fault. Explain what the binary search method discussed in class is for the example code main.c, and why it is efficient at locating run-time debugs. If a piece of code, main.c, has N statements, how many steps in the binary search is needed in the worst-case to pinpoint the location of a run-time bug? In the case where N is 4000 (main.c has 4000 statements) how many steps are sufficient? What happens if you modify v6/main.c so that the newline character '\n' is removed at the end of all debug printf() calls? Explain the reason for this behavior.

Problem 9 (20 pts)

Based on the discussion of how we view 1-D arrays as being represented in main memory -- not the description provided in the textbook which is an optimization which we will ignore for the moment -- describe the layout of 1-D integer array of v7/main.c, int z[3], in main memory. Based on the memory layout explain why *(z+2) is equivalent to z[2]. Modify main() so that it outputs to stdout z and &z. Based on the output explain why we can deduce that the layout of the 1-D we discussed is incorrect. What is the optimization step carried out by gcc for variables declared as 1-D arrays? Note: When we employ dynamic memory allocation later in the course to create 1-D arrays at run-time the layout we discussed -- not be declaration of 1-D array variables -- will be the correct description. The optimization performed by gcc is of minor relevance.

Problem 10 (15 pts)

Explain where and why a segmentation fault occurs in v8/main.c.

Problem 11 (25 pts)

Explain what the silent run-time error in the example code of v9/ is. In what sense is a silent run-time error worse than an error that causes an app process to crash (e.g., by triggering segmentation fault)? What happens if the bound of third for-loop is changed from 6 to 9? Explain the reason for the observed run-time behavior. What happens if we compile main.c with the option -fno-stack-protector and execute a.out? Provide an explanation for what you find. By default, in CS240, we will allow gcc to attempt to aid in coding by helping detect stack smashing, arguably the most notorious run-time bug that hackers have exploited over the past decades to compromise computing systems. In general, assistance provided by gcc only goes so far (e.g., see Problem 12) and the programmer must ensure that run-time vulnerabilities are removed from software.

Problem 12 (20 pts)

Create a copy of v9/main.c and name is main9.c. Modify main9.c so that the 1-D integer array, x[5], is made global, and the bound of the third for-loop is set to 9. Compile without the -fno-stack-protector option and execute the program. How is the behavior different from Problem 11? Explain your finding.

Problem 13 (25 pts)

For the 1-D array, char x[10], to contain string "hello" how must the 10 bytes of x[10] be assigned? How many bytes of char x[10] are used for storing the string? What is the longest string that can be stored in x? You may use the library function strlen() (include header file <string.h>) to determine the length of a string given as its argument. What length does strlen() output for "hello"? Compare the value returned to what the man page of strlen() states will be returned. Check if they are consistent. Use the man page of strlen() to determine the type of strlen()'s return value so that printf() is called with correct formatting instruction to print the value to stdout.


Bonus problem (20 pts)

What happens if the argument passed to strlen() is missing an end-of-string character? Is strlen() fundamentally buggy? Discuss your reasoning. How is the library function strnlen() different from strlen()? Does strnlen() help address the concern associated with strlen()? Explain your reasoning.

The Bonus Problem is entirely optional. Bonus points count toward reaching 35% of the course grade contributed by lab assignments.


Turn-in instructions

Electronic turn-in instructions:

i) For problems that require answering/explaining questions, submit a write-up as a pdf file called lab2.pdf. Place lab2.pdf in your directory lab2/. You can use your favorite editor subject to that it is able to export pdf files which many freeware editors do. Files submitted in any other format will not be graded. The TAs need to spend their time evaluating the content of your submission, not switching between editors or hunting down obscure document formats which wastes time and is in no one's interest.

ii) We will use turnin to manage lab assignment submissions. In the parent directory of lab2, run the command

turnin -c cs240 -p lab2 lab2

You can verify/list your submission by running: turnin -c cs240 -p lab2 -v. Please double-check that you submitted what you intended to submit.


Back to the CS 240 web page