Program to count lines, char, or words from file - c

I am writing a program to count words as practice but I am running into a problem where it is incorrectly counting no matter which option I choose.
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
int main(int argc, char **argv){
int totalcount = 0; //hold overall count
for(int i = 2; i < argc; i++){
int count = 0; //hold count for each file
int c; //temporarily hold char from file
FILE *file = fopen(argv[i], "r");
if (strcmp("-c",argv[1])){
while((c = fgetc(file)) != EOF){
count++;
}
}
else if(strcmp("-w",argv[1])){
bool toggle = false; //keeps track whether the next space or line indicates a word
while((c = fgetc(file)) != EOF){
if(!toggle && ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))){
toggle = true;
}
if(toggle && ((c == '\n') || (c == ' '))){
count++;
toggle = false;
}
}
}
else{
while((c = fgetc(file)) != EOF){
if(c == '\n'){
count++;
}
}
}
printf("%d %s", count, argv[i]);
fclose(file);
totalcount += count;
}
if (argc > 3){
printf("%d total", totalcount);
}
return 0;
}
I don't know why my logic for char count doesn't work. I have ran through my logic when writing each section and it doesnt make sense to me why it would not me working. Any help would be greatly appreciated.

strcmp returns 0 when the strings equal, so never enter into the if/else statement
if (strcmp("-c",argv[1]) == 0){ //return value is 0
while((c = fgetc(file)) != EOF){
count++;
}
}
else if(strcmp("-w",argv[1]) == 0){ //return value is 0
bool toggle = false; //keeps track whether the next space or line indicates a word
while((c = fgetc(file)) != EOF){
if(!toggle && ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))){
toggle = true;
}
if(toggle && ((c == '\n') || (c == ' '))){
count++;
toggle = false;
}
}
}
Hope it works for you

You can read file line by line, it may simplify the task
int get_lines_chars(const char *path)
{
/* Open templorary file */
FILE *fp = fopen(path, "r");
if (fp != NULL)
{
ssize_t read;
size_t len = 0;
char *line = NULL;
unsigned int line_no, char_no;
line_no = char_no = 0;
/* Read line-by-line */
while ((read = getline(&line, &len, fp)) != -1)
{
int curr_line = 0;
while (*line)
{
curr_line++;
char_no++;
line++;
}
line -= curr_line;
line_no++;
}
/* Cleanup */
fclose(fp);
if(line) free(line);
printf("File has %d lines and %d chars\n", line_no, char_no);
return 1;
}
return 0;
}

Related

fflush(stdout) not working but \n' works in C language

I was working on a homework problem when I encounter this error, fflush inside main function in main.c is not working
I tried the code in ubuntu local system and in repl.it and the output does not contain "#include" line from sample.c , The only line "preprocessor " is printed in terminal..
Files used:
main.c
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
char token[1024];
int toksize = 0;
int breaker = 0;
int is_normal(char ch) {
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|| ch == '_' || (ch >= '0' && ch <= '9'))
return 1;
return 0;
}
int Tokenizer(FILE * file_ptr) {
char ch;
toksize = 0;
ch = 'a';
while (is_normal(ch) == 1 && ch != EOF) {
ch = fgetc(file_ptr);
if (ch == EOF) break;
if (toksize > 0 && !is_normal(ch)) break;
token[toksize] = ch;
toksize++;
token[toksize] = '\0';
}
if (ch == EOF)
breaker = 1;
if (toksize > 1 || is_normal(token[0]))
fseek(file_ptr, -1L, SEEK_CUR);
// fflush(stdin);
// fflush(stdout);
return 1;
}
int main() {
fprintf(stderr, "ji");
int flag = 0;
FILE * fd = fopen("sample.c", "r");
breaker = 0;
if (fd == NULL) {
printf("file not found!!");
return 0;
}
while (breaker == 0 && Tokenizer(fd) > 0) {
int stage = 0;
if (token[0] == '#') { // handling preprocessor
while (token[0] != '\n') {
printf("%s", token);
if (Tokenizer(fd) == 0) {
breaker = 1;
break;
}
}
fflush(stdout);
printf(" -- preprocessor directive\n");
}
}
}
sample.c
#include<stdio.h>

