Advanced C Programming

Autumn 2016 :: ECE 264 :: Purdue University

This is for Fall 2016 (8 years ago)
Due 8/26

Editing C code with Vim

Goals

This assignment has the following goals.

  1. Learn to use the Vim text editor to efficiently move around a code file and make changes.
  2. Practice improving the style of poorly formatted code.
  3. Get to know how grades will be calculated in this course.

Setup

In this course, you will work on the ecegrid server. That's where you will get your starter files (if any), pre-test your submission (when possible), and submit your code. This gives everyone the same environment, with the same version of the tools (e.g., gcc, vim, etc.), and the same platform for testing code.

Before you proceed, please complete the setup.

Start learning Vim

This assignment is your chance to get good at editing code in Vim, before we get to the more challenging C programming assignments. Therefore, you should take this opportunity to learn it well.

This will take about 15-30 minutes, and will make the rest of this much easier. The Resources page has some web-based options, which look nicer but are less complete.

Bare minimum: Go through vimtutor

vimtutor is an interactive tutorial that is installed on ecegrid and every computer where Vim is installed. At the command line, just enter vimtutor and follow the instructions.

Recommended: Print out a reference sheet (or two or three)

Recommended: Watch a video (or two or three)

Get the homework files

To fetch the files for this assignment, enter 264get hw01 from bash. That should create a new directory called hw01. To see the directory enter ls . Next, enter cd hw01 to enter the directory and start working.

Do the homework

Here's the scenario: You have been given a partially-working calculator for ECE 264 grades. However, the code is very messy. First, you will fix the formatting. Next, you will complete the code. Finally, you will finish the code so that it prints out a course grade.

For this assignment, we will record the keys you type into vim. When the assignment is scored, we will play the keys back to verify if you reached the intended result. You will start with before.c and finish with goal.c. Do not modify goal.c or before.c. You may need those.

Do not use the arrow keys or mouse. You will not receive credit if you do. To avoid accidentally using them, enter the following command in vim (from normal mode): :DisableMouseAndArrowKeys and press enter.

We will give you hints in purple for some steps. For the others, you will need to use what you learned from vimtutor and/or the reference sheet. In this explanation, <esc> refers to the Escape key, <enter> refers to the Enter key, <tab> refers to the Tab key, and <space> refers to the spacebar.

Tips

You must do the entire process in one vim session. If you exit vim before the files match, you will need to start over. For that reason, you may end up doing the whole process several times. The repitition will serve as good practice. Once you are very comfortable with vim and understand what you are doing, it shouldn't take more than about 10 minutes to edit before.c into goal.c.

Pay close attention to the spacing in goal.c. For example, all of the // hw#, // quiz#, and // exam# comments start in column 11. The comma in those lines is in column 8. Vim shows the current line and column in the lower-right corner of your screen.

If you want to look at the files after you are done, be sure to not use the -W recorded.vim argument to vim. Otherwise, you will overwrite your recorded.vim and you will have to start over.

Get the homework files

