Trying to create a function that counts 3 amounts of lines (lines that aren't empty, lines that are comments, total lines) and return all 3 values

Viewed 73

I as the title says I am trying to create a function that will return 3 values when reading a document for an assignment. I wanted to make it work in a function, so I can just call that function and it will output the 3 values, but at the moment the Developer prompt is just running endlessly and not printing anything. Below is a snippet of my code if anybody could help.

#include <stdio.h>
#include <string.h>
#define LINE 1000

void countLines(int *emptyLines, int *totalLines, int *totalComments)
{
    char line[LINE];
    *emptyLines = 0;
    *totalLines = 0;
    *totalComments = 0;
    FILE *input = fopen("student.java", "r");

    while (fgets(line, LINE, input)) {
        int i;
        int len = strlen(line);
        char *delimiters = "   . , \n \t";
        char *token = strtok(line, delimiters);

        for (i = 0; i < len; i++) {
            if (line[i] != '\n' && line[i] != '\t' && line[i] != ' ') {
                emptyLines++;
                break;
            }
        } // counts all the lines that aren't empty
            
        while (token != NULL) {
            if (strcmp(token, "/**") == 0) {
                totalComments++;
            }
        } // counts the total amount of comments
            
        totalLines++; // counts the total amount of lines
    }
    fclose(input);  
}

int main(int argc, char **argv) {
    FILE *input = fopen("student.java", "r");
    int emptyLines, totalLines, totalComments;
    
    countLines(&emptyLines, &totalLines, &totalComments);

    printf("There are %d total lines, %d lines of code and %d comments in the file\n",
           totalLines, emptyLines, totalComments);
    return 0;
}
2 Answers
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define LINE 1000

void countLines(){
    char* line = calloc(LINE, sizeof(char));
    if (line == NULL) {
        fprintf(stderr, "ERROR: Unable to alloc memory\n");
        exit(EXIT_FAILURE);
    }
    int emptyLines = 0;
    int totalLines = 0;
    int totalComments = 0;
    FILE *input = fopen("student.java", "r");
    while (fgets(line, LINE, input) != NULL) {
        int i;
        char *delimiters = " .,\n\t";
        char *token = strtok(line, delimiters);
        for (i = 0; line[i]; i++) {
            if (line[i] != '\n' && line[i] != '\t' && line[i] != ' ') {
                emptyLines++;
                break;
            }
        } // counts all the lines that aren't empty
        while (token != NULL) {
            if (strcmp(token, "/**") == 0) {
                totalComments++;
            }
            token = strtok(NULL, delimiters);
        } // counts the total amount of comments
        totalLines++; // counts the total amount of lines
    }
    printf("There are %d total lines, %d lines of code and %d comments in the file\n", totalLines, emptyLines, totalComments);
    fclose(input); 
    free(line); 
}


int main(){
    countLines();
    exit(EXIT_SUCCESS);
}

Now it works:

Added token = strtok(NULL, delimiters);at the end of strtok while.

Used calloc to alloc char* line with control of allocated memory.

Opened just one time the file instead of two.

Changed function countLines from (*int, *int, *int) -> void to (void) -> void.

A tip is to read the manual if you re going to use a function you don't know and be clearer with indentation.

Your program has problems:

  • emptyLines++; does not increment the counter, it increments the pointer, which has no effect on the variable in the main function and makes it to an undefined location. Use *emptyLines += 1; instead. The same applies to the other counters.

  • the loop to detect empty lines actually detect non-empty lines. Calling it after breaking the first token from the line with strtok() does not do what you expect. strtok() is tricky and should probably not be used for this problems.

  • the loop while (token != NULL) runs forever if token is not NULL, ie: if there is at least one nonspace character in the line, because you do not modify token in the body of the while loop.

First let's be more precise with the goal:

  • lines that start with white space followed by // are comment lines
  • lines that start with white space followed by /* are comment lines and the comment extends to the line that contains */
  • lines that have just white space are empty lines.
  • other lines are lines of code.

strtok() is not the best function for your purpose: strspn() is your friend.

Here is a modified version:

#include <stdio.h>
#include <string.h>

#define LINE 1000

void countLines(int *linesOfCode, int *totalLines, int *totalComments) {
    char line[LINE];
    int incomment = 0;
    int skip;
    FILE *input;

    *linesOfCode = 0;
    *totalLines = 0;
    *totalComments = 0;

    if ((input = fopen("student.java", "r")) == NULL)
        return;

    while (fgets(line, LINE, input)) {
        *totalLines += 1;
        // compute the number of white space characters at the beginning of the line
        skip = strspn(line, " \t\f\v\r\n");
        if (incomment) {
            *totalComments += 1;
            if (strstr(line, "*/"))
                incomment = 0;
            continue;
        }
        if (line[skip] == '/' && line[skip + 1] == '/') {
            *totalComments += 1;
            continue;
        }
        if (line[skip] == '/' && line[skip + 1] == '*') {
            *totalComments += 1;
            if (!strstr(line, "*/"))
                incomment = 1;
            continue;
        }
        if (line[skip] != '\0') {
            *linesOfCode += 1;
        }
    }
    fclose(input);  
}

int main(int argc, char *argv[]) {
    int linesOfCode, totalLines, totalComments;
    
    countLines(&linesOfCode, &totalLines, &totalComments);

    printf("There are %d total lines, %d lines of code and %d comment lines in the file\n",
           totalLines, linesOfCode, totalComments);
    return 0;
}

Note that this method is too simplistic to handle comments that start on a line of code and extend beyond the current line. Detecting such comments is non-trivial, even for the java language because you need to recognise strings and character constants to handle "/*" correctly.

To try and get a count of lines of code that is independent of the coding style and placement of braces, I would recommend not counting the lines that only contain punctuation such as braces and parentheses. You can simply change the skip line to:

   skip = strspn(line, " \t\f\v\r\n{}[]().,:?;");
Related