How to parse bigger amount of words?

I have a program, which receives filename as an input, saves file contents into 2d char array and then outputs words. It works absolutely fine for about 400 words, but then, when I add more words, it crashes. Debugging showed that i am trying to access unused address, and I don't understand how is that possible considering that previous tests with lesser amount of words were successful.
The question is: what am i missing here?
FILE: functions.c
#include "Lab10.h"
#include <stdio.h>
#include <malloc.h>
char** parser(char* filename) {
FILE* fp;
fp = fopen(filename, "r");
char** str = (char**)calloc(N, sizeof(char*) * N);
if (!str)
{
printf("\n Allocation error");
return NULL;
}
char ch;
int space = 0, words = 0;
for (int i = 0; !feof(fp); i++) // Memory allocation
{
ch = fgetc(fp);
if (!is_ch(ch))
{
if (i != space)
{
if (!(str[words] = (char*)calloc(i - space, sizeof(char) * (i - space))))
{
printf("\n Allocation error");
return NULL;
}
words++;
}
while (!is_ch(ch) && !feof(fp))
{
ch = fgetc(fp);
i++;
}
if(!feof(fp))
fseek(fp, -(int)sizeof(char), 1);
i--;
space = i;
}
}
fseek(fp, 0, SEEK_SET);
for (int i = 0; i < words; i++) // Copying words into 2d array
{
while (!is_ch(fgetc(fp)));
if (!feof(fp))
fseek(fp, -(int)sizeof(char), 1);
int j = 0;
do {
if (((fscanf(fp, "%c", &str[i][j])) != 1))
break;
j++;
} while (is_ch(str[i][j-1]) && !feof(fp));
}
return str;
}
int is_ch(char ch)
{
return ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'));
}
FILE: main.c
#define _CRT_SECURE_NO_WARNINGS
#include "Lab10.h"
#include <stdio.h>
#include <stdlib.h>
int main() {
char* filename = (char*)malloc(sizeof(char) * N);
if (!scanf("%s", filename) || filename == 0)
{
printf("\n Incorrect filename input");
return -1;
}
char** str = parser(filename);
printf("\n Contents of .txt file:");
for (int i = 0; str[i] != NULL; i++) {
printf("\n\t%d) ", i+1);
for (int j = 0; is_ch(str[i][j]); j++) {
printf("%c", str[i][j]);
}
}
return 0;
}
This answer was posted as a reply to one of the comments below the question itself. I tried writing readWord function, which recieves filepointer, reads one word and then returns pointer to the resulting array - that's eases the procedure, making it less complex. It works almost like fgets(), but it reads till non-character, instead of a newline
readWord function itself:
char* readWord(FILE* fp) {
char ch = 0;
while (!is_ch(ch))
{
ch = fgetc(fp);
if (ch == EOF || !ch)
return NULL;
}
int size = 1;
while (is_ch(ch))
{
if ((ch = fgetc(fp)) == EOF || !ch)
break;
size++;
}
fseek(fp, -(size * (int)sizeof(char)), 1);
if (ch != EOF || !ch)
size--;
char* word = (char*)calloc(size, sizeof(char) * size + 1);
if (!word)
{
printf("\n Allocation error.");
return NULL;
}
for (int i = 0; i < size; i++)
word[i] = fgetc(fp);
word[size] = '\0';
return word;
}
That's how i use it in main():
FILE* fp = fopen("test.txt", "r");
char* word;
while ((word = readWord(fp)) != NULL)
{
for (int i = 0; word[i] != '\0'; i++)
printf("%c", word[i]);
printf(" ");
}
Is there is anything i need to improve here? It works fine, but is it possible to somehow make it better?

Brainfuck interpreter not running some codes

