Beginner’s guide to awesome C projects

Sabbir Mollah
NSUACMSC
Published in
8 min readNov 19, 2018

--

A bit of backstory

My first CS course in University required me to make a group project in C programming language. My team decided to make a ticket management program for the console.

As beginner enthusiasts we were tempted to write the most efficient code using everything C had to offer. We were all coding on the same file and sharing the file over Facebook messenger. A great amount of our effort was spent just to merge the codes from each other.

We somehow managed to finish the program and present it to our faculty, but the end result was a single file containing a thousand lines of unreadable and unmanageable tricky one-liners.

I wish someone had showed me this quote during the development of that project:

Premature optimization is the root cause of all evil. — Donald Knuth

So here are a few guidelines for you so that you can write a manageable project in collaboration with you teammates.

Your Code, Not your rules

Follow a convention.

A convention is a set of rules that defines that defines how you should name your identifiers (variables, functions, etc.), how to document your code and how to structure your code.

This may seem pretty odd at first. You may find it easier to go out of the convention at first, but always remember

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

Following a convention will make your code readable to your teammates and other people.

Assign meaningful names

As some programmers say, “Explicit is always better than implicit”.

//You will not understand what x or myVariable
//is after a few lines of codes
int x,a,b,c,d, myVariable;
//By giving a proper name you save your brain from the stress
//of remembering the meanings of all those a,b,c,d,x,y,z
int numOfTickets, userId;
//Some programmers even go to the extent
//of not using any abbreviations
int numberOfTickets;

However it is pretty intuitive to keep the loop counters as i,j,k.

Use camel case identifiers

You know camels, right? You also know their shape?

In camel case convention you start your identifier with a lower case letter and the first letter of each other words will be in capital.

Although there are lots of conventions to follow while naming variables, you will see how the camel case convention is the most widely followed convention by developers of almost every language.

//Variables should be in camelCase
int numOfTickets, userId;
//Constants should be all uppercase and the words
//will be separated by underscores
const int NUMBER_OF_SEATS = 100;
const float PI=3.14f;

Indentation

We have smart IDEs these days which does this step for us. But if you use an IDE from the last century, then remember, the TAB button is your best friend.

if( ticketBought ){
printf( "Welcome passenger\n" );
if( isPremium ) printf( "Your lunch is on us!\n" );
printf( "Have a nice journey!\n" );
}

If you write your code like this, don’t blame me if you get hatred from your team mates. Always follow proper indentations in the following manner

if( ticketBought ){
printf( "Welcome passenger\n" );
if( isPremium ) {
printf( "Your lunch is on us!\n" );
}
printf( "Have a nice journey!\n" );
}

Now one can easily understand which line belongs to which block.

Also you can omit the curly braces if you have one line after an if condition, but seriously never do it. You might later unconsciously add another line there and waste hours finding the bug in your code.

/*Code Tells You How, Comments Tell You Why*/

Always put comments in your code. Human brain is very fragile, and legend says it will forget why you put a line in your code after two minutes.

Look at the following code that inputs a password from command line:

for(i = 0; i< MAX_PASS_LENGTH - 1; i++){
if(i<0){
i=0;
}
ch = getch();

if (ch == 13)
break;
if (ch == 8){
putch('\b');
putch(NULL);
putch('\b');
i--;
continue;
}
pass[i] = ch;
putch('*');
}

You see, C can turn into gibberish pretty easily. And if you write your code like this, without commenting even Professor Dumbledore can’t help you.
Now look at the next code, and see if you can make sense of it.

for(i = 0; i< MAX_PASS_LENGTH - 1; i++){
if(i<0){
//This is to prevent i to go to a negative index
//when user presses many backspaces
i=0;
}
//getch() was used instead of getche()
//so that the character doesn't appear
//in command line
char inputChar = getch();

if (inputChar== 13){
//If user presses Enter, break from loop
break;
}
if (inputChar == 8){
//This was a workaround to keep the cursor
//in position when user presses Backspace
putch('\b');
putch(NULL);
putch('\b');
i--;
if( i >= 0){
//Removing character from array
password[i] = '\0';
}
continue;
}
password[i] = inputChar;
putch('*');
}

You could have also used constants to indicate the backspace and enter key valuers in this code.

const int BACKSPACE = 8;
//...
if( inputChar == BACKSPACE ){
//...
}

Commenting is good, but don’t overdo it. The following comment is unnecessary and your peers may even find it humiliating.

//Assigning 10 to the variable spam
int spam = 10;

Use Pure Functions

Make your code modular. Modularity increases the readability and reduces copy pasting of your code.

To maintain modularity write functions that do only one specific task. Also the function shouldn’t have access to variables others than the ones you pass by parameters. To maintain this pattern, avoid using global variables.

