Entab.c - Program that replaces string of blanks by the min # of spaces & tabs to achieve identical output This is Exercise 1-21 of K&amp;R (2nd edition). 

I've seen someone else's post about it but it doesn't solve the problem the way my code does, and I wasn't sure whether I was allowed to post my code as an answer and ask for feedback (it just seemed better to create a new thread and ask for advice here, didn't wanna pollute the other user's topic but if that's what I am supposed to do please let me know and I'll reply over there).

In any way, here's the approach I took to solve the problem:


  Approach:
  
  
  We'll keep track of number of spaces encountered (between nontab/nonspace characters)
  We'll keep track of characters (that aren't tabs/blanks/newlines) per input line
  We'll evaluate the "gaps" generated by spaces by: 
  
  
  Evaluating whether the number of spaces in between those characters.
  A gap will be "big enough" when the number of spaces is >= TABSIZE
  Then, for all the left over spaces in our "buffer", we'll print them out individually
  
  
  
  Finally, we print out the character that was read in (which was not a tab/blank)
  
  As well as updating space count and character count if necessary.


Here's the code:

#include &lt;stdio.h&gt;

//Entab: replaces string of blanks by the min # of spaces &amp; tabs
//Same tab spots as for detab (8)
//Given performance to tabs.

#define TABSIZE 8

//Approach:
//We'll keep track of number of spaces encountered (between nontab/nonspace characters)
//We'll keep track of characters (that aren't tabs/blanks/newlines) per input line
//We'll evaluate the "gaps" generated by spaces by: 
//  evaluating whether the number of spaces in between those characters.
//  A gap will be "big enough" when the number of spaces is &gt;= TABSIZE
//  Then, for all the left over spaces in our "buffer", we'll print them out individually
//Finally, we print out the character that was read in (which was not a tab/blank)
//Update space count and character count if necessary.

int main()
{
    int c, nc, ns;

    nc = ns = 0;
    while((c = getchar()) != EOF)
    {
        //if this character was a space
        if(c == ' ') {
            //increase the space count
            ++ns;
        }
        //else if the character read in is not a space
        else {

            //while one or more spaces are still "in buffer"
            while(ns &gt; 0)
            {
                //decide whether gap in between chars is long enough for a space
                if(ns &gt;= TABSIZE - nc)
                {
                    //if it is, then place a tab, and remove that amount of spaces
                    putchar('\t');
                    ns -= TABSIZE;
                }
                //else, if the gap is not big enough for spaces, just print them out individually
                else
                {
                    putchar(' ');
                    --ns;
                }
            }

            //if read a newline, reset char count
            //if not, increase it by one for the char we just read in
            //as well as update the total space count to 0
            if(c == '\n')
                nc = ns = 0;
            else if(c != '\t')
                ++nc;

            //finally, put this "nonspace/nontab" character just read
            //after the gap we just covered
            putchar(c);
        }
    }
}


Also, keep in mind that I am just revisiting C's K&amp;R and I am aware that some of it may be outdated, but I'm doing my best to use what's still "useful" of the book and discard what may not be. 

I'm using these notes to accompany my travels through C.
A good implementation of this problem.  You've avoided some of the hurdles (such as remembering to store the result of getchar() in an int if you want to compare against EOF).
Most of what I say will be about style and readability.
Be consistent with your braces
We have a few different styles here:
int main()
{

Brace on its own line.  I like that for function definitions (though others differ).
    while((c = getchar()) != EOF)
    {

Another brace getting its own line.
        if(c == ' ') {
            //increase the space count
            ++ns;
        }
        //else if the character read in is not a space
        else {

Here, the brace shares the same line as the if.  And the else shares a line with only one of the braces.
            if(c == '\n')
                nc = ns = 0;
            else if(c != '\t')
                ++nc;

Here, we have no braces at all.  While that's legal, it's a good idea to always include braces (and I was reminded so recently, when I posted my own code for review!).
I would write the above like this:
int main()
{


    while((c = getchar()) != EOF) {


        if(c == ' ') {
            ++ns;
        } else {
            // not a space


            if(c == '\n') {
                nc = ns = 0;
            } else if(c != '\t') {
                ++nc;
            }

Alternatively, as:
int main()
{


    while((c = getchar()) != EOF)
    {


        if(c == ' ')
        {
            ++ns;
        }
        else
        {
            // not a space


            if(c == '\n')
            {
                nc = ns = 0;
            }
            else if(c != '\t')
            {
                ++nc;
            }

Naming
It's quite conventional to use c for a variable holding the current character.  But nc and ns are less obvious.  You could change the names; alternatively, add comments where they are declared:
    int nc = 0;                 /* number of characters read in this line */
    int ns = 0;                 /* number of consecutive spaces seen */

Comments
Generally the comments are pretty good.  I think you've over-commented a few things that are obvious to an experienced C programmer, but that's natural as you are learning - with experience, you'll recognise parts that are not idiomatic and concentrate your comments there, where they are most needed.
My personal taste is to avoid duplicating the code, so I wouldn't write &quot;else&quot; in the comment when it immediately follows an else in the code - I hope the samples below demonstrate what I mean.
Simplify loops
This loop is quite complex:
        //while one or more spaces are still &quot;in buffer&quot;
        while (ns &gt; 0) {
            //decide whether gap in between chars is long enough for a space
            if (ns &gt;= TABSIZE - nc) {
                //if it is, then place a tab, and remove that amount of spaces
                putchar('\t');
                ns -= TABSIZE;
            } else {
            // the gap is not big enough for spaces, just print them out individually
                putchar(' ');
                --ns;
            }
        }

We can replace with two simpler loops:
            //while one or more spaces are still &quot;in buffer&quot;
            while (ns &gt;= TABSIZE - nc) {
                // place a tab, and remove as many spaces
                putchar('\t');
                ns -= TABSIZE;
            }
            while (ns &gt; 0) {
                // use spaces
                putchar(' ');
                --ns;
            }

Finally
I'm not sure whether you've actually got the logic correct.  Remember that a tab jumps to the next tab stop - it may be equivalent to less than 8 spaces.  Have you tested with a variety of inputs (including tabs in input, and e.g. a run of 4 or 5 spaces after some non-space characters)?
The logic might be simpler if we keep track of current read column and current output column - at the end of a run of spaces we then just need to do the correct action to make the output column match the input column (using tabs where possible).
As a hint, if the current (0-based) column number is n, then a tab will advance the column number by TABSIZE - n % TABSIZE positions.