I'm kinda new to C programming and decided that making a brainfuck interpreter in C would be a good way to learn the language. I could write and tested with these bf codes:
this should print a hello world
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
this works as expected, so i thought my interpreter worked fine, but when I tested with a few variants of the hello world code, strange things happened.
this bf code should also print a hello world, but instead it prints out ²♣■■ÖFu ÖÖ■♦u
--<-<<+[+[<+>--->->->-<<<]>]<<--.<++++++.<<-..<<.<+.>>.>>.<<<.+++.>>.>>-.<<<+.
this bf code should also print a hello world, but instead the program gets stuck
+[-->-[>>+>-----<<]<--<---]>-.>>>+.>>..+++[.>]<<<<.+++.------.<<-.>>>>+.
this is the code I wrote to interprete brainfuck:
#include <stdio.h>
int main(int argc, char const *argv[])
{
if (argc == 1)
{
printf("You must specify a file path\n");
return -1;
}
//amount of memory locations available
int mem = 30000;
//creating an integer array with mem positions
char arr[mem];
//current memory position
int index = 0;
//setting everything to 0
for (int i = 0; i < mem; i++)
{
arr[i] = 0;
}
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
printf("ERROR, file couldn't be read\n");
return -1;
}
//reading util the END OF THE FILE
char c;
while ((c = fgetc(file)) != EOF)
{
if (c == '+')
{
arr[index]++;
}
else if (c == '-')
{
arr[index]--;
}
else if (c == '>')
{
index++;
index %= mem;
}
else if (c == '<')
{
index--;
index %= mem;
}
else if (c == '.')
{
printf("%c", arr[index]);
}
else if (c == ',')
{
scanf("%c", &arr[index]);
}
else if (c == '[')
{
char temp = fgetc(file);
int skip = 0;
while (temp != ']' || skip != 0)
{
if (temp == '[')
skip++;
if (temp == ']' && skip > 0)
skip--;
temp = fgetc(file);
}
fseek(file, -1, SEEK_CUR);
}
else if (c == ']')
{
if (arr[index] != 0)
{
fseek(file, -2, SEEK_CUR);
char temp = fgetc(file);
int skip = 0;
while (temp != '[' || skip != 0)
{
if (temp == ']')
skip++;
if (temp == '[' && skip > 0)
skip--;
fseek(file, -2, SEEK_CUR);
temp = fgetc(file);
}
}
else
{
continue;
}
}
}
fclose(file);
return 0;
}
Thanks a lot if you can help me out on this one.
There's could be a problem with this piece of code, when index become negative.
index--;
index %= mem;
% operator retains the sign of the left argument, so -1 % mem is –1, not mem–1 you may expect.

How can I get my Lexical analyzer program to print out more than just seperators?