int passengers = 10;
int ticketCost = 100;

//...

int calculateFareCollected(){
int total = passengers*ticketCost;
printf("Total Money Collected: %d", total)
}

int main() {
calculateFareCollected();
//...
}

The above code is bad design. First of all the calculateFareCollected() function is not only calculating the fare but also printing it. So, you can only print the value and not use it in other functions. Also, it is accessing two global variables which reduces readability and makes your code prone to bugs. A function might silently change a global variable in a line without you noticing it which may break the whole program.

A better approach to the above code would be

//...

int calculateFareCollected( int passengers, int ticketCost){
return passengers*ticketCost;
}

int main() {
int passengers = 10;
int ticketCost = 100;
int totalFare = calculateFareCollected(passengers,
ticketcost);


printf("Total Fare Collected %d", totalFare);
//...
}

The force of #include

You have been writing #include<stdio.h> from the first day at college.
Do you know what #include does?
Basically there are some basic function definitions such as printf() or scanf() in the stdio.h header file. Similarly there are mathematics related functions and constants defined in math.h . So including a header file in C is like bringing all those definitions in your project file.

Besides including header files, you can also include other c files in your file.

How to include .c files?

#include <stdio.h>
#include "myOtherAwesomeFile.c"
//Make sure the file containing this code and
// myOtherFile.c are in the same directory

Why include other .c files?

First of all, it turns a file containing thousands of lines of codes into smaller files that does one specific task each.

For example, in a Ticket Management type of application you may need a struct definition of a Vehicle and another struct for a User. So you can have your user struct and all the functions that process a user defined in a file called user.c

Similarly, you put all the vehicle related definitions in a file called vehicle.c

This way, you can assign each file to each of your group member.

Then finally put all the files in the same directory and merge them in a main.c file.

//This is main.c file#include<stdio.h>
//...
#include "vehicle.c"
#include "user.c"
int main(){}

Make sure that only the main.c file has a main() function.
However, during development, each developer can write their own main function to test their codes and remove them before merging.

If you are confident enough and want to learn some advanced ways of contributing and project management you can learn about git version control system. But this tool can be overkill at a beginner level.

Project design

There is a famous saying among developers that goes

A week of coding can save you from hours of planning

Make sure you plan the workflow and project design before getting into coding. Remember coding is the easiest part of making a project. The hard stones are the designing and maintenance.

Make a diagram of which page will come after which. Which key press will bring you to which page.

A beginners flowchart of a project

You are just starting out, and I assume you don’t know about design patterns, database schemas yet. So a basic flowchart like the one above would be enough to communicate with your team members.

Before starting the function definitions, define the function signatures and what each of them will do. This will help each member to work independently on his portion.

An efficiency trick for the more curious ones

Let’s say this is your first page of the program

How do you go from the Buy main menu to the ticket buying page? Simple,

if( choice == 1){
system("cls");
buyTicket();
}

Now, how do you get back to main menu from ticket buying page?

if(choice == 0){
system("cls");
mainMenu();
}

Do you think this is a good approach?

In C programming language every variable and function is stored in a function. So if you go and forth a few times between mainMenu and buyTicket you will end up only stacking up the functions one on top of the other never closing it.

To avoid cluttering your space, you can use the return keyword in every other function that wants to get back to main menu. The return keyword will stop the execution of that function. Just remember that once you are back to the main menu, you will have to implement some mechanism to display the main menu contents again.

Files are your best friends

Since C is mostly an introductory course, you probably have no idea about any database system. So, make sure you know about files the most. They are your best options to store information.

Study about reading and writing to files. The basic concepts stay in other programming languages as well, and you will thank yourself later.

If you only know how to read variables from a file, you should also see how to read or write entire structs in a file.

//Reading a struct from file
struct User user;
File *fp;
fp = fopen("USER.DATA","rb+");
while( fread(&user, sizeof(user), fp) == 1) {
printf("\n%s %d", user.name, user.age);
}

This code can read from a file containing information in the following format:

Karim 20
Rahim 30
Amin 27

Tips and Tricks

This is a bonus section for the beginners. These are some functions that I found to be very useful during my C project.

#include <stdlib.h>system("cls");

This function executes any command passed to it. “cls” stands for clear screen thus the function clears your current screen.

#include <conio.h>gotoxy(int x, int y);

This function can be very useful to add some aesthetics to your program. It can move your command prompt cursor to any x,y coordinate. (Top left position is (0,0))

#include <Windows.h>Sleep(x);

The Sleep function can make your program wait or pause for x milliseconds.

Wrapping up

It’s 2018, and internet is more accessible than ever. Always look for tutorials and solutions. There are plenty of people that would gladly help you if you ever face any problem. Follow the mentioned guidelines to make the best possible project.

Questions? Leave a comment.

--

--