• Coding
  • [Exercise] Remove C comments

Write a program that removes comments from a C source file. Consider only the multiline comments /*..... */ and ignore the inline (//).

Remember that comments don't nest, so the follwing input should remove all of line 3 and ignore the second '/*'.
int main (int agrc, char **argv)
{
    /* I write something /* here */

    printf("Number of pure args: %d\n", --i);

    return EXIT_SUCCESS;
}
Side Story: I remember around 10 years ago, we had a three apache web servers load balanced on three different Sun Netras. Had to do a bunch of configuration and the comments were really standing in my way. I wanted to remove the comments from the config but i did not want to pull the config to my dev machine and do it, so i figured i'd give it a try on the machine itself. Granted, the web server should remain free of unneeded software, the only thing i had access to at that time, was "vi", notice it's vi not "vim" on Solaris 7. Had a blast doing it in vi >.<
side answer
s:/\*\_.*\*/::g
This should do it in vi (notice also works with vim - and sed).
Too easy :P

EDIT: It might be problematic for comments spreading on multiple lines though ... Let me look into it.
EDIT 2: I should also note that you can access a file remotely with vim, without even installing it on the web server. Like this:

$ vim scp://user@host/[path_to_file]

but that functionnality might've not been around when you were working on it. It was only around for years.
You're old.

EDIT 3 Updated the code with the correct answer. For the record, you need to add _ to include line breaks in the next character. In this case "."
Funny how once you get how recursion works, you cannot stop using it :)

Here's my code in C.
#include <stdio.h>
#include <stdlib.h>

#define ON 0
#define OFF -1

static int FLAG = ON;

void print_no_comment (FILE *f)
{
    int next = fgetc(f);
    if (next != EOF) {

        switch (FLAG) {
            case ON:
                if (next == '/')
                    FLAG = next;
                else
                    printf("%c", next);
                break;

            case '/':
                if (next == '*')
                    FLAG = OFF;
                else {
                    printf("%c%c", FLAG, next);
                    FLAG = ON;
                }
                break;

            case OFF:
                if (next == '*')
                    FLAG = next;
                break;

            case '*':
                if (next == '/')
                    FLAG = ON;
                break;
        }

    print_no_comment (f);
    }
}

int main (int argc, char **argv)
{
    FILE *csrc = NULL;

    if (argc != 2) {
        printf("Usage: %s filename\n", argv[0]);
        return EXIT_FAILURE;
    }

    csrc = fopen (argv[1], "r");

    if (csrc) {
        print_no_comment(csrc);
        fclose(csrc);
    } else

        fprintf(stderr, "Cannot open file %s\n", argv[1]);

    return EXIT_SUCCESS;
}
rahmu wroteFunny how once you get how recursion works, you cannot stop using it :)
funny how recursion rapes pc's memory :D
In this case it doesn't. Tail recursion optimization.
arithma wroteIn this case it doesn't. Tail recursion optimization.
Tail Call Optimization is usually referred to as an algorithm which smart compilers use to convert tail-recursive (non-mutually recursive) functions to iterative ones.

Sure here its not spamming the heap with stack frames because there is no depth, however its still slightly expensive than an iterative function , and in general its a bad practice to use Recursive functions , unless there is no other way to solve a problem through or the cost required to solve it iteratively is not worth :(.
There is absolutely no reason to avoid writing recursions, especially when answering a coding exercise. Whether recursion is a resource hog is completely tied to the implementation and as arithma mentioned, in this case most modern compilers will know how to avoid the bottleneck.

Optimizing for the sake of optimizing is worse than futile, it's actually very dangerous. Knuth said "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil"

Good code is meant to be read, not just executed.
No matter what , its just a bad practice when not necessary , why not just use a nice while /for loop ? =]

like how about this? shorter and lighter ;)
void print_no_comment (FILE *f)
{
    for(int next = fgetc(f);next != EOF;next = fgetc(f))
    {

        switch (FLAG) {
            case ON:
                if (next == '/')
                    FLAG = next;
                else
                    printf("%c", next);
                break;

            case '/':
                if (next == '*')
                    FLAG = OFF;
                else {
                    printf("%c%c", FLAG, next);
                    FLAG = ON;
                }
                break;

            case OFF:
                if (next == '*')
                    FLAG = next;
                break;

            case '*':
                if (next == '/')
                    FLAG = ON;
                break;
        }
    }
}
PS: C default compiler won't apply tail call optimization to convert to an iterative form .
why not just use a nice while /for loop
Because it's boring.
its just a bad practice when not necessary
Says who?

PS: What the fuck is the "C default compiler"?
it is bad practice simply because the it doesn't satisfy the conditions of "when to use recursion" =]

->by default C compiler i meant the usually used C Compilers, their optimization ain't optimum.
This is turning into a non discussion and a flamewar. I will not stand that. You present no arguments other than "recursion is bad unless absolutely necessary" which is anything but convincing. And I still don't know what are the "usual C Compilers" you're talking about, but I can assure you that the ones I use can manage a simple tail recursion call.

You made me think of this classic piece by Spolsky. In this article, the author criticizes Java as a learning language because it teaches students to overlook the 2 most important points of computer science: pointers and recursion.

I'm not going to argue whether Java is right or wrong, frankly I couldn't care less. But once again, I won't stand by and look while recursion is dismissed as blind overhead. To me criticizing a code for using recursion instead of an iterative loop is almost as idiotic as criticizing a programmer for using functions instead of putting everything in the main() call.

Sure my code ain't the most impressive, but I'm proud of it as hell. A few months ago, I couldn't think in recursive manner, and always admired the great devs of this forum for their ability to do it. Now I can, it did not come without effort. I don't see the point of presenting a simple iterative loop simply because your computer cannot handle it.

Once again, code is meant to be read. I don't care what your compiler says. Do you criticize a mathematical proof because your calculator cannot compute it quickly enough?
Woah flamewars?? noooooooooooo, cheers, you are one king and your code works, i don't want you to think i'm knit picking or sumthn , just was trying to remind you of the basic principle (guideline) , don't forget principles (guidelines) are also the keys of recursion functions :p
take it easy and remember that "In order to understand recursion, one must first understand recursion."
back to the main topic:
StringReplace[sourcecode, "/*" ~~ ShortestMatch[___] ~~ "*/" -> ""]