I have a task in university to write a C program which reads a file and counts the number of single and multi comments. The problem I have is that the second while() only reads the first line and so the returned comments are 0.
Previously I read the file character by character, but that's not the task requirement. Why does this program read only the first line and not the others?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
FILE *fp;
int c, i = 0;
char path[256], ch, line[80];
unsigned int multi = 0;
unsigned int single = 0;
enum states {
PLAIN_TEXT,
SLASH,
STAR,
SINGLE_COMMENT,
MULTI_COMMENT,
QUOTES
} state = PLAIN_TEXT;
printf("Write file's name\n");
gets(path)
fp = fopen(path, "r");
if (!fp) {
// give an error message
} else {
while (fgets(line, sizeof(line), fp) != NULL) {
while (i < sizeof(line)) {
printf("%d.%c", i, line[i]);
switch (state) {
case PLAIN_TEXT:
switch (line[i]) {
case '/': i++;
state = SLASH;
break; // found a slash. In the next loop the switch argument will be SLASH
case '"': i++;
state = QUOTES;
break; // found a quote. Quoted text (there might be a '//' inside)
default: i++;
break; // found an ordinary character
}
break;
case QUOTES:
switch (line[i]) {
case '"': i++;
state = PLAIN_TEXT;
break; // Gets out the string;
case ' ':i++;
state = PLAIN_TEXT;
break;
default: i++;
state = QUOTES;
break; // Still a quoted text;
}
break;
case SLASH:
switch (line[i]) {
case '/': i++;
state = SINGLE_COMMENT;
break; // found a slash => a possible single comment found
case '*': i++;
state = MULTI_COMMENT;
break; // found a star => a possible multi comment found
default: i++;
state = PLAIN_TEXT;
break; // found an ordinary character
}
break;
case STAR:
switch (line[i]) {
case '/': i++;
state = PLAIN_TEXT;
multi++;
break; // Increments the multi comment and the next characher will be treated as a plain_taxt
default: i++;
state = MULTI_COMMENT;
break; // Still multi comment
}
break;
case SINGLE_COMMENT:
switch (line[i]) {
case '\n':i++;
state = PLAIN_TEXT;
single++;
break; // End of the single comment line. Increment the counter and the next character will be treated as a plain_text
default: i++;
break;
}
break;
case MULTI_COMMENT:
switch (line[i]) {
case '*': i++;
state = STAR;
break; // Found a multi comment. The next state will be star.
default: i++;
break;
}
break;
default: i++;
break;
}
}
}
fclose(fp);
printf("Single-comment : %8u\n", single);
printf("Multi-comment : %8u\n", multi);
}
return 0;
}
To enumerate the characters on the line, you must reinitialize i to 0 for each line and stop at the null terminator or at the newline character
Related
I'm writing a program to 'encrypt' an inputted string of text by using a switch statement to correlate the given character with a symbol, and output that symbol in the place of the character. I put it in a while loop, the idea being that it would loop the full switch function each time until the received character is EOF. On a guess, I believe it is looping through just the first character, because I don't advance the getchar() statement, but I'm not sure how to do that so any help would be greatly appreciated. I say this because if I use return instead of break, it closes the while loop and only takes that first letter, if I use a break then it spams the first 'encrypted' char.
#include <stdlib.h>
#include <stdio.h>
/* C program to encrypt a given text message, assuming all lowercase */
int main() {
int Input, Encrypted;
printf("Please type your message\n");
Input = getchar();
while (Input != EOF) {
switch (Input) {
case 'a':printf("!"); break;
case 'b':printf("#"); break;
case 'c':printf("#"); break;
case 'd':printf("$"); break;
case 'e':printf("%"); break;
case 'f':printf("^"); break;
case 'g':printf("&"); break;
case 'h':printf("*"); break;
case 'i':printf("`"); break;
case 'j':printf("~"); break;
case 'k':printf("-"); break;
case 'l':printf("_"); break;
case 'm':printf("="); break;
case 'n':printf("+"); break;
case 'o':printf("["); break;
case 'p':printf("{"); break;
case 'q':printf("]"); break;
case 'r':printf("}"); break;
case 's':printf(";"); break;
case 't':printf(":"); break;
case 'u':printf("|"); break;
case 'v':printf(","); break;
case 'w':printf("<"); break;
case 'x':printf("."); break;
case 'y':printf(">"); break;
case 'z':printf("'");break;
return 0;
}
}
return 0;
}
The simplest solution would be to remove the line
Input = getchar();
and to replace the line
while (Input != EOF) {
with:
while ( (Input=getchar()) != EOF && Input != '\n' ) {
Alternatively, if you find this while condition too confusing, you could also use an infinite loop, instead, like this:
#include <stdlib.h>
#include <stdio.h>
int main( void )
{
printf("Please type your message\n");
for (;;) //infinite loop, equivalent to while(true)
{
int c;
c = getchar();
if ( c == EOF || c == '\n' )
break;
switch ( c )
{
case 'a':printf("!"); break;
case 'b':printf("#"); break;
case 'c':printf("#"); break;
case 'd':printf("$"); break;
case 'e':printf("%%"); break;
case 'f':printf("^"); break;
case 'g':printf("&"); break;
case 'h':printf("*"); break;
case 'i':printf("`"); break;
case 'j':printf("~"); break;
case 'k':printf("-"); break;
case 'l':printf("_"); break;
case 'm':printf("="); break;
case 'n':printf("+"); break;
case 'o':printf("["); break;
case 'p':printf("{"); break;
case 'q':printf("]"); break;
case 'r':printf("}"); break;
case 's':printf(";"); break;
case 't':printf(":"); break;
case 'u':printf("|"); break;
case 'v':printf(","); break;
case 'w':printf("<"); break;
case 'x':printf("."); break;
case 'y':printf(">"); break;
case 'z':printf("'"); break;
}
}
return 0;
}
Note that most character sets (such as ASCII) store the characters a to z consecutively. With these character sets, you don't need the long switch statement. Instead, you can simplify it to the following:
#include <stdlib.h>
#include <stdio.h>
int main( void )
{
printf("Please type your message\n");
for (;;) //infinite loop, equivalent to while(true)
{
const char map[] = "!##$%^&*`~-_=+[{]};:|,<.>'";
int c;
c = getchar();
if ( c == EOF || c == '\n' )
break;
if ( 'a' <= c && c <= 'z' )
putchar( map[c-'a'] );
}
return 0;
}
The program needs to execute until 'q' is pressed. But the below code what I wrote it is only executing whichever case is first and then stops executing further cases. Ex: case 1.if my input is p, q, then only p case is executed, not the q.
case 2.if my input is g, q, then only g case is executed, not the q.
int main()
{
int i,n,cnt;
char value[10]={0,0,0,0,0,0,0,0,0,0};
int index; float values,Max;
int *val;
bool quit=false;
float num[10]={1.500, 2.200, 7.300, 9.200, 7.400, 7.500, -8.000, 1.500, 12.000, 0.000};
for(i=0;i<20;i++)
{
scanf("%c",&value[i]);
if(value[i]=='r')
{
scanf("%d", &index);
scanf(", %3f",&values);
}
if((value[i] =='p')|(value[i] =='q')|(value[i] =='r')|(value[i] =='g')|(value[i] =='s'))
{
cnt++;
}
}
for(i=0;i<cnt;i++)
{
while(!quit)
{
switch(value[i])
{
//printf("Command (p/g/r/s/q):");
case 'p':
{
printf("Command (p/g/r/s/q):");
printValues(&num,10);
return;
}
case 'g':
{
printf("Command (p/g/r/s/q):");
Max= largestElement(&num,10);
printf("Max=%0.3f",Max);
return;
}
case 'r':
{
printf("Command (p/g/r/s/q):");
replaceElement(&num,index,values);
printValues(&num,10);
return;
}
case 's':
{
printf("Command (p/g/r/s/q):");
sortOnValue(&num,10);
printValues(&num,10);
return;
}
case'q':
{
printf("Command (p/g/r/s/q):");
quit= true;
break;
}
default:
{
printf("help");
return;
}
}
}
}
return 0;
}
Within most of your case blocks you probably want break rather than return to exit the switch. At the moment you are returning frommain() and consequently exiting the program. break transfers control to the end of the switch and your program can then continue.
The case 'q' block would then have a return to exit the program.
Few problems here.
for(i=0;i<20;i++) you are accessing out of bound so your loop should be
for(i=0;i<10;i++).
You need to add ' ' in the format string to consume new line character (\n).
`scanf(" %c",&value[i]);`
You are using | operator instead of || hence your if should be.
if((value[i] =='p')||(value[i] =='q')||(value[i] =='r')||(value[i] =='g')||(value[i] =='s'))
{
cnt++;
}
You are using return instead of break in your switch case.
change this
case 'p':
{
printf("Command (p/g/r/s/q):");
printValues(&num,10);
return;
}
to
case 'p':
{
printf("Command (p/g/r/s/q):");
printValues(&num,10);
break;
}
Your while(!quit) inside the for loop is not useful and will lead to infinate loop when used break statement inside switch case. Hence remove the while(!quit) and change your for loop as below.
for(i=0;i<cnt&&!quit;i++)
side note:: It is high time for you
learn-how-to-debug-small-programs
I've started studying C in the university. The professor gave us a task - to write a program that counts the number of comments in an another C program. We still haven't talked about operating with files. I found a similar solution - C Program to count comment lines (// and /* */) . Modified it a bit and it actually works but I can't understand the enum stuff. Tried to rewrite it without enumerations but with no success (cuz we have to explain how to program works). My question is - is there a way to solve it without enumerations?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
FILE *fp;
int c, i=0;
char ch;
char path[150];
unsigned int chars = 0;
unsigned int multi = 0;
unsigned int single = 0;
enum states { TEXT,
SAW_SLASH,
SAW_STAR,
SINGLE_COMMENT,
MULTI_COMMENT } state = TEXT;
printf("Write file's path. Separate the folders with TWO back slashes (\\)\n");
scanf("%s", &path);
fp = fopen(path, "r");
if ( !fp )
{
fprintf(stderr, "Cannot open file %s\n", argv[1] );
}
else {
while((c=fgetc(fp)) != EOF){
switch( state ) {
case TEXT :
switch( c )
{
case '/' : state = SAW_SLASH; break;
default : break;
}
break;
case SAW_SLASH :
switch( c )
{
case '/' :
printf("case SLASH case / \n");
state = SINGLE_COMMENT;
break;
case '*' :
printf("case SLASH case * \n");
state = MULTI_COMMENT;
break;
default :
state = TEXT;
break;
}
break;
case SAW_STAR :
switch( c )
{
case '/' :
printf("case STAR case / \n");
state = TEXT;
multi++;
break;
case '*' :
break;
case '\n' :
printf("case SLASH case 'NEW LINE' \n");
multi++; // fall through
default :
state = MULTI_COMMENT;
break;
}
break;
case SINGLE_COMMENT :
switch( c )
{
case '\n' :
printf("case SINGLE case NEW LINE \n");
state = TEXT;
single++; // fall through
default :
break;
}
break;
case MULTI_COMMENT :
switch( c )
{
case '*' :
printf("case MULTI case * \n");
state = SAW_STAR;
break;
case '\n' :
break;
default :
break;
}
break;
default: // NOT REACHABLE
break;
}
}
fclose(fp);
printf( "File : %s\n", argv[1] );
printf( "Single-comment: %8u\n", single );
printf( "Multi-comment: %8u\n", multi );
}
return 0;
}
Since enum is equivalent to a bunch of #define 's, you can replace this part of the code:
enum states {
TEXT,
SAW_SLASH,
SAW_STAR,
SINGLE_COMMENT,
MULTI_COMMENT
} state = TEXT;
with:
#define TEXT 0
#define SAW_SLASH 1
#define SAW_STAR 2
#define SINGLE_COMMENT 3
#define MULTI_COMMENT 4
int state = TEXT;
I'm using ncurses and I'm getting input string with getstr(). I want to make something like autocompletion by Tab keystroke. However, I don't see a way to catch Tab with getstr(). I tried this:
char input = 0;
while (input != '\n')
switch (input = getch())
{
case '\t':
printw("Got Tab\n");
break;
default:
addch(input);
break;
}
But in this case I have to write my own handlings for Backspace, Delete etc., what is undesirable and essentialy is reinventing of wheel.
Maybe try:
switch (input = getch())
{
case KEY_STAB:
printw("Got Tab\n");
break;
default:
addch(input);
break;
}
Complete list of keys
This one works fine for me:
#include <cstdio>
#include <conio.h>
int main() {
char input = 0;
while (input != '\n') {
input = getch();
switch (input)
{
case '\t':
printf("T");
break;
case '\b':
printf("\b \b");
break;
default:
printf("%c", input);
break;
}
}
}
using the latest g++
I'm trying to implement a command line menu in C so that when the user enters a character, it will instantly process the character and carry out specific functions. The problem is, whenever I try to make it so that after each input is processed, the menu displays again and is ready for new input, the program will just continually read input and never process it unless I exit the program.
This is the code that works 1 time through:
char command;
command = getchar();
switch(command){
case 'c':
//create a new hash table;
break;
case 'l':
//look up a word;
break;
case 'f':
//read a file
break;
case 'p':
//print the table;
break;
case 'r':
//Remove a word
break;
case 'q':
exit(0);
break;
}
However, if I try to place it into an infinite loop to continually run, like I said, it will never process the inputs until I exit the program.
This code should work for you — it works for me. Note the use of int for the variable command.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
int command;
while ((command = getchar()) != EOF)
{
switch(command)
{
case 'c':
printf("Create a new hash table\n");
break;
case 'l':
printf("Look up a word\n");
break;
case 'f':
printf("Read a file\n");
break;
case 'p':
printf("Print the table\n");
break;
case 'r':
printf("Remove a word\n");
break;
case 'q':
printf("Quit\n");
exit(0);
break;
default:
printf("Unexpected input %d (0x%.2X) ('%c')\n",
command, command, isgraph(command) ? command : '.');
break;
}
}
return 0;
}