Im writing a Lexical analyzer to read from a file and describe the text as either identifiers, keywords, separators, or operators. For some reason I am only able to output the separators, unless I delete or comment out the while loop with the print statement for the separators. When I delete that, the program prints out everything else correctly, skipping over the separators.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
int isKeyword(char buffer[]){
char keywords[32][10] = {"auto","break","case","char","const","continue","default",
"do","double","Else","enum","Function","Float","for","goto",
"If","Integer","long","register","Return","short","signed",
"sizeof","static","struct","switch","typedef","union",
"DOWhile","void","Write","while"};
int i, flag = 0;
for(i = 0; i < 32; ++i){
if(strcmp(keywords[i], buffer) == 0){
flag = 1;
break;
}
}
int k, flag2 = 0;
for (k = 0; k<32; ++k){
if(strcmp(keywords[i], buffer) == 0){
flag2 = 1;
break;
}
}
return flag;
return flag2;
}
int main(){
char ch, buffer2[15], operators[] = "+-*/%=";
char ch2, buffer[15], seperators[] = "{}(),;";
FILE *fp;
int i,k,j=0;
fp = fopen("input.txt","r");
if(fp == NULL){
printf("error while opening the file\n");
exit(0);
}
while((ch = fgetc(fp)) != EOF){
for(i = 0; i < 6; ++i){
if(ch == operators[i])
printf("%c is operator\n", ch);
while((ch2 = fgetc(fp)) != EOF){
for(k = 0; k < 6; ++k){
if(ch2 == seperators[k])
printf("%c is seperator\n", ch2);
}
}
if(isalnum(ch)){
buffer[j++] = ch;
}
else if((ch == ' ' || ch == '\n') && (j != 0)){
buffer[j] = '\0';
j = 0;
if(isKeyword(buffer) == 1)
printf("%s is keyword\n", buffer);
else
printf("%s is indentifier\n", buffer);
}
}
}
fclose(fp);
return 0;
}
The problem seems to be the second while loop containing the separator instructions, but I cant seem to figure out how to print that along with everything else.
I think this may help.There is no reason to create an additional char ch, or the buffer, when creating the separators. Just add it onto the end of the previous line. I just split it with a comma.This will clean your code up and allow you to keep the separators with the rest of the while loop code.
#include <stdio.h>
#define KEY 32
#define BUFFER_SIZE 15
int isKeyword(char buffer[])
{
char keywords[KEY][10] = { "auto","break","case","char","const","continue","default", "do","double","else","enum","extern","float","for","goto",
"if","int","long","register","return","short","signed", "sizeof","static","struct","switch","typedef","union", "unsigned","void","volatile","while"};
int i, flag = 0;
for (i = 0; i < KEY; ++i)
{
if (strcmp(keywords[i], buffer) == 0)
{
flag = 1;
break;
}
}
return flag;
}
int main()
{
char ch, buffer[BUFFER_SIZE], operators[] = "+-*/%=", separators[] = "(){}[]<>,";
FILE *fp;
int i, j = 0;
fp = fopen("Text.txt", "r");
while ((ch = fgetc(fp)) != EOF)
{
for (i = 0; i < 6; ++i)
{
if (ch == operators[i])
{
printf(" OPERATOR: %c \n", ch);
}
else if (ch == separators[i])
printf(" SEPARATOR: %c \n", ch);
}
if (isalnum(ch))
{
buffer[j++] = ch;
}
else if ((ch == ' ' || ch == '\n') && (j != 0))
{
buffer[j] = '\0';
j = 0;
{
if (isKeyword(buffer) == 1)
printf(" KEYWORD: %s \n", buffer);
else
printf(" IDENTIFIER: %s \n", buffer);
}
}
}
fclose(fp);
return 0;
}

Segmentation fault (core dumped) when reading file