From bash, enter cp before.c after.c to make a copy of the starter version of the file. Next, enter vim -W recorded.vim after.c to open it in vim.  The -W recorded.vim parameter is what makes it record your keystrokes.

  1. Fix the missing semicolon on line 3.
    1. Move to line 3. 3G
    2. Append a semicolon at the end. A;<esc>
  2. Indent the body (everything inside the curly braces) of the average function, which starts on line 14.
    1. Search for "average".    /average<enter>
    2. Go down one line (to get to the beginning of the body of this function). j
    3. Select the current line using visual mode. V
    4. Extend the selection to include the rest of the body of this function. jjjj
    5. Indent everything that is selected. >
  3. Indent the body of the for loop inside the average function.
    1. Move to line 18.
    2. Indent the current line. >>
  4. Indent the bodies of the weighted_sum, weighted_average, and main functions, as well as any for loops inside them.
  5. Add a blank line after the #include statement at the top.
    1. Jump to the beginning of the file. gg
    2. Start a blank line below the current line. o (lowercase letter)
    3. Exit insert mode (to get back to normal mode) <esc>
  6. Add a blank line between the declarations of QUIZ_SCORES and NUM_EXAMS.
  7. Add a blank line between the declarations of EXAM_WEIGHTS and QUIZZES_WEIGHT.
  8. Add a blank line between the declarations of BONUS_POINTS and PARTICIPATION_POINTS.
  9. Add a blank line above the declaration of the average function.
    1. Search for "average".
    2. Enter a blank line above the current line. O (uppercase letter)
    3. Exit insert mode (to get back to normal mode).
  10. Ensure that there is exactly one blank line above all function declarations.
  11. In the const arrays declared at the top of the file (HOMEWORK_SCORES, HOMEWORK_WEIGHTS, QUIZ_SCORES, EXAM_SCORES, EXAM_WEIGHTS), put each number on its own line.
    1. Jump to the top of the file.
    2. Move down to line 5.
    3. Move to the beginning of the line. 0 (zero)
    4. Move right by 4 words. wwww
    5. Insert a carriage return and a tab, and then immediately exit insert mode (back to normal mode) i<enter><tab><esc>
    6. Start creating a quick macro so you don't have to do that so many times. qq
    7. Move right by words until the cursor is at the beginning of a number. www
    8. Insert a carriage return and then immediately exit insert mode (back to normal mode).
    9. Stop recording the quick macro. q
    10. Replay the macro once. @q
    11. Replay the same macro several more times. @@@@@@@@@@@@ (…and so on)
    12. Insert a carriage return just before the ending curly brace (}) and ensure that it is flush with the left side (i.e., not indented).
    13. Follow a similar procedure for HOMEWORK_WEIGHTS, QUIZ_SCORES, EXAM_SCORES, and EXAM_WEIGHTS.
  12. Right align all of the numbers.
    1. Move to the first 2-digit number in HOMEWORK_SCORES (70).
    2. Insert one space before the line beginning. I<space>
    3. Go down one line (to get to the number 80).
    4. Repeat the last action. (period)
    5. Do likewise for the rest of the two-digit numbers in HOMEWORK_SCORES, as well as the one-digit numbers in QUIZ_SCORES.
  13. Add a comment after every number in each of the const arrays declared at the top of the file (HOMEWORK_SCORES, HOMEWORK_WEIGHTS, QUIZ_SCORES, EXAM_SCORES, EXAM_WEIGHTS), to indicate which homework, exam, or quiz they refer to.
    1. Move to the first number in HOMEWORK_SCORES.
    2. Append the text " // hw" at the end of the line. A<space><space>//<space>hw<esc>
    3. Move back to the first number in HOMEWORK_SCORES.
    4. Append the number "1" at the end of the line so that the comment reads " // hw1".
    5. Append the numbers "2" to "15" at the end of the remaining lines in HOMEWORK_SCORES.
    6. Follow a similar procedure for HOMEWORK_WEIGHTS, QUIZ_SCORES, EXAM_SCORES, and EXAM_WEIGHTS.
  14. Ensure that there is exactly one space after every comma in a function parameter list.
  15. Ensure that there is exactly one space before and after every arithmetic operator, as shown in goal.c.
  16. For the very long arithmetic expressions (exam_score, and summary_score), break them into two lines but align the equals sign in the first line with the plus sign in the second line, as shown in goal.c.
  17. There is a bug with the calculation of quiz_score (first line of the main(…) function). Currently, it is calculated as just the average. It should be the average times 10. Fix this bug.
  18. There is another bug. The print_grade(…) function is used in main(…) but is never defined. Add the following function just above main(…):
    void print_grade(float summary_score) {
      printf("summary score:  %.2f\n", summary_score);
    }
  19. Save. :w<enter>
  20. Modify the print_grade(…) function so that instead of printing the summary score, it prints the letter grade. You will need an if statement (or if else) for each possible letter grade. Do not type all of these repeatedly. Instead, you will use copy-paste. (In vim parlance, these are called yank and put.)
    1. Move to the definition of the print_grade(…) function.
    2. Move to the end of the line. $
    3. Move to the corresponding closing curly brace. %
    4. Move up one line.
    5. Delete the current line ("printf(…"). You should now be back on the closing curly brace.
    6. Add a line above this closing curly brace. This is where you will enter the code to print the letter grade.
    7. Type the following code.
      if(summary_score >= 93) {
          printf("A+\n");
      }
    8. Select the ending curly brace using visual mode.
    9. Extend the selection upward to include all 3 lines of this if statement and its body.
    10. Yank (copy) the selection. y
    11. Move back to the ending curly brace of the if statement.
    12. Put (paste) the text that you previously yanked directly below the if statement. p
    13. Insert the text "else " at the beginning of this line.
    14. Change "93" to "90" and change "A+" to "A" so that you have the following:
      if(summary_score >= 93) {
          printf("A+\n");
      }
      else if(summary_score >= 90) {
          printf("A\n");
      }
    15. Add another copy of the else if clause and adjust the score and grade letter so that you have the following:
      if(summary_score >= 93) {
          printf("A+\n");
      }
      else if(summary_score >= 90) {
          printf("A\n");
      }
      else if(summary_score >= 87) {
          printf("A-\n");
      }
    16. Using a similar method, copy these 9 lines to insert the code for "B+", "B" and "B-". Repeat for "C+", "C", "C-" and "D+", "D", "D-".
    17. Add the else clause.
  21. Fix the two for loops so that they conform to the Code Quality Standards, especially with respect to curly braces and for loop counter scope
  22. Make any other changes needed so that your after.c file is identical to goal.c.
  23. Save.
  24. Exit vim. :q<enter>

