Appendix A - Coding Practice & Style Guide
When you write programs professionally, you need to be able to have consistent styling. Consistent styling makes your code easier to read and update. These mostly come down to habits... it is better to develop this habit early. If you write your code with a style in mind, it will make your programs easier to read and understand. It will make your own program easier to write because it will make your logical decisions easier to understand. This guide will go over some of the most important aspects of styling your code
There are different opinions when it comes to exact styling. When you go and work, your company could very well have a code styling guide that they expect you to follow. This is to make the code that you write fit together with your co-workers' code. Your code may be rejected if you do not follow code styling guidelines even if it works! Knowing the rules matter. Below are the rules we expect you to follow when writing your programs for this course. You will be expected to follow these styling rules when you write your programs and your grade will be affected if these conventions are not followed.
Single Entry Single Exit (SESE)
In this course, you must follow the single entry single exit principle in all your code. This means that in every code block (functions, loops etc.) you must have only ONE entry and only ONE exit.
You can typically avoid this by following a few simple steps:
- declare a variable that will hold your return value and in every step of your code, make sure that variable is correct and consistent. The variable is returned only once at the very end of your function.
- In every loop, your loop condition expresses all reasons to continue the loop. there should never be any checks to get out of the loop outside of the loop condition.
Simple way to tell if your code is breaking the SESE Principle:
- if your function has more than one return statement, you have broken SESE
- if inside your loop block, you see this...you have broken SESE: _ break; (unless it is also inside a switch) _ continue;
Loop Control
For loops:
A for loop involves an iterator variable that is initialized,checked and updated in the for statement. The update to this variable must be done ONLY in the for() statement
Correct ✅
This block of code prints even numbers starting at 0 up to but not inclusive of n
int i;
for (i = 0;i < n;i+=2){
printf("%d\n", i);
}
Wrong ❌
This block of code prints also prints even numbers starting at 0 up to but not inclusive of n but the i gets updated inside the loop.
int i;
for (i = 0;i < n;i++){
printf("%d\n",i);
i++;
}
While and do-while loops loops
While and do-while loops are more flexible in terms of when the items that control a loop get updated. However, as much as possible, the update conditions should be done in a succinct manner that avoids undoing updates. This means that we should use as few variables as possible to accomplish our task and limit how the updating of these variables occur.
Use of a control variable
One way to simplify this is to use a control variable. The control variable is essentially a boolean and while the control variable is one value, the loop continues. Otherwise it the loop ends. This makes it so that any changes amount to whether or not the control variable gets modified.
Example:
while( keepAdding && hasSpace) {
...
if(some condition that indicates we are out of space){
hasSpace = 0;
}
...
if(some condition that indicates we should stop adding){
keepAdding = 0;
}
...
}
Naming Conventions
For any thing where you must provide a name use the following guideline
The Names
- all names must be descriptive. The name is part of the documentation so use a descriptive name.
- single character variable names are not allowed unless they are part of a commonly known naming convention
- i, j and k are allowed as loop counters in for loop. They must be used in that order. If it is a single for loop, the counter is i. If you have a for loop inside another for loop, the outer most loop is i, the inner loop is j.
for(i = ...){
for(j = ... ){
for(k = ...){
...
}
}
}
- x, y and z are only allowed if they are used to store coordinates
Casing
The convention is to use SCREAMING_SNAKE_CASE, UpperCamelCase or lowerCamel case for names depending on what the name refers to.
constants
If you are declaring a constant either through #define statement or a const variable, the name for the constant should be in SCREAMING_SNAKE_CASE. This means that every word is separated by an underscore and we write every thing in upper case
Examples:
#define PI 3.14159
const int MAX_CAPACITY = 50
function, parameters and variable names
Declare functions, variables and parameters in lower camelcase. To create a name that is lowerCamelCase, write all words of the descriptive name in all lower case. Starting with the second word, capitalize the first character of the word.
Examples:
double widthOfCar
double startingSalary
int hoursWorked
structs
Declare the name of a struct (not the instance.. the struct itself) in upper camel case. This casing capitalizes the first character of every word including the first.
Examples:
void EmployeeRecord(...);
int MedalStandings(...)
struct VideoPlaylist
{
...
}
pointers
When declaring pointers, declare only one pointer variable per line and put the * character with the data type name for sematic clarity.
int* ptr;
struct Student* studentPointer;
Consistent conventions
There are other naming conventions that some programmers adopt. For example, some programmers use something called "Hungarian Notation"...(came from Charles Simonyi, a Hungarian-American developer in the early days of Microsoft). Hungarian Notation adds extra characters to describe the types of the variables. For example, instead of using just ageOfPet, you would indicate that it is an integer by using iAgeOfPet.
These kind of naming conventions can be divisive and controversial. Some were created to address language related issues. It doesn't mean its good in the languages we use today! While we will leave it to you to decide if you want to adopt something such as "Hungarian Notation", you must consistently follow the convention. Do not sometimes use it but sometimes not use it. It is either all or nothing.
Code blocking
In C, the curly brackets, , are used to create blocks of code. Here are the rules of where to place these curly brackets
For functions and struct declarations put the opening curly bracket on the next line.
struct MyStruct
{
//struct member declaration goes here
};
void myFunction(...)
{
//code goes here
}
For control structures such if/else/for/while/do-whiles, put the opening curly on the same line as the control structure
if(...){
}
for(...){
}
While C does allow you to not use curly brackets if there is only one statement in the control structure, it is bad habits. You are expected to always use curly brackets with your control structures
Indentation
- Use 4 spaces for indentation size.
- You may choose to use tabs or spaces for indentation BUT, you must use one or the other. You cannot mix it.
- Every code block that is inside another code block needs to be indented one indentation
Variable declarations
Declare One Variable per line
In general variables should be declared one per line. This makes the code easier to read. The only time where it might be acceptable to declare multiple variables per line is when the two variables are very closely related. For example if you are declaring two variables to store coordinates:
int x,y;
Otherwise, it is better to declare one variable per line.
Pointer Declaration
Declare pointers with the * symbol directly next to the data type:
datatype* variablename;
Comments and Documentation
Comments make your code easier to read but there is a balance that must be maintained. Too little comments and reading your program becomes a huge slog. Comment too much and you risk creating "sacred text" in your program. These are comments that are for one reason or another never modified even when the code changes. At some point the code and comments mismatch and the reader is left to decide whether the code is wrong or the comment is wrong. This is not a good thing.
Required documentation
- Every function that you write requires documentation. This documentation must include the following:
- high level description of what your function will do. (be clear about the "what", not the "how")
- parameters to the function - what the function is expecting and any limitations
- what the function returns - what is the function suppose to return
- Anytime where you are doing something that is not clearly obvious
- Extended descriptions that would have made names too long
Comment do's and don't's
Do's
- DO state intentions
- DO state things that go beyond names (like units)
- DO state for each function what it accepts, what it returns and what it does (at a high level), special cases, etc.
Don'ts
- DON'T state the obvious
- DON'T write line by line comments that mirrors the code... documentation is about intention. You want to state why are you doing something instead of what you are doing. The what should be obvious from the code. The intention is not always obvious and needs documentation.