I'm doing a simple project to read a input.txt text file and show some basic statistics about it. The file is supposed to be about the entrance on a company building. That's how the file is:
1 ; Visitor ; 10 ; 19 ; 2
2 ; 1 ; Worker ; 8 ; 0
3 ; 2 ; Director ; 12 ; 19
4 ; 5 ; Worker ; 18 ; 22
5 ; Visitor ; 8 ; 0 ; 3
Format is = ID ; Companions(if employee) ; Type ; Entrance Time ; Exit Time ; Services(if Visitor)
I got the program to read the file correctly (i guess), it reads the first worker correctly, but when it gets to the second one it reads the ID and suddenly exits with Segmentation fault (core dumped).
I'd really appreciate if someone with more knowledge could help since i have no idea what's happening, and other questions with the same error didn't help.
Here's the code:
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef enum { false, true } bool;
char * removeSpaces(char *line) {
int counter = 0,i=0;
while (line[i]!='\0'){
if (line[i] == ' '){
i++;
} else{
line[counter] = line[i];
counter++;
i++;
}
}
return(line);
line[counter] = '\0';
}
int main (int argc, char *argv[]){
FILE * fp;
char * line = NULL;
char field[30];
size_t len = 0;
ssize_t read;
bool flag = false;
int i=0,j=0,k=0,counter=0; //variables to count on loops
fp = fopen("input.txt", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
printf("%s", line);
if(strstr(line, "Worker") != NULL) { //determine the entrance type
line = removeSpaces(line);
printf("\nWORKER READ\n");
i = 0;
while(line[i] != ';'){ //Read ID
field[i] = line[i]; //saves the content of the field (all between ';')
i++;
}
field[i] = '\0';
printf("\nID: ");
for(i=0;field[i] != '\0';i++){
printf("%c",field[i]);
}
//memset(field,0,strlen(field));
i = 0; j = 0;
while(flag != true){ //Read Companions
if(line[i] == ';'){
flag = true; //keeps skipping the string till it finds the right field
}
if(flag == true){
j = i+1;
while(line[j] != ';'){
field[k] = line[j]; //saves the content of the field (all between ';')
j++; k++;
}
}
i++;
}
field[k] = '\0';
printf("\nCOMPANIONS: ");
for(i=0;field[i] != '\0';i++){
printf("%c",field[i]); //prints what the number of companions read
}
//memset(field,0,strlen(field));
i = 0; j = 0; k = 0; flag = false;
while(flag != true){ //Read Type
if(line[i] == ';'){
counter++;
if(counter == 2){
flag = true; //keeps skipping the string till it finds the right field
}
}
if(flag == true){
j = i+1;
while(line[j] != ';'){
field[k] = line[j]; //saves the content of the field (all between ';')
j++; k++;
}
}
i++;
}
field[k] = '\0';
printf("\nTIPO: ");
for(i=0;field[i] != '\0';i++){
printf("%c",field[i]); /prints the type of entrance read
}
//memset(field,0,strlen(field));
i = 0; j = 0; k = 0; flag = false; counter = 0;
while(flag != true){ //Read Entrance Time
if(line[i] == ';'){
counter++;
if(counter == 3){
flag = true; //keeps skipping the string till it finds the right field
}
}
if(flag == true){
j = i+1;
while(line[j] != ';'){
field[k] = line[j]; //saves it
j++; k++;
}
}
i++;
}
field[k] = '\0';
printf("\nENTRANCE: ");
for(i=0;field[i] != '\0';i++){
printf("%c",field[i]);
}
i = 0; j = 0; k = 0; flag = false; counter = 0;
while(flag != true){ //Read Exit Time
if(line[i] == ';'){
counter++;
if(counter == 4){
flag = true;
}
}
if(flag == true){
j = i+1;
while(line[j] != ';'){
field[k] = line[j];
j++; k++;
}
}
i++;
}
field[k] = '\0';
printf("\nSAIDA: ");
for(i=0;field[i] != '\0';i++){
printf("%c",field[i]);
}
printf("\n\n");
i = 0; j = 0; k = 0; flag = false;
memset(field,0,strlen(field));
} else if(strstr(line, "Director") != NULL){
//TODO
} else if(strstr(line, "Visitor") != NULL){
//TODO
}
}
return 0;
}
While I recommend sscanf or fscanf over writing complicated parsing code, it's also good for your coding skills to learn how to write parsers. After adjusting your code to use fgets instead of getline so that I could get it to compile, I hit a fault in this loop:
while ( flag != true )
{ //Read Type
if ( line[i] == ';' ) // <<<< Fault when i = 2488
{
counter++;
if ( counter == 2 )
{
flag = true; //keeps skipping the string till it finds the right field
}
}
if ( flag == true )
{
j = i + 1;
while ( line[j] != ';' )
{
field[k] = line[j]; //saves the content of the field (all between ';')
j++; k++;
}
}
i++;
}
You're incrementing i without reference to the length of the actual line, so at some point you are accessing a memory address that you do not own.
You should enable all warnings when you compile your code. Your compiler should be warning you of some of your mistakes. One of the important ones you should be seeing is "Unreachable code..." at line 27 in your removeSpaces function:
return(line);
line[counter] = '\0'; // This never executed.
See http://pubs.opengroup.org/onlinepubs/009696699/functions/fgets.html
sscanf could be used to parse the values from line.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char *argv[]){
FILE * fp;
char * line = NULL;
char id[30];
char companions[30];
char type[30];
char entrance[30];
char depart[30];
size_t len = 0;
ssize_t read;
fp = fopen("input.txt", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
printf("%s", line);
if(strstr(line, "Worker") != NULL) { //determine the entrance type
printf("\nWORKER READ\n");
if ( 5 == sscanf ( line, "%29s ; %29s ; %29s ; %29s ; %29s"
, id, companions, type, entrance, depart)) {
printf("\nID: %s", id);
printf("\nCOMPANIONS: %s", companions);
printf("\nTIPO: %s", type);
printf("\nENTRANCE: %s", entrance);
printf("\nSAIDA: %s", depart);
printf("\n\n");
}
else {
printf ( "problem parsing Worker\n");
}
} else if(strstr(line, "Director") != NULL){
//TODO
} else if(strstr(line, "Visitor") != NULL){
//TODO
}
}
return 0;
}

Resources