Test

Update:  There is now a pre-tester for HW01. From your hw01 directory, type 264test_special_vim . That will replay your keystrokes (recorded.vim) in vim and display any differences with goal.c. If there are no differences, then you are done. Your task is to edit before.c after.c to make it identical to goal.c. If it prints a "Congratulations..." message, you should receive 100%, once scores are posted (probably next week).

There are two ways to test your recorded.vim to make sure you got this right. The best—in terms of your learning—is to use the diff command as follows:

cp before.c after.c
vim -s recorded.vim after.c
diff after.c goal.c

If it prints nothing, then it means after.c and goal.c are identical so you did the assignment perfectly. Otherwise, if it prints any lines, then those lines must have some differences, so you will need to repeat the process. Note that this method of testing will not work properly if you have used the undo command (u) within vim. In that case, try the next method.

The other method of testing your recorded.vim is to use our automated pre-tester. After you submit (see below), type 264test hw01 from bash. 264test will be enabled at least 48 hours prior to the deadline.

Submit (or save)

In general, to submit any assignment for this course, you will use the following command:

264submit ASSIGNMENT FILES…

For HW01, you will type 264submit hw01 recorded.vim from inside your hw01 directory.

You can submit as often as you want, even if you are not finished with the assignment. That saves a backup copy which we can retrieve for you if you ever have a problem.

Before you consider this done, you may want to do a quick check to make sure your recorded.vim is a reasonable size. In the past, a few people accidentally typed vim -W recorded.vim after.c (or similar) after they were done, and inadvertently overwrote their recorded.vim. As a quick double-check, you can type ls -l from bash. Make sure your recorded.vim is at least a few hundred bytes long.

How much work is this?

For those who do not know vim (or don't know it very well), we estimate it may take about 2 hours to go through the tutorial(s) and another 2 hours to edit the before.c to make it identical to goal.c, including time for several repetitions.

If you already know vim well, this assignment should be very easy.

Q&A

Purpose of this assignment

  1. I already know an editor. Why should I learn Vim?

    Even if you know and love some other editor, learning Vim will make you a more versatile programmer. Unlike most other editors, Vim can be used through a terminal (e.g., PuTTY, ssh), which will make your life a lot easier for all homework assignments in this course. this course

    In ECE 264, you will find the workflow for homework assignments a lot simpler and less error-prone if you work directly on ecegrid through an SSH terminal. The course is optimized for working in this way. You will fetch starter files, test your code, and submit—all through an SSH window. Although it would be possible to write your code in another editor on your computer (e.g., Sublime, TextMate, etc.), and transfer the files to ecegrid, that would be inefficient and error-prone. Once you are comfortable editing code through an SSH terminal, you will not need to transfer any files anywhere. Out in the world, that comes in handy when editing code that runs on a server, as well as some embedded systems.

  2. Why not Emacs?

    Emacs is the only other viable choice for coding in a terminal. Like Vim, it is a very powerful tool for programmers who take the time to learn it well.

    We chose Vim for this course because (a) it is introduced lightly in CS 159, (b) its key replay features makes this assignment possible, and (c) it is available and usually pre-installed on practically every Linux/UNIX-based system in the world.

    For decades, there was an ongoing debate over which of the two was better. (Search for [editor war] or [vim vs. emacs], or just read this great article on Slate.) In recent years, several online polls (here, here, and here) have found Vim to be more “popular”, by a ratio of around 4 to 1. However, both have unique features and virtues that appeal to different people. Those who prefer Emacs have plenty of great reasons to do so. The choice of Vim for this class was borne of pragmatism.

  3. Why are we learning any editor? Why not just focus on C?
    This class is about “Advanced C Programming (verb), not “The C Language” (noun). As such, the focus is on doing. When you finish this course, you will be expected to know how to write programs. All serious code editors require some learning. In the past, we found that many ECE students were so focused on the assignments that they never took the time to learn any tool well. We created this assignment to ensure that everyone knows at least one editor well enough to be productive. Typically, very few students come in know some other editor well. Those that do will still benefit, by becoming ambidextrous, and will most likely find this assignment easy anyway.
  4. Do I always have to use vim?
    No. Everyone must learn Vim, and use it for this assignment. After that, you are free to use whatever you like.
  5. Are there any drawbacks to using some other editor?

    Yes. If you use a local editor (i.e., running on your laptop or desktop computer), you will need to transfer the starter files from ecegrid to your computer. Then, every time you want to test them, you will need to transfer your code back to ecegrid. Your code must compile and run on ecegrid using our version of the gcc, so it is important to test on ecegrid. Finally, when you are ready to submit, you will again need to transfer your files.

    If you already know Emacs well, there is no drawback to using that for future assignments. Emacs is installed on ecegrid, and works well through an SSH terminal.

  6. How can I possibly learn to use Vim while simultaneously solving challenging programming assignments?
    This assignment is for you. Learning to use Vim—or any other serious programming editor—well takes effort, so we are giving you this assignment to focus on just that. After this, you will move on to C programming. (There will be one more tool-focused assignment, in which you will learn the Gdb debugger.)

Doing this assignment

  1. How do I know if I have used any arrow keys?
    Open your recorded.vim file in vim. (Be careful not to have the -W flag!) The arrow keys will show up as any of the following:
    • <80>ku
    • <80>kd
    • <80>kl
    • <80>kr
  2. What if I accidentally click the mouse in the window?
    Press gg right afterward to put the cursor on the top line. Then continue. That will make sure that accidentally repositioning the cursor with the mouse doesn't throw off the line that you are editing.
  3. If I quit and come back, can I start where I left off?
    Short answer: No.

    It's easiest if you can do the whole thing in one session. If you quit, it will leave a :q (or similar) command in your recorded.vim file. We looked into possibly filtering those out, but it gets complicated to do properly. Editing your recorded.vim file to remove the :q<enter> is a possibility. You might try doing :vert diffsplit goal.c to see differences and fix them. (You would open your after.c and then enter that command from inside Vim.)

  4. May I edit my recorded.vim file directly?
    Yes. However, the script you turn in should be able to transform before.c into goal.c. If you can find a way to edit your script to make that work, that's fine. However, it may be easiest to just start over. Once you've learned the commands that this assignment uses, the process of transforming before.c into goal.c should be relatively quick.

About Vim

  1. What is vim?
    Vim is a code editor (a text editor designed for programming).
  2. What's the difference between vim and vi?
    Typing vi gives you vim in a "compatibility mode" that simply turns off many of the newer features. It is actually the same program. There is no reason to type vi. Type vim instead.
  3. Where can I use it?
    Vim is almost always installed on Linux and UNIX machines. On Windows, you can install gVim, which gives you GUI.
  4. Can I use the mouse with Vim?
    Yes. This works in PuTTY, but may not work in other SSH programs. (This sample .vimrc enables this for you. If you are using your own .vimrc file, you need to add set mouse+=a to it.)
  5. Can I use tabs?
    Yes. To open several files using tabs, use the -p flag at the command line (e.g., vim -p file1.c file2.c …). Within Vim, use the :tabe command to open another file in a separate tabe (e.g., :tabe file2.c). With the sample .vimrc file, you can also just press F2 to open a new tab, [ to move to a tab to the left, and ] to move to the tab to the right.
  6. Can I get syntax highlighting?
    Yes. (The sample .vimrc file turns this on for you.)

Updates

8/22: Fixed typo in step #3 (colon → semicolon); removed step about blank line between BONUS_POINTS and PARTICIPATION_POINTS; added note about 264test.

8/23: No blank line between EXAM_WEIGHTS and QUIZZES_WEIGHT either; added reminder about setup.