There will be weekly take-home lab assignments, each consisting of 2 to 4 exercises. The main objective of these assignments is to provide feedback for you on your own learning. As they are primarily used for formative assessment, we have kept their weightage low -- 10% of your final grade, to encourage you, especially beginners, to work on your own without the fear of losing too many marks. With this, we hope that you would be motivated to do all these programs all by yourself instead of resorting to copying or asking for help from others.
Copying others' programs or relying on others to help you on these assignments will only offer short-term reprieve. When Practical Exam (PE) time comes, your inadequancy will be exposed and the consequence would be dire.
You are advised to (1) spend some time thinking before you begin coding, (2) practise incremental coding and (3) test your programs thoroughly.
Please note that:
A student who is caught copying program from others, or knowingly allowed his program to be copied, will have his Attempt Mark revoked for that lab assignment and his identity noted. In the case of a repeat offender, he will be referred to the School for disciplinary action.
Lab assignments are to be attempted individually so reason such as collaboration, intentional or arising from convenience (such as sharing of laptop), will not be accepted.
Should there be any dispute or appeal, please consult your respective lecturer.
The 1 mark Attempt Mark is awarded to you for each lab assignment if you satisfy ALL the following conditions:
For your Feedback Mark, below are the grading guidelines given to the graders. Each program has a maximum of 100 marks. Unless otherwise stated. the correctness of a program constitutes 60 marks, while design andstyle make up the other 40 marks.
CodeCrunch determines program correctness by feeding a set of test data into your program and comparing your output with the correct output. The test cases have equal weights. Therefore, if N test cases are used, then each test case is worth 60/N marks. N is usually 10.
If your program cannot be compiled (and hence it cannot be run), you will get zero mark for correctness.
Hence, each time after you edit your program, make sure you compile, run and test it. As CodeCrunch grabs your source code (.c) and not your executable code (.exe), if you didn't test it and your program contains compilation error, CodeCrunch will not be able to compile your source code, and you will get zero mark for correctness.
If you hardcode your output, you will get zero mark for correctness,
even though your output may happen to be correct. (Hardcoding the
output means, for example, you write "printf("100\n");" and hope that
one of the test data's answer is indeed 100. Even if it is so,you won't
get the mark.)
Style constitutes 20 marks and design constitutes another 20 marks for Lab #1. From Lab #2 onwards, style constitutes 15 marks and design 25 marks.
In general, style refers to typographical and documentation issues such as indentation and spacing, naming of variables, readability, proper comments, etc. whereas design refers to choice of algorithm, use of appropriate programming constructs, efficiency, modular programming, etc. Sometimes, when a certain item may not fit into style or design category, it is arbitrarily categorised under either one for convenience.
A negative marking scheme will be used for marking design and style. Your grader will manually check your program and deduct marks according to the points listed in this document. For some lab assignments, there will be additional guidelines which are specific to the assignment. The grader has the authority to justify and deduct marks for problems in a program which are not covered in the guidelines.
Note that the following are just general guidelines. For each lab exercise, there might be additional specific guidelines given to the grader.
Style
Design
Should any discrepancy, dispute or queries arise in grading, the students should first approach their respective discussion leader for clarification. The discussion leader should exercise his/her good judgment in granting appeals, bearing in mind the marking consistency among other programs with similar issues. If the appeal cannot be resolved with the discussion leader, the lecturer shall be the final arbiter in deciding an appropriate resolution.
The main goal of the recommendations here is to improve readability and thereby the understanding and maintainability of the code. Violations to this guide are allowed if they enhance readability.
For example,
// PREFERRED double x,y,z; // Coordinates of a particle
As opposed to:
// AVOID double x; double y; double z;
Use descriptive names for variables so that their meanings are immediately clear when they appear in the code. For example, "int coins;" is an appropriate variable but not "int c;". Avoid using single character for variable names.
There are some exceptions, however, as shown below:
Despite the recommendation for descriptive names, identifiers can be short yet descriptive by using abbreviations and/or common naming conventions. For example,
// AVOID MAXIMUM_LENGTH, numberOfElements, currentNodePointer, table_number
can be shortened without losing their descriptive form:
// PREFERRED MAX_LEN, nElems, pcurr, table_num
Negated variables often results in hard-to-read double-negatives in an expression like !isNotError.
// AVOID isNotError, isNotFound, isNotValid, cannotOpenFile
// PREFERRED isError, isFound, isValid, canOpenFile
Avoid direct use of magic numbers. Constant literals which have special meanings should be named and its named identifier should be used in its place. For example:
// AVOID for (i=0; i<100; i++) { ... }
// PREFERRED #define MAX_LEN = 100; ... for (i=0; i<MAX_LEN; i++) { ... }
MAX_ITERATIONS, MAX_LEN, GOLDEN_RATIO, COLOR_DEFAULT, PI
Code should be properly and neatly indented to emphasize the nested logical structure of the program. An indentation of 4 spaces is recommended (8 is too wide and 2 is too cramp).
Every block that follows a for, while, if-else, switch, do-while statement must be indented from its enclosing block.
Comments within a block should follow the indentation level of its enclosing block. For example,
for (i=0; i<3; i++) { // Trailing open-braces is OK // Comments should be indented too while (j != i) // Leading open-braces OK as well { // More indented comments printf("Hello\n"); } }
The following are wrong ways to indent the comments.
for (i=0; i<3; i++) { // This comment should be indented and aligned with the while statement. while (j != i) { // This comment should be aligned with the printf statement. printf("Hello\n"); } }
There are two camps on the position of open braces. The following shows the "trailing open braces":
for (i=0; i<3; i++) { // Trailing open-brace while (j != i) { // Trailing open-brace printf("Hello\n"); } }
The following shows the "leading open braces". The leading open brace must be aligned with the block of the construct it is in:
for (i=0; i<3; i++) { // Leading open-brace while (j != i) { // Leading open-brace printf("Hello\n"); } }
Both styles are acceptable, but you should be consistent and should not mixed both styles in a single program.
For close braces, they should be leading close braces aligned with the block of the construct. Close braces should NOT be trailing as that would make it hard to spot them.
Major segments of code should have explanatory comments. A major segment may be a loop block or a function block.
An "if" block with a complex condition or an expression that is hard to understand should have explanatory comments. For example,
// Check and reject out-of-bounds indices if (k < 0 || k >= MAX_LEN) { return -1; }
A comment such as:
i++; /* add one to i */
serves no purpose, adds clutter to a program and does more harm than good.
It is good to add a blank line between two functions, or two long segments of code for readability.
// This function ... int f(int x) { // body } // This function ... int g(double y) { // body }
// Statements 1 to 10 belong to a sub-task statement1; statement2; : statement10; // Leave a blank line for readability statement11; statement12; :
However, guard against the use of excessive blank lines. Double blank lines should be used sparingly, if at all. Triply blank lines, or more, should not be present.
If a line (be it a statement or a comment) is too long (more than 80 characters), do not let it run through the screen and wrap around. Instead, split it into a few lines.
// This is not advisable printf("%s: name = %s; age = %d; gender = %c\n", header, player.name, player.age, player.gender); // This is preferred printf("%s: name = %s; age = %d; gender = %c\n", header; player.name, player.age, player.gender);
As programs get more complex, program design becomes increasingly important. Decomposing a complex program into smaller, more manageable units and the design of the interfaces between the units are fundamental to good programming. Generally, the constituents of a program unit should be highly cohesive (5.1), and the coupling between program units should be clean and minimal (5.2). Algorithmic logic should be easy to understand (5.4). The program should also be easy to setup and its usage should be intuitive (5.3).
(Students to note: You may skip this section for a start, and return to read this at a later point of time.)
Each function should consist of closely related elements. If a function consists of a mixed-bag of unrelated elements, it often indicates a need to modularize the code into further cohesive program units.
As a general rule, each function should do only one thing. This should be done so that the conceptual unit can be understood easily. Sometimes it will be convenient to do two things in a function because you are working on the same data. Try to resist this temptation. Make two functions if you reasonably can.
Often the naming of the function indicates its cohesiveness. Does the method only do what its name says, or does it do more than that? If you find that a complete name for one of your method is like openInputAndReadVectorAndComputeSum(..), it is time to break the multi-tasked function into its sub-constituents.
Segments of code which are repeated should be abstracted into a function. This not only results in shorter programs but also makes it easier to maintain and read. The abstracted function then forms a cohesive unit by itself.
(Students to note: You may skip this section for a start, and return to read this at a later point of time.)
If changing one function in your program requires changing the main function, then a coupling exists between the two functions. One indicator of program quality is the amount of coupling between your program units.
Coupling indicates a dependency between source codes. Reducing this dependency improves the quality and maintainability of your program.
Is the program particularly difficult to use?
Simplicity is a virtue. Wherever possible, your program should be simple, compact, and easy to read. For example, long chains of nested if-else statements can often be replaced with a more compact form for evaluating the logic. If you find that the logic in your code is getting very unwieldy, rethink and rewrite it.
Some labs may expressly disallow the use of certain syntax. Generally, using syntax or statements which are not yet covered either in class or in the lab handouts is strongly discouraged. The lab assignments are designed such that you should not need to do so. If the objective of the assignment is undermined, the penalty for using such forbidden syntax will be heavy.
For instance, if all the inputs to a problem are integers, the program should refrain from introducing any variables of floating-point type. Similarly, it should refrain from invoking any functions which involve floating-point types.
Other examples including using while instead of for when the number of iterations is easily determined before the loop.
Although in CS1010 we are not too concerned about order-of-growth efficiencies, any obvious inefficiencies which can easily be avoided must not be present, or they will be penalised.
It is not easy to write fool-proof and robust programs from the start. Unless otherwise stated, you may assume that the input data used to test your programs are all valid and are according to the problem specification. Hence, you do not need to write extra code to check for data validity unless otherwise stated. As we go along, we may include such requirement once you gain more